diff --git a/.changeset/clean-boxes-marry.md b/.changeset/clean-boxes-marry.md new file mode 100644 index 000000000..36b1332c0 --- /dev/null +++ b/.changeset/clean-boxes-marry.md @@ -0,0 +1,5 @@ +--- +"@cube-creator/shared-dimensions-api": minor +--- + +Improve loading speed of Shared Dimensions in UI (closes #1509) diff --git a/.changeset/thick-clocks-ring.md b/.changeset/thick-clocks-ring.md new file mode 100644 index 000000000..ae1729b21 --- /dev/null +++ b/.changeset/thick-clocks-ring.md @@ -0,0 +1,5 @@ +--- +"@cube-creator/shared-dimensions-api": minor +--- + +Shared dimensions are now searchable and paginated in search results on dimension mapping and hierarchy screens (re #1509, closes #1481) diff --git a/api.Dockerfile b/api.Dockerfile index f4326f592..c5274dc71 100644 --- a/api.Dockerfile +++ b/api.Dockerfile @@ -3,6 +3,7 @@ FROM node:18-alpine AS builder WORKDIR /app ADD package.json yarn.lock ./ +ADD ./patches ./patches/ ADD ./apis/core/package.json ./apis/core/ ADD ./apis/errors/package.json ./apis/errors/ ADD ./apis/shared-dimensions/package.json ./apis/shared-dimensions/ diff --git a/apis/core/bootstrap/shapes/dimension.ts b/apis/core/bootstrap/shapes/dimension.ts index 50333f70d..aa35e5574 100644 --- a/apis/core/bootstrap/shapes/dimension.ts +++ b/apis/core/bootstrap/shapes/dimension.ts @@ -3,13 +3,10 @@ import { supportedLanguages } from '@cube-creator/core/languages' import { sparql, turtle } from '@tpluscode/rdf-string' import { dash, hydra, prov, rdf, rdfs, schema, sh, qudt, time, xsd } from '@tpluscode/rdf-ns-builders' import namespace from '@rdfjs/namespace' -import $rdf from 'rdf-ext' import { lindasQueryTemplate } from '../lib/query' const sou = namespace('http://qudt.org/vocab/sou/') -const sharedDimensionCollection = $rdf.namedNode('dimension/_term-sets') - const unitsQuery = sparql` CONSTRUCT { @@ -472,7 +469,14 @@ ${shape('dimension/shared-mapping-import')} { ${sh.path} ${cc.sharedDimension} ; ${sh.name} "Shared dimension" ; ${dash.editor} ${dash.AutoCompleteEditor} ; - ${hydra.collection} ${sharedDimensionCollection} ; + ${hydra.search} [ + ${hydra.template} "dimension/_term-sets?{&q}" ; + ${hydra.mapping} [ + ${hydra.variable} "q" ; + ${hydra.property} ${hydra.freetextQuery} ; + ${sh.minLength} 0 ; + ]; + ] ; ${sh1.orderBy} ( ${schema.name} ) ; ${sh.nodeKind} ${sh.IRI} ; ${sh.order} 10 ; @@ -520,7 +524,14 @@ ${shape('dimension/shared-mapping')} { ${sh.path} ${cc.sharedDimension} ; ${sh.name} "Shared dimensions" ; ${dash.editor} ${dash.AutoCompleteEditor} ; - ${hydra.collection} ${sharedDimensionCollection} ; + ${hydra.search} [ + ${hydra.template} "dimension/_term-sets?{&q}" ; + ${hydra.mapping} [ + ${hydra.variable} "q" ; + ${hydra.property} ${hydra.freetextQuery} ; + ${sh.minLength} 0 ; + ]; + ] ; ${sh1.orderBy} ( ${schema.name} ) ; ${sh.nodeKind} ${sh.IRI} ; ${sh.order} 10 ; diff --git a/apis/shared-dimensions/bootstrap/entrypoint.ts b/apis/shared-dimensions/bootstrap/entrypoint.ts index dcc59d3cc..17574ebfa 100644 --- a/apis/shared-dimensions/bootstrap/entrypoint.ts +++ b/apis/shared-dimensions/bootstrap/entrypoint.ts @@ -5,5 +5,5 @@ import type { BootstrappedResourceFactory } from './index' export const entrypoint = (ptr: BootstrappedResourceFactory, ns: NamespaceBuilder) => ptr('').addOut(rdf.type, [hydra.Resource, md.Entrypoint]) - .addOut(md.sharedDimensions, ns('_term-sets')) + .addOut(md.sharedDimensions, ns('_term-sets?pageSize=1000')) .addOut(md.hierarchies, ns('_hierarchies')) diff --git a/apis/shared-dimensions/hydra/index.ttl b/apis/shared-dimensions/hydra/index.ttl index db5fb0dad..aa45cd689 100644 --- a/apis/shared-dimensions/hydra/index.ttl +++ b/apis/shared-dimensions/hydra/index.ttl @@ -48,6 +48,27 @@ md:SharedDimensions a code:EcmaScript ; code:link ; ] ; + hydra-box:variables + [ + a hydra:IriTemplate ; + hydra:template "/_term-sets{?q,pageSize,page}" ; + hydra:mapping + [ + a hydra:IriTemplateMapping ; + hydra:property hydra:freetextQuery ; + hydra:variable "q" ; + ], + [ + a hydra:IriTemplateMapping ; + hydra:property hydra:limit ; + hydra:variable "pageSize" ; + ], + [ + a hydra:IriTemplateMapping ; + hydra:property hydra:pageIndex ; + hydra:variable "page" ; + ] ; + ] ; ], [ a hydra:Operation, schema:CreateAction ; hydra:method "POST" ; diff --git a/apis/shared-dimensions/lib/domain/shared-dimensions.ts b/apis/shared-dimensions/lib/domain/shared-dimensions.ts index e95775f3f..8eb46381e 100644 --- a/apis/shared-dimensions/lib/domain/shared-dimensions.ts +++ b/apis/shared-dimensions/lib/domain/shared-dimensions.ts @@ -1,8 +1,6 @@ import path from 'path' import type { Quad, Stream, Term } from '@rdfjs/types' -import { CONSTRUCT } from '@tpluscode/sparql-builder' import { hydra, rdf, schema, sh } from '@tpluscode/rdf-ns-builders' -import { md, meta } from '@cube-creator/core/namespace' import $rdf from 'rdf-ext' import { toRdf } from 'rdf-literal' import { fromFile } from 'rdf-utils-fs' @@ -11,28 +9,31 @@ import { isGraphPointer } from 'is-graph-pointer' import { StreamClient } from 'sparql-http-client/StreamClient' import { ParsingClient } from 'sparql-http-client/ParsingClient' import env from '../env' -import shapeToQuery from '../shapeToQuery' +import shapeToQuery, { rewriteTemplates } from '../shapeToQuery' import { getDynamicProperties } from './shared-dimension' -export function getSharedDimensions() { - return CONSTRUCT` - ?termSet ?p ?o . - ?termSet ${md.terms} ?terms . - ?termSet ${md.export} ?export . - ` - .WHERE` - ?termSet a ${schema.DefinedTermSet}, ${meta.SharedDimension} . - ?termSet ?p ?o . - - MINUS { ?termSet ${md.export} ?o } - - BIND ( IRI(CONCAT("${env.MANAGED_DIMENSIONS_BASE}", "dimension/_terms?dimension=", ENCODE_FOR_URI(STR(?termSet)))) as ?terms ) - - OPTIONAL { - ?termSet a ${md.SharedDimension} . - BIND ( IRI(CONCAT("${env.MANAGED_DIMENSIONS_BASE}", "dimension/_export?dimension=", ENCODE_FOR_URI(STR(?termSet)))) as ?export ) - } - ` +interface GetSharedDimensions { + freetextQuery?: string + limit?: number + offset?: number +} + +export async function getSharedDimensions(client: C, { freetextQuery = '', limit = 10, offset = 0 }: GetSharedDimensions = {}): Promise { + const { constructQuery } = await shapeToQuery() + + const shape = await loadShape('dimensions-query-shape') + + const { MANAGED_DIMENSIONS_BASE } = env + const variables = new Map(Object.entries({ + MANAGED_DIMENSIONS_BASE, + limit, + offset, + freetextQuery, + orderBy: schema.name, + })) + await rewriteTemplates(shape, variables) + + return constructQuery(shape).execute(client) as any } interface GetSharedTerms { @@ -44,10 +45,7 @@ interface GetSharedTerms { } export async function getSharedTerms({ sharedDimensions, freetextQuery, validThrough, limit = 10, offset = 0 }: GetSharedTerms, client: C): Promise { - const shape = await loadShape() - if (!isGraphPointer(shape)) { - throw new Error('Multiple shapes found') - } + const shape = await loadShape('terms-query-shape') shape.addOut(sh.targetNode, sharedDimensions) @@ -79,13 +77,19 @@ export async function getSharedTerms({ s } const { constructQuery } = await shapeToQuery() - return constructQuery(shape).execute(client.query) as any + return constructQuery(shape).execute(client) as any } -async function loadShape() { - const dataset = await $rdf.dataset().import(fromFile(path.resolve(__dirname, '../shapes/terms-query-shape.ttl'))) +async function loadShape(shape: string) { + const dataset = await $rdf.dataset().import(fromFile(path.resolve(__dirname, `../shapes/${shape}.ttl`))) - return clownface({ + const ptr = clownface({ dataset, }).has(rdf.type, sh.NodeShape) + + if (!isGraphPointer(ptr)) { + throw new Error('Multiple shapes found') + } + + return ptr } diff --git a/apis/shared-dimensions/lib/handlers/collection.ts b/apis/shared-dimensions/lib/handlers/collection.ts index d3f89c6be..f729e2941 100644 --- a/apis/shared-dimensions/lib/handlers/collection.ts +++ b/apis/shared-dimensions/lib/handlers/collection.ts @@ -1,23 +1,32 @@ import type { NamedNode, Quad } from '@rdfjs/types' import $rdf from 'rdf-ext' -import clownface from 'clownface' +import clownface, { GraphPointer } from 'clownface' import { hydra, rdf } from '@tpluscode/rdf-ns-builders' interface CollectionHandler { memberType: NamedNode collectionType: NamedNode + view?: NamedNode memberQuads: Quad[] collection: NamedNode } -export function getCollection({ collection, memberQuads, memberType, collectionType }: CollectionHandler) { +export function getCollection({ collection, view, memberQuads, memberType, collectionType }: CollectionHandler): GraphPointer { const dataset = $rdf.dataset(memberQuads) const graph = clownface({ dataset }) const members = graph.has(rdf.type, memberType) - return graph.node(collection) + graph.node(collection) .addOut(rdf.type, [hydra.Collection, collectionType]) .addOut(hydra.member, members) .addOut(hydra.totalItems, members.terms.length) + + if (view) { + graph.node(view) + .addOut(rdf.type, hydra.PartialCollectionView) + .addIn(hydra.view, collection) + } + + return graph.node(collection) } diff --git a/apis/shared-dimensions/lib/handlers/shared-dimensions.ts b/apis/shared-dimensions/lib/handlers/shared-dimensions.ts index 71b29ade7..3a1b814a7 100644 --- a/apis/shared-dimensions/lib/handlers/shared-dimensions.ts +++ b/apis/shared-dimensions/lib/handlers/shared-dimensions.ts @@ -19,9 +19,24 @@ import { rewrite, rewriteTerm } from '../rewrite' import { postImportedDimension } from './shared-dimension/import' import { getCollection } from './collection' -export const get = asyncMiddleware(async (req, res) => { - const collection = await getCollection({ - memberQuads: await getSharedDimensions().execute(parsingClient.query), +export const get = asyncMiddleware(async (req, res, next) => { + if (!req.dataset) { + return next(new httpError.BadRequest()) + } + const query = clownface({ dataset: await req.dataset() }) + const pageSize = Number(query.out(hydra.limit).value || 10) + const page = Number(query.out(hydra.pageIndex).value || 1) + const offset = (page - 1) * pageSize + const queryParams = { + freetextQuery: query.has(hydra.freetextQuery).out(hydra.freetextQuery).value, + validThrough: query.has(md.onlyValidTerms, query.literal(true)).terms.length ? new Date() : undefined, + limit: pageSize, + offset, + } + + const collection = getCollection({ + view: $rdf.namedNode(req.absoluteUrl()), + memberQuads: await getSharedDimensions(parsingClient, queryParams), collectionType: md.SharedDimensions, memberType: schema.DefinedTermSet, collection: req.hydra.resource.term, @@ -73,7 +88,7 @@ export const getTerms = asyncMiddleware(async (req, res, next) => { offset, } - const collection = await getCollection({ + const collection = getCollection({ memberQuads: await getSharedTerms(queryParams, parsingClient), memberType: schema.DefinedTerm, collectionType: md.SharedDimensionTerms, diff --git a/apis/shared-dimensions/lib/shapeToQuery.ts b/apis/shared-dimensions/lib/shapeToQuery.ts index bf777c003..9a8bc7dc1 100644 --- a/apis/shared-dimensions/lib/shapeToQuery.ts +++ b/apis/shared-dimensions/lib/shapeToQuery.ts @@ -1,11 +1,14 @@ import onetime from 'onetime' import { md } from '@cube-creator/core/namespace' -import { GraphPointer } from 'clownface' +import { AnyPointer, GraphPointer } from 'clownface' import { isGraphPointer } from 'is-graph-pointer' import { hydra } from '@tpluscode/rdf-ns-builders' import { Parameters, PropertyShape } from '@hydrofoil/shape-to-query/model/constraint/ConstraintComponent' +import evalTemplateLiteral from 'rdf-loader-code/evalTemplateLiteral.js' import namespace from '@rdfjs/namespace' import { sparql } from '@tpluscode/sparql-builder' +import $rdf from 'rdf-ext' +import type { Literal } from '@rdfjs/types' import env from './env' /* @@ -15,23 +18,63 @@ import env from './env' // eslint-disable-next-line no-new-func const _importDynamic = new Function('modulePath', 'return import(modulePath)') -export default async function shapeToQuery() { +export default async function shapeToQuery(): Promise> { await setup() - const { constructQuery, deleteQuery } = await _importDynamic('@hydrofoil/shape-to-query') + const { constructQuery, deleteQuery, s2q } = await _importDynamic('@hydrofoil/shape-to-query') return { constructQuery, deleteQuery, + s2q, } } +export async function rewriteTemplates(shape: AnyPointer, variables: Map) { + const { s2q } = await shapeToQuery() + + shape.any().has(s2q('template' as any)) + .forEach(templateNode => { + const template = templateNode.out(s2q('template' as any)) + if (!isGraphPointer(template)) { + throw new Error('Template not found') + } + + const value = evalTemplateLiteral(template.value, { variables }) + const literalOption = (template.term as Literal).language || (template.term as Literal).datatype + + ;[...shape.dataset.match(null, null, templateNode.term)].forEach(quad => { + shape.dataset.delete(quad) + shape.dataset.add($rdf.quad(quad.subject, quad.predicate, $rdf.literal(value, literalOption), quad.graph)) + }) + + templateNode.deleteOut() + }) + + shape.any().has(s2q('variable' as any)) + .forEach(templateNode => { + const variableName = templateNode.out(s2q('variable' as any)).value + if (!variableName) { + return + } + + const value = variables.get(variableName) as any + + ;[...shape.dataset.match(null, null, templateNode.term)].forEach(quad => { + shape.dataset.delete(quad) + shape.dataset.add($rdf.quad(quad.subject, quad.predicate, value, quad.graph)) + }) + + templateNode.deleteOut() + }) +} + const setup = onetime(async () => { await defineConstraintComponents() }) async function defineConstraintComponents() { - const { ConstraintComponent } = await _importDynamic('@hydrofoil/shape-to-query/model/constraint/ConstraintComponent.js') + const { default: ConstraintComponent } = await _importDynamic('@hydrofoil/shape-to-query/model/constraint/ConstraintComponent.js') const { constraintComponents } = await _importDynamic('@hydrofoil/shape-to-query/model/constraint/index.js') const { PatternConstraintComponent } = await _importDynamic('@hydrofoil/shape-to-query/model/constraint/pattern.js') diff --git a/apis/shared-dimensions/lib/shapes/dimensions-query-shape.ttl b/apis/shared-dimensions/lib/shapes/dimensions-query-shape.ttl new file mode 100644 index 000000000..9e2fced3f --- /dev/null +++ b/apis/shared-dimensions/lib/shapes/dimensions-query-shape.ttl @@ -0,0 +1,101 @@ +PREFIX xsd: +@prefix sh: . +@prefix rdf: . +prefix meta: +PREFIX s2q: +prefix schema: +PREFIX sparql: +prefix md: + +[ + a sh:NodeShape ; + sh:target + [ + a s2q:NodeExpressionTarget ; + sh:expression + [ + sh:distinct + [ + sh:limit [ s2q:template "${limit}"^^xsd:integer ] ; + sh:nodes + [ + sh:offset [ s2q:template "${offset}"^^xsd:integer ] ; + sh:nodes + [ + sh:orderBy [ sh:path [ s2q:variable "orderBy" ] ] ; + sh:nodes + [ + sh:filterShape + [ + sh:property + [ + sh:path schema:name ; + sh:pattern + [ + s2q:template "^${freetextQuery}" ; + ] ; + sh:flags "i" ; + ] ; + sh:property + [ + sh:path rdf:type ; + sh:hasValue schema:DefinedTermSet, meta:SharedDimension ; + ] ; + ] ; + ] ; + ] ; + ] ; + ] ; + ] ; + ] ; + sh:property + [ + sh:path schema:name ; + ] ; + sh:property + [ + sh:path schema:alternateName ; + ] ; + sh:property + [ + sh:path rdf:type ; + ] ; + sh:property + [ + sh:path schema:validThrough ; + ] ; + sh:property + [ + sh:path md:terms ; + sh:values + [ + sparql:iri + ( + [ + sparql:concat + ( + [ s2q:template "${MANAGED_DIMENSIONS_BASE}dimension/_terms?dimension=" ; ] + [ sparql:encode_for_uri ( [ sparql:str ( sh:this ) ] ) ] + ) + ] + ) + ] + ] ; + sh:property + [ + sh:path md:export ; + sh:values + [ + sparql:iri + ( + [ + sparql:concat + ( + [ s2q:template "${MANAGED_DIMENSIONS_BASE}dimension/_terms?dimension=" ; ] + [ sparql:encode_for_uri ( [ sparql:str ( sh:this ) ] ) ] + ) + ] + ) + ] + ] ; +] . diff --git a/apis/shared-dimensions/lib/shapes/hierarchy.ts b/apis/shared-dimensions/lib/shapes/hierarchy.ts index 4630b18ab..c4cf0edbd 100644 --- a/apis/shared-dimensions/lib/shapes/hierarchy.ts +++ b/apis/shared-dimensions/lib/shapes/hierarchy.ts @@ -9,7 +9,7 @@ import env from '@cube-creator/core/env' export default function ({ rdfTypeProperty = false }: { rdfTypeProperty?: boolean } = {}) { return (graph: AnyPointer): Initializer => { - const sharedDimensionCollection = graph.namedNode('/dimension/_term-sets') + // const sharedDimensionCollection = graph.namedNode('/dimension/_term-sets') const publicQueryEndpoint = graph.blankNode() .addOut(sd.endpoint, graph.namedNode(env.PUBLIC_QUERY_ENDPOINT)) .addOut(foaf.page, env.TRIFID_UI) @@ -79,7 +79,14 @@ export default function ({ rdfTypeProperty = false }: { rdfTypeProperty?: boolea maxCount: 1, nodeKind: sh.IRI, [dash.editor.value]: dash.InstancesSelectEditor, - [hydra.collection.value]: sharedDimensionCollection, + [hydra.search.value]: iriTemplate({ + template: 'dimension/_term-sets{?q}', + mapping: { + variable: 'q', + property: hydra.freetextQuery, + [sh.minLength.value]: 0, + }, + }), order: 5, }, { name: 'Root', diff --git a/apis/shared-dimensions/lib/shapes/shared-dimension.ts b/apis/shared-dimensions/lib/shapes/shared-dimension.ts index 800410ad1..b8fc2bd7f 100644 --- a/apis/shared-dimensions/lib/shapes/shared-dimension.ts +++ b/apis/shared-dimensions/lib/shapes/shared-dimension.ts @@ -2,6 +2,7 @@ import { dash, dcterms, hydra, qudt, rdf, rdfs, schema, sh, time, xsd } from '@t import { supportedLanguages } from '@cube-creator/core/languages' import { datatypes } from '@cube-creator/core/datatypes' import type { Initializer } from '@tpluscode/rdfine/RdfResource' +import { fromPointer as iriTemplate } from '@rdfine/hydra/lib/IriTemplate' import type { NodeShape, PropertyShape } from '@rdfine/shacl' import $rdf from 'rdf-ext' import { editor, iso6391, md, meta, sh1 } from '@cube-creator/core/namespace' @@ -257,7 +258,14 @@ const properties: Initializer[] = [{ name: 'Shared dimension', path: sh.class, [dash.editor.value]: dash.AutoCompleteEditor, - [hydra.collection.value]: $rdf.namedNode('/dimension/_term-sets'), + [hydra.search.value]: iriTemplate({ + template: '/dimension/_term-sets{?q}', + mapping: { + variable: 'q', + property: hydra.freetextQuery, + [sh.minLength.value]: 0, + }, + }), nodeKind: sh.IRI, minCount: 1, maxCount: 1, diff --git a/apis/shared-dimensions/lib/store/index.ts b/apis/shared-dimensions/lib/store/index.ts index c0002ab9d..c1b334846 100644 --- a/apis/shared-dimensions/lib/store/index.ts +++ b/apis/shared-dimensions/lib/store/index.ts @@ -32,7 +32,7 @@ export default class implements SharedDimensionsStore { focusNode: term, }).FROM(this.graph) - const quads = await query.execute(this.client.query, { + const quads = await query.execute(this.client, { operation: 'postDirect', }) return clownface({ @@ -59,7 +59,7 @@ export default class implements SharedDimensionsStore { async delete(id: NamedNode): Promise { const shape = await this.getShape(id) - await (await this.deleteQuery(shape, id)).execute(this.client.query) + await (await this.deleteQuery(shape, id)).execute(this.client) } private async deleteQuery(shape: GraphPointer, focusNode: NamedNode) { diff --git a/apis/shared-dimensions/package.json b/apis/shared-dimensions/package.json index c4f254282..1304461f8 100644 --- a/apis/shared-dimensions/package.json +++ b/apis/shared-dimensions/package.json @@ -7,7 +7,7 @@ "@cube-creator/core": "1.0.0", "@cube-creator/express": "0.0.0", "@hydrofoil/labyrinth": "^0.4.2", - "@hydrofoil/shape-to-query": "^0.8.1", + "@hydrofoil/shape-to-query": "^0.12", "@rdfine/hydra": "^0.8.2", "@rdfine/rdfs": "^0.6.4", "@rdfine/schema": "^0.6.3", @@ -39,6 +39,7 @@ "rdf-dataset-ext": "^1.0.1", "rdf-ext": "^1.3.0", "rdf-literal": "^1.2.0", + "rdf-loader-code": "^0.3.3", "rdf-utils-fs": "^2", "rdf-validate-shacl": "^0.4.3", "slugify": "^1.6.5", @@ -51,6 +52,7 @@ "@types/clownface": "^1.2.6", "@types/parse-prefer-header": "^1.0.0", "@types/rdf-dataset-ext": "^1", + "@types/rdf-loader-code": "^0.3", "@types/rdf-utils-fs": "^2", "@types/sinon": "^10.0.0", "chai": "^4.2.0", diff --git a/apis/shared-dimensions/test/lib/domain/managed-dimensions.test.ts b/apis/shared-dimensions/test/lib/domain/managed-dimensions.test.ts index 1ffaa0113..f1018caaa 100644 --- a/apis/shared-dimensions/test/lib/domain/managed-dimensions.test.ts +++ b/apis/shared-dimensions/test/lib/domain/managed-dimensions.test.ts @@ -15,7 +15,7 @@ describe('@cube-creator/shared-dimensions-api/lib/domain/shared-dimensions @SPAR it('returns from all graphs', async () => { // when const dataset = await $rdf.dataset() - .import(await getSharedDimensions().execute(mdClients.streamClient.query)) + .import(await getSharedDimensions(mdClients.streamClient)) // then const termSets = [...dataset.match(null, rdf.type, schema.DefinedTermSet)].map(({ subject }) => subject) @@ -25,6 +25,21 @@ describe('@cube-creator/shared-dimensions-api/lib/domain/shared-dimensions @SPAR $rdf.namedNode('http://example.com/dimension/chemicals'), ]) }) + + it('returns filtered by name', async () => { + // when + const dataset = await $rdf.dataset() + .import(await getSharedDimensions(mdClients.streamClient, { + freetextQuery: 'colors', + })) + + // then + const termSets = [...dataset.match(null, rdf.type, schema.DefinedTermSet)].map(({ subject }) => subject) + expect(termSets).to.have.length(1) + expect(termSets).to.deep.contain.members([ + $rdf.namedNode('http://example.com/dimension/colors'), + ]) + }) }) describe('getSharedTerms', () => { diff --git a/patches/@hydrofoil+shaperone-wc-shoelace+0.3.2.patch b/patches/@hydrofoil+shaperone-wc-shoelace+0.3.2.patch deleted file mode 100644 index d4f54aff5..000000000 --- a/patches/@hydrofoil+shaperone-wc-shoelace+0.3.2.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/node_modules/@hydrofoil/shaperone-wc-shoelace/elements/sh-sl-autocomplete.js b/node_modules/@hydrofoil/shaperone-wc-shoelace/elements/sh-sl-autocomplete.js -index ef0875a..f44ede5 100644 ---- a/node_modules/@hydrofoil/shaperone-wc-shoelace/elements/sh-sl-autocomplete.js -+++ b/node_modules/@hydrofoil/shaperone-wc-shoelace/elements/sh-sl-autocomplete.js -@@ -33,6 +33,7 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } - import { css, html, LitElement } from 'lit'; - import { customElement, property, query } from 'lit/decorators.js'; - import debounce from 'p-debounce'; -+import { rdfs, schema } from '@tpluscode/rdf-ns-builders' - import { stop } from '../lib/handlers.js'; - import '@shoelace-style/shoelace/dist/components/input/input.js'; - import '@shoelace-style/shoelace/dist/components/icon/icon.js'; -@@ -232,6 +233,11 @@ export let ShSlAutocomplete = _decorate([customElement('sh-sl-autocomplete')], f - this._menu.show(); - } - } -+ if (_changedProperties.has('selected')) { -+ this.inputValue = this.selected?.out(schema.name).value -+ || this.selected?.out(rdfs.label).value -+ || '' -+ } - } - }, { - kind: "method", diff --git a/patches/@types+rdf-loader-code+0.3.7.patch b/patches/@types+rdf-loader-code+0.3.7.patch new file mode 100644 index 000000000..aa65db34f --- /dev/null +++ b/patches/@types+rdf-loader-code+0.3.7.patch @@ -0,0 +1,12 @@ +diff --git a/node_modules/@types/rdf-loader-code/evalTemplateLiteral.d.ts b/node_modules/@types/rdf-loader-code/evalTemplateLiteral.d.ts +new file mode 100644 +index 0000000..a34997c +--- /dev/null ++++ b/node_modules/@types/rdf-loader-code/evalTemplateLiteral.d.ts +@@ -0,0 +1,6 @@ ++function evalTemplateLiteral(content: string, options?: { ++ context?: Record ++ variables?: Map ++}): string ++ ++export = evalTemplateLiteral diff --git a/yarn.lock b/yarn.lock index 4eab53d8a..b4a5714e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1538,23 +1538,22 @@ rdf-loaders-registry "^0.2.0" sparql-http-client "^2.2.2" -"@hydrofoil/shape-to-query@^0.8.1": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@hydrofoil/shape-to-query/-/shape-to-query-0.8.1.tgz#530ecbe5cfe4a12fcb8f241dc7b8b9e5af29ecdd" - integrity sha512-omAz3aEAVbAuCN1k0WMsHf5B5/qULTJYuF2ffJCNYYQPuLwLw0EVE4cWOkRm9lTCPYWDgN+DSmJ9aa/1Tua8Tg== +"@hydrofoil/shape-to-query@^0.12": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@hydrofoil/shape-to-query/-/shape-to-query-0.12.0.tgz#cc36a95781bc334b48c7836cf17631d9af2a100e" + integrity sha512-2ZljN+03GpRQAnMS7WOMADCkqJtTCEbOblHD0dL+6p968ZZC5eVzECmgpZnVli6/escZS/kWeWbH/7QZBiMglQ== dependencies: "@tpluscode/rdf-ns-builders" ">=3.0.2" - "@tpluscode/rdf-string" "^1.0.3" - "@tpluscode/sparql-builder" "^1.1.0" - "@vocabulary/dash" "^1.0.0" - "@vocabulary/dash-sparql" "^1.0.0" - "@vocabulary/sh" "^1.0.0" + "@tpluscode/rdf-string" "^1.3.1" + "@tpluscode/sparql-builder" "^2.0.3" + "@vocabulary/dash" "^1.0.4" + "@vocabulary/dash-sparql" "^1.0.4" + "@vocabulary/sh" "^1.1.5" + "@zazuko/env" "^2.2.0" "@zazuko/prefixes" ">=2" - clownface "^1.5.1" - clownface-shacl-path "^2.0.1" + clownface-shacl-path "^2.1.1" is-graph-pointer "^2.0.0" - rdf-ext "^2.2.0" - rdf-literal "^1.3.1" + rdf-literal "^1.3.2" "@hydrofoil/shaperone-core@^0.11", "@hydrofoil/shaperone-core@^0.11.0": version "0.11.0" @@ -2543,19 +2542,6 @@ resolved "https://registry.yarnpkg.com/@rdfjs/environment/-/environment-1.0.0.tgz#fd36305e93e2e1ec772684a497c533414b2d56ba" integrity sha512-+S5YjSvfoQR5r7YQCRCCVHvIEyrWia7FJv2gqM3s5EDfotoAQmFeBagApa9c/eQFi5EiNhmBECE5nB8LIxTaHg== -"@rdfjs/environment@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@rdfjs/environment/-/environment-0.1.2.tgz#845ad9816f768417170d1a214f16b9aea2b26322" - integrity sha512-R4N73kaoaOt3XvgLy2Cb98bJUgMJv/wRsUPGDxeogbtalkENPmo3X5to/rKQEwOjnj+jw+ILzN2webUHb8pvEw== - dependencies: - "@rdfjs/data-model" "^2.0.1" - "@rdfjs/dataset" "^2.0.1" - "@rdfjs/fetch-lite" "^3.2.1" - "@rdfjs/namespace" "^2.0.0" - "@rdfjs/sink-map" "^2.0.0" - "@rdfjs/term-map" "^2.0.0" - "@rdfjs/term-set" "^2.0.1" - "@rdfjs/express-handler@^1.2.0", "@rdfjs/express-handler@^1.2.1": version "1.2.1" resolved "https://registry.yarnpkg.com/@rdfjs/express-handler/-/express-handler-1.2.1.tgz#e0182697d87cf211fc75d10534c4c3812296d266" @@ -2580,7 +2566,7 @@ nodeify-fetch "^2.2.1" readable-stream "^3.3.0" -"@rdfjs/fetch-lite@^3.0.0", "@rdfjs/fetch-lite@^3.2.1", "@rdfjs/fetch-lite@^3.2.2": +"@rdfjs/fetch-lite@^3.0.0", "@rdfjs/fetch-lite@^3.2.2": version "3.2.2" resolved "https://registry.yarnpkg.com/@rdfjs/fetch-lite/-/fetch-lite-3.2.2.tgz#5968745715ce452912c2b2d638ed1f313582b301" integrity sha512-hcdg9gvMgaOLPGS1LAYPjyS3rjQg2x8G/do+ZTlHjIHrAtRzXZCa0ui+pzoT98258RQzxEGqajY4ug4IqSuHZw== @@ -2647,13 +2633,6 @@ dependencies: "@rdfjs/data-model" "^2.0.0" -"@rdfjs/normalize@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@rdfjs/normalize/-/normalize-2.0.0.tgz#87f6872043e3459da7baa09946f746fd3d3144f1" - integrity sha512-jOSdIKz9r/oPI9nuWXMTYzFaCbrFQj9qEOPdqs1/7oAR1JTvqpS69HVZPkVqbH+WhL52PJbBXyA5QadoyNLgpQ== - dependencies: - rdf-canonize "^3.0.0" - "@rdfjs/parser-jsonld@^1.2.1", "@rdfjs/parser-jsonld@^1.2.2": version "1.3.1" resolved "https://registry.yarnpkg.com/@rdfjs/parser-jsonld/-/parser-jsonld-1.3.1.tgz#0d6fe7e41a7350d358cc02e5c8ced7fedaa97193" @@ -2704,16 +2683,6 @@ dependencies: readable-stream "^4.3.0" -"@rdfjs/score@^0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@rdfjs/score/-/score-0.1.1.tgz#8431cbf62458eb28ddc06dcbd02ee5d814d4f492" - integrity sha512-+t9Sf5nFUJTvH8X2Xy7H+egLKIyVCwlDzCGrWThSrSCmIENcC9n3+GkMMImnsmYDeSXaWi3awcI1f1TmA84FIQ== - dependencies: - "@rdfjs/data-model" "^2.0.1" - "@rdfjs/term-map" "^2.0.0" - "@rdfjs/term-set" "^2.0.1" - "@rdfjs/to-ntriples" "^2.0.0" - "@rdfjs/serializer-jsonld-ext@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@rdfjs/serializer-jsonld-ext/-/serializer-jsonld-ext-3.0.0.tgz#96e05494638ec9affdafd63dd8e4da90e7fa01e6" @@ -2856,7 +2825,7 @@ resolved "https://registry.yarnpkg.com/@rdfjs/to-ntriples/-/to-ntriples-3.0.1.tgz#db6f8adadd7b450a1c748642e1ff468cce400599" integrity sha512-gjoPAvh4j7AbGMjcDn/8R4cW+d/FPtbfbMM0uQXkyfBFtNUW2iVgrqsgJ65roLc54Y9A2TTFaeeTGSvY9a0HCQ== -"@rdfjs/traverser@^0.1.1", "@rdfjs/traverser@^0.1.2": +"@rdfjs/traverser@^0.1.2": version "0.1.2" resolved "https://registry.yarnpkg.com/@rdfjs/traverser/-/traverser-0.1.2.tgz#19dfafbbdc37c04f1bd220319d2500af9f423551" integrity sha512-EBB/p9LrTMzupZ6VlxtBXyL0bdXFY7e5lAp2tHNwxOoe3kcR6hOJFVWdPT7pdWaSotyXbTIEQxG4PkXMw/OY7w== @@ -3167,7 +3136,7 @@ "@tpluscode/rdf-ns-builders" "^2" "@zazuko/rdf-vocabularies" ">=2023.01.17" -"@tpluscode/rdf-string@^1.0.1", "@tpluscode/rdf-string@^1.0.3": +"@tpluscode/rdf-string@^1.3.0", "@tpluscode/rdf-string@^1.3.1": version "1.3.3" resolved "https://registry.yarnpkg.com/@tpluscode/rdf-string/-/rdf-string-1.3.3.tgz#7bd989b4745240eb0fb8b140dceaf54715151b0d" integrity sha512-BiBVkX3EVRApo6DNpXuq7Mh87tPX/3aD8m1tjxe4TT6piRrmwbIT/QRrlNdAjt5cAEBRwH8cp+GFTOb/X4Y8Ww== @@ -3206,17 +3175,16 @@ "@types/sparql-http-client" "^2" debug "^4.1.1" -"@tpluscode/sparql-builder@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@tpluscode/sparql-builder/-/sparql-builder-1.1.0.tgz#8d290ee4725d849dc7fb2f5c3fdfd0f429a82ae7" - integrity sha512-xrbKKezWwvv6bXHRlkzM7hhSJqnG63DwUT2jGqtJIOWaOPAFc1wDXXd9TiuLk/oGBX6J9oV4KzaNRoZCWob9eQ== +"@tpluscode/sparql-builder@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@tpluscode/sparql-builder/-/sparql-builder-2.0.3.tgz#7a116347126551933b50dd169770d0b5659de8a5" + integrity sha512-VoV2Ifv8QSaj7uXagPkMzcUxEEhJbn3S+etz82O6fTUvrrn3ndwB/LgNfeSwc2NxPj3kBkyCb5EVeaD7YawOjw== dependencies: "@rdfjs/data-model" "^2" "@rdfjs/term-set" "^2" "@rdfjs/types" "*" - "@tpluscode/rdf-ns-builders" ">=3.0.2" - "@tpluscode/rdf-string" "^1.0.3" - "@types/sparql-http-client" "^2" + "@tpluscode/rdf-string" "^1.3.0" + "@types/sparql-http-client" "^3.0.0" anylogger "^1.0.11" "@transloadit/prettier-bytes@0.0.7": @@ -3689,6 +3657,14 @@ "@types/rdf-dataset-indexed" "*" rdf-js "^4.0.2" +"@types/rdf-loader-code@^0.3": + version "0.3.7" + resolved "https://registry.yarnpkg.com/@types/rdf-loader-code/-/rdf-loader-code-0.3.7.tgz#8b61ca18be4c64021e0c755aba8f0b177d769eba" + integrity sha512-liGxLWbFrsk4Jld0QttSIEN4f1+noxReXqjt4b3laTTm5ou+242fYdKiTfhYb5Q5dGNAANpwysRNUl6O1Wq7Pw== + dependencies: + "@types/rdf-loaders-registry" "*" + rdf-js "^4.0.2" + "@types/rdf-loaders-registry@*": version "0.3.1" resolved "https://registry.yarnpkg.com/@types/rdf-loaders-registry/-/rdf-loaders-registry-0.3.1.tgz#4c99757b3a90dc5f3b6a1177545b5a0e1184702c" @@ -3917,6 +3893,14 @@ dependencies: rdf-js "^4.0.2" +"@types/sparql-http-client@^3.0.0": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/sparql-http-client/-/sparql-http-client-3.0.2.tgz#8f89fccdb6af40e72160ed865ef2d0913149024e" + integrity sha512-sGQ7y+W/fhSM78vBjCuwaZPiM/UAfl5ZRmc6NoxddkqBmb5JEfUmTqts7lESzuG9XxDmLfiIXsrZjeSyDlPMlg== + dependencies: + "@rdfjs/types" ">=1.0.0" + "@types/rdfjs__environment" "*" + "@types/sparqljs@^3.1.3": version "3.1.3" resolved "https://registry.yarnpkg.com/@types/sparqljs/-/sparqljs-3.1.3.tgz#e4b9a2511bc2f14f564559ed6cf567835791a7e9" @@ -4242,17 +4226,17 @@ resolved "https://registry.yarnpkg.com/@vanillawc/wc-codemirror/-/wc-codemirror-1.9.8.tgz#356727aa56ecf0672f3d6c57a768594df7a39232" integrity sha512-tdhzg+5MsTEml0at43IAYrwfwLY5l5r56I5l9WlDOheNjMZgAD5yoYYkK3RQY1Pi6JqLpVIxBi9LEqVQggHBPQ== -"@vocabulary/dash-sparql@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@vocabulary/dash-sparql/-/dash-sparql-1.0.1.tgz#e3c1bee2b5c0ee6074b9adfa98dcfe49d74f0d57" - integrity sha512-k917kcXK8G3tltofD62tgHx035Zsj3SPxMDCMvty0SY6snj0w9ZOBOe8Y0vuicqrDQc3cjk+swwetJ27C67Zsg== +"@vocabulary/dash-sparql@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@vocabulary/dash-sparql/-/dash-sparql-1.0.4.tgz#eb1744d356a8202939d635eee75a4fdc2fe2f6dc" + integrity sha512-NjSJzffH3EPN5g0oB8E4ujmpsWPHbQTQAJk3rroQsxopTjoGsTXsRuukKBfaZCqZ/plpEeebAgUo+nHf+T3J9w== -"@vocabulary/dash@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@vocabulary/dash/-/dash-1.0.1.tgz#79b3974c6501d536bb0df461e182f8f8d1670aa8" - integrity sha512-EWbB1XAAiJaMiy1Y1bAaYh8x5twuaezHXuHQzX66IBcYOFiieaxYDy3d0BMNiI8p2luz/HciCCwPzxidxOCA0g== +"@vocabulary/dash@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@vocabulary/dash/-/dash-1.0.4.tgz#f3398007b3240018d0d1f11e9f70df8dd5f0800e" + integrity sha512-4z0++iVAmN4bmLdO/7iHS5MW0g9NLxUVXsKtdPWgJYO+m27s7wbso2jCUB12MWWqpGBklH7Z1vXEXyJv61vZFg== -"@vocabulary/sh@^1.0.0", "@vocabulary/sh@^1.0.1": +"@vocabulary/sh@^1.0.1", "@vocabulary/sh@^1.1.5": version "1.1.5" resolved "https://registry.yarnpkg.com/@vocabulary/sh/-/sh-1.1.5.tgz#fc133a865968b536bcdbc843edccfda72e919da2" integrity sha512-8R4uxHLpwmp6l6szZdCtfQx0wRy64OHuOsYTDfhCsbJ773Uv6nCM2bYBtjjirZHN+2m3uHQWgtWOdvuu1jwmOA== @@ -4848,7 +4832,7 @@ "@zazuko/env" "^2.1.1" "@zazuko/rdf-utils-fs" "^3.3.0" -"@zazuko/env@^2.1.1": +"@zazuko/env@^2.1.1", "@zazuko/env@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@zazuko/env/-/env-2.2.0.tgz#090ca10466113428483bfffeedf981b0b411d8e5" integrity sha512-73KwqrckawQTmoPAizlkHIRpsqFOaR31LA4XEZUnLM6CbGF/DhmbclfhMtg8GBAiZLIVdgXj6GZAW0lUmA4knQ== @@ -6216,14 +6200,14 @@ clownface-shacl-path@^1.0.1, clownface-shacl-path@^1.3.2: "@tpluscode/rdf-ns-builders" "^2.0.0" "@tpluscode/rdf-string" "^0.2.26" -clownface-shacl-path@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/clownface-shacl-path/-/clownface-shacl-path-2.0.1.tgz#84b7cee23c14ee0554c7cb023307395141eea1db" - integrity sha512-Srl+LfQE7ZXVW44iY5KPuY3TR4r1rq3nZ3/QmQ1u5MB3ONouCHeYJSKTk1x93QWaZH1UpZ6bLSI1/ehsYXMQ2A== +clownface-shacl-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clownface-shacl-path/-/clownface-shacl-path-2.1.1.tgz#ff655221c9e660726d82552ce26fddc03d6517f2" + integrity sha512-UqMETJtsjlHzp0aTBOja3I9NE6mR3E4s19FcTvYo2xJ80mxLNV+zJ5XhhdR1+lxttRfe2SNdPa9hUj1NsjOcOw== dependencies: "@rdfjs/term-set" "^2.0.1" "@tpluscode/rdf-ns-builders" ">=3.0.2" - "@tpluscode/rdf-string" "^1.0.1" + "@tpluscode/rdf-string" "^1.3.1" clownface@^1, clownface@^1.0.0, clownface@^1.1.0, clownface@^1.2.0, clownface@^1.3.0, clownface@^1.4.0, clownface@^1.5.1: version "1.5.1" @@ -12490,26 +12474,6 @@ rdf-ext@^1.3.0, rdf-ext@^1.3.1, rdf-ext@^1.3.5: rdf-normalize "^1.0.0" readable-stream "^3.6.0" -rdf-ext@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/rdf-ext/-/rdf-ext-2.2.0.tgz#32ff50ef4220e88336f3ed1a3656a38e807bd57a" - integrity sha512-/6Z1VK+OdL4SQnxhzdN1CJJY7pmtTzh0BHLRgKQG9MPIN2SnYr/eymHxqcygcZ/YHqXAV7kl2aOFbn6u9P4Wgw== - dependencies: - "@rdfjs/data-model" "^2.0.1" - "@rdfjs/dataset" "^2.0.1" - "@rdfjs/environment" "^0.1.2" - "@rdfjs/fetch-lite" "^3.2.1" - "@rdfjs/namespace" "^2.0.0" - "@rdfjs/normalize" "^2.0.0" - "@rdfjs/prefix-map" "^0.1.1" - "@rdfjs/score" "^0.1.1" - "@rdfjs/term-map" "^2.0.0" - "@rdfjs/term-set" "^2.0.1" - "@rdfjs/to-ntriples" "^2.0.0" - "@rdfjs/traverser" "^0.1.1" - clownface "^1.5.1" - readable-stream "^4.3.0" - rdf-js@*, rdf-js@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/rdf-js/-/rdf-js-4.0.2.tgz#f01510528bbfc6e004012b71a8a533896c4c4c10" @@ -12517,15 +12481,15 @@ rdf-js@*, rdf-js@^4.0.2: dependencies: "@rdfjs/types" "*" -rdf-literal@^1.2.0, rdf-literal@^1.3.0, rdf-literal@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/rdf-literal/-/rdf-literal-1.3.1.tgz#07db05d4a92e1b8b3dd491a4499648872c6d96ee" - integrity sha512-+o/PGOfJchyay9Rjrvi/oveRJACnt2WFO3LhEvtPlsRD1tFmwVUCMU+s33FtQprMo+z1ohFrv/yfEQ6Eym4KgQ== +rdf-literal@^1.2.0, rdf-literal@^1.3.0, rdf-literal@^1.3.1, rdf-literal@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/rdf-literal/-/rdf-literal-1.3.2.tgz#6f1bd103bcd0be72a3d969115a6343a53c526eb2" + integrity sha512-79Stlu3sXy0kq9/decHFLf3xNPuY6sfhFPhd/diWErgaFr0Ekyg38Vh9bnVcqDYu48CFRi0t+hrFii49n92Hbw== dependencies: "@rdfjs/types" "*" rdf-data-factory "^1.1.0" -rdf-loader-code@^0.3.0, rdf-loader-code@^0.3.1: +rdf-loader-code@^0.3.0, rdf-loader-code@^0.3.1, rdf-loader-code@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/rdf-loader-code/-/rdf-loader-code-0.3.3.tgz#c8abf53329f577b502fac261df0cd44816133cfb" integrity sha512-5uLQOLn2YrPO9YxPpMqVqtX3SmCALH+97u2Tj8NA33baYgMMczam6G2EOm0kYRbIk3n5wgBCs2Z4Y6jkgPwRMg==