Link Library
A Link to the Web
Reference: How to use Link with React
This package aims to make building rich web applications quick and easy by providing all the tools
needed to work with linked data, providing high-level API's for view rendering, data querying
& manipulation, and API communication. See the link-redux package on how to
use this in a React project.
To transform your Rails application into a linked-data serving beast, see our
Active Model Serializers plugin.
This was built at Argu, if you like what we do, these technologies
or open data, send us a mail.
Example
See the TODO app for a live example and
link-redux-todo for the implementation. Mind that it isn't connected to
a back-end, so it's only a demo for the view rendering mechanism.
Installation
yarn add link-lib
and some peer dependencies:
yarn add @ontologies/as @ontologies/core @ontologies/schema @ontologies/shacl @ontologies/xsd http-status-codes n-quads-parser
The package externalizes the Promise API, so make sure to include your own when targeting platforms without native
support.
Usage
See the Hypermedia API page for documentation on how to
execute actions against the service.
See Link Redux for documentation on how to use Link in a React application.
Included namespace prefixes
See the utilities for the namespaces included by
default.
Contributing
The usual stuff. Open an issue to discuss a change, open PR's from topic-branches targeted to master for bugfixes and
refactors.
Variables
Const CI_MATCH_PREFIX
CI_MATCH_PREFIX: 0 = 0
Const CI_MATCH_SUFFIX
CI_MATCH_SUFFIX: 1 = 1
Const DATA_ACQUIRED
DATA_ACQUIRED: "DATA_ACQUIRED" = "DATA_ACQUIRED"
Const DEC_CUTOFF
DEC_CUTOFF: 2 = 2
Const DEFAULT_TOPOLOGY
DEFAULT_TOPOLOGY: NamedNode = ll.defaultTopology
Const DT
DT: any = rdfFactory.id(DEFAULT_TOPOLOGY)
Const EMPTY_ST_ARR
EMPTY_ST_ARR: ReadonlyArray<Quad> = Object.freeze([])
Const FETCHER_CALLBACKS
FETCHER_CALLBACKS: string[] = ["done", "fail", "refresh", "request", "retract"]
Const FETCH_EXT
FETCH_EXT: "FETCH_EXT" = "FETCH_EXT"
Const FETCH_RESOURCE
FETCH_RESOURCE: "FETCH_RESOURCE" = "FETCH_RESOURCE"
Const F_JSON
F_JSON: "application/json" = "application/json"
Const F_JSONLD
F_JSONLD: "application/ld+json" = "application/ld+json"
Const F_N3
F_N3: "text/n3" = "text/n3"
Const F_NQUADS
F_NQUADS: "application/n-quads" = "application/n-quads"
Const F_NTRIPLES
F_NTRIPLES: "application/n-triples" = "application/n-triples"
Const F_NTRIPLES_DEP
F_NTRIPLES_DEP: "text/ntriples" = "text/ntriples"
Const F_PLAIN
F_PLAIN: "text/plain" = "text/plain"
Const F_RDF_XML
F_RDF_XML: "application/rdf+xml" = "application/rdf+xml"
Const F_TURTLE
F_TURTLE: "text/turtle" = "text/turtle"
Const F_TURTLE_DEP
F_TURTLE_DEP: "application/x-turtle" = "application/x-turtle"
Const GET_ENTITY
GET_ENTITY: "GET_ENTITY" = "GET_ENTITY"
Const IRI_LEN
IRI_LEN: 20 = 20
LinkedDataAPI
LinkedDataAPI: { constructor: any }
Const MAIN_NODE_DEFAULT_IRI
MAIN_NODE_DEFAULT_IRI: NamedNode = ll.targetResource
Const MSG_BAD_REQUEST
MSG_BAD_REQUEST: "Request failed with bad status code" = "Request failed with bad status code"
Const MSG_INCORRECT_TARGET
MSG_INCORRECT_TARGET: "Collections or Literals can't be the target" = "Collections or Literals can't be the target"
Const MSG_OBJECT_NOT_IRI
MSG_OBJECT_NOT_IRI: "Action object property must be an IRI." = "Action object property must be an IRI."
Const MSG_TYPE_ERR
MSG_TYPE_ERR: "Non-optimized NamedNode instance given. Please memoize your namespace correctly." = "Non-optimized NamedNode instance given. Please memoize your namespace correctly."
Const MSG_URL_UNDEFINED
MSG_URL_UNDEFINED: "No url given with action." = "No url given with action."
Const MSG_URL_UNRESOLVABLE
MSG_URL_UNRESOLVABLE: "Can't execute action with non-named-node url." = "Can't execute action with non-named-node url."
Const NON_CONTENT_EXTS
NON_CONTENT_EXTS: string[] = ["php", "asp", "aspx", "cgi", "jsp"]
Const NON_DATA_OBJECTS_CTORS
NON_DATA_OBJECTS_CTORS: Function[] = [Array,ArrayBuffer,Boolean,DataView,Date,Error,EvalError,Float32Array,Float64Array,Int16Array,Int32Array,Int8Array,Intl.Collator,Intl.DateTimeFormat,Intl.NumberFormat,Map,Number,Promise,/* istanbul ignore next */(typeof Proxy !== "undefined" ? Proxy : undefined)!,RangeError,ReferenceError,RegExp,Set,].filter(Boolean)
Const OWL
OWL
: VocabularyProcessor = {axioms: [],processStatement(item: Quad, ctx: VocabularyProcessingContext): Quad[] | null {if (rdfFactory.equals(item.predicate, nsOWLsameAs)) {const a = ctx.equivalenceSet.add((item.object as SomeNode).id as number);const b = ctx.equivalenceSet.add(item.subject.id as number);ctx.equivalenceSet.union(a, b);return [item];}return null;},processType(_: NamedNode, __: VocabularyProcessingContext): boolean {return false;},} as VocabularyProcessor
Const RCN
RCN: any = rdfFactory.id(RENDER_CLASS_NAME)
Const RDFS
RDFS
: VocabularyProcessor = {axioms: [rdfFactory.quad(rdf.type, rdfs.domain, rdfs.Resource),rdfFactory.quad(rdfs.domain, rdfs.domain, rdf.Property),rdfFactory.quad(rdfs.range, rdfs.domain, rdf.Property),rdfFactory.quad(rdfs.subPropertyOf, rdfs.domain, rdf.Property),rdfFactory.quad(rdfs.subClassOf, rdfs.domain, rdfs.Class),rdfFactory.quad(rdf.subject, rdfs.domain, rdf.Statement),rdfFactory.quad(rdf.predicate, rdfs.domain, rdf.Statement),rdfFactory.quad(rdf.object, rdfs.domain, rdf.Statement),rdfFactory.quad(rdfs.member, rdfs.domain, rdfs.Resource),rdfFactory.quad(rdf.first, rdfs.domain, rdf.List),rdfFactory.quad(rdf.rest, rdfs.domain, rdf.List),rdfFactory.quad(rdfs.seeAlso, rdfs.domain, rdfs.Resource),rdfFactory.quad(rdfs.isDefinedBy, rdfs.domain, rdfs.Resource),rdfFactory.quad(rdfs.comment, rdfs.domain, rdfs.Resource),rdfFactory.quad(rdfs.label, rdfs.domain, rdfs.Resource),rdfFactory.quad(rdf.value, rdfs.domain, rdfs.Resource),rdfFactory.quad(rdf.type, rdfs.range, rdfs.Class),rdfFactory.quad(rdfs.domain, rdfs.range, rdfs.Class),rdfFactory.quad(rdfs.range, rdfs.range, rdfs.Class),rdfFactory.quad(rdfs.subPropertyOf, rdfs.range, rdf.Property),rdfFactory.quad(rdfs.subClassOf, rdfs.range, rdfs.Class),rdfFactory.quad(rdf.subject, rdfs.range, rdfs.Resource),rdfFactory.quad(rdf.predicate, rdfs.range, rdfs.Resource),rdfFactory.quad(rdf.object, rdfs.range, rdfs.Resource),rdfFactory.quad(rdfs.member, rdfs.range, rdfs.Resource),rdfFactory.quad(rdf.first, rdfs.range, rdfs.Resource),rdfFactory.quad(rdf.rest, rdfs.range, rdf.List),rdfFactory.quad(rdfs.seeAlso, rdfs.range, rdfs.Resource),rdfFactory.quad(rdfs.isDefinedBy, rdfs.range, rdfs.Resource),rdfFactory.quad(rdfs.comment, rdfs.range, rdfs.Literal),rdfFactory.quad(rdfs.label, rdfs.range, rdfs.Literal),rdfFactory.quad(rdf.value, rdfs.range, rdfs.Resource),rdfFactory.quad(rdf.Alt, rdfs.subClassOf, rdfs.Container),rdfFactory.quad(rdf.Bag, rdfs.subClassOf, rdfs.Container),rdfFactory.quad(rdf.Seq, rdfs.subClassOf, rdfs.Container),rdfFactory.quad(rdfs.ContainerMembershipProperty, rdfs.subClassOf, rdf.Property),rdfFactory.quad(rdfs.isDefinedBy, rdfs.subPropertyOf, rdfs.seeAlso),rdfFactory.quad(rdfs.Datatype, rdfs.subClassOf, rdfs.Class),rdfFactory.quad(rdfs.Resource, rdf.type, rdfs.Class),rdfFactory.quad(rdfs.Class, rdf.type, rdfs.Class),],processStatement(item: Quad, ctx: VocabularyProcessingContext): Quad[] | null {const result = [item];const domainStatements = ctx.store.match(item.predicate, rdfs.domain, null, null);if (domainStatements.length > 0) {for (let i = 0; i < domainStatements.length; i++) {result.push(rdfFactory.quad(item.subject as NamedNode, rdf.type, domainStatements[i].object));}}const rangeStatements = ctx.store.match(item.predicate, rdfs.range, null, null);if (rangeStatements.length > 0) { // P rdfs:range C..Cnfor (let i = 0; i < rangeStatements.length; i++) {result.push(rdfFactory.quad(item.object as NamedNode, rdf.type, rangeStatements[i].object));}}if (equals(rdfs.domain, item.predicate)) {result.push(rdfFactory.quad(item.subject, rdf.type, rdf.Property)); // P rdf:type rdf:Propertyresult.push(rdfFactory.quad(item.object, rdf.type, rdfs.Class)); // C rdf:type rdfs:Classconst dereferences = ctx.store.match(item.subject, null, null, null);for (let i = 0; i < dereferences.length; i++) {result.push(rdfFactory.quad(item.subject as NamedNode, rdf.type, dereferences[i].object));}if (!equals(item.subject, rdf.type)) {ctx.dataStore.getInternalStore().newPropertyAction(item.subject as NamedNode,(quad: Quad) => {ctx.store.addQuads([rdfFactory.quad(quad.subject, rdf.type, item.object)]);return true;},);}} else if (equals(rdfs.range, item.predicate)) {result.push(rdfFactory.quad(item.subject, rdf.type, rdf.Property)); // P rdf:type rdf:Propertyresult.push(rdfFactory.quad(item.object, rdf.type, rdfs.Class)); // C rdf:type rdfs:Classconst dereferences = ctx.store.match(null, null, item.subject, null);for (let i = 0; i < dereferences.length; i++) {result.push(rdfFactory.quad(dereferences[i].subject, rdf.type, item.object));}if (!equals(item.subject, rdf.type)) {ctx.dataStore.getInternalStore().newPropertyAction(item.subject as NamedNode,(quad: Quad) => {ctx.store.addQuads([rdfFactory.quad(quad.object, rdf.type, item.object)]);return true;},);}} else if (equals(rdfs.subClassOf, item.predicate)) { // C1 rdfs:subClassOf C2if (!(item.object.termType === TermType.NamedNode || item.object.termType === TermType.BlankNode)) {throw new Error("Object of subClassOf statement must be a NamedNode");}const iSubject = id(item.subject);const iObject = id(item.object);if (!ctx.superMap.has(iObject)) {ctx.superMap.set(iObject, new Set([id(rdfs.Resource)]));}let parents = ctx.superMap.get(iObject);if (parents === undefined) {parents = new Set();ctx.superMap.set(iObject, parents);}parents.add(iObject);const itemVal = ctx.superMap.get(iSubject) || new Set<number>([iSubject]);parents.forEach((i) => itemVal.add(i));ctx.superMap.set(iSubject, itemVal);ctx.superMap.forEach((v, k) => {if (k !== iSubject && v.has(iSubject)) {itemVal.forEach(v.add, v);}});} else if (equals(rdfs.subPropertyOf, item.predicate)) {// TODO: Implementreturn result;}return result.length === 1 ? null : result;},processType(type: NamedNode, ctx: VocabularyProcessingContext): boolean {RDFS.processStatement(rdfFactory.quad(type, rdfs.subClassOf, rdfs.Resource), ctx);ctx.store.addQuads([rdfFactory.quad(type, rdf.type, rdfs.Class)]);return false;},} as VocabularyProcessor
Const RENDER_CLASS_NAME
RENDER_CLASS_NAME: NamedNode = ll.typeRenderClass
Const SAFE_METHODS
SAFE_METHODS: string[] = ["GET", "HEAD", "OPTIONS", "CONNECT", "TRACE"]
Const SET_ACCEPT_HOST
SET_ACCEPT_HOST: "SET_ACCEPT_HOST" = "SET_ACCEPT_HOST"
Const STORE_UPDATE
STORE_UPDATE: "STORE_UPDATE" = "STORE_UPDATE"
Const createNS
createNS: (ns: string) => Namespace = basicCreateNS
Type declaration
-
-
Parameters
Returns Namespace
Const creativeWorkStatements
creativeWorkStatements: any[] = [rdfFactory.quad(schemaCW, rdf.type, rdfs.Class),rdfFactory.quad(schemaCW, rdfs.label, rdfFactory.literal("CreativeWork")),rdfFactory.quad(schemaCW, rdfs.subClassOf, schemaT),rdfFactory.quad(schemaCW,dcterms.source,rdfFactory.namedNode("http://www.w3.org/wiki/WebSchemas/SchemaDotOrgSources#source_rNews"),),rdfFactory.quad(schemaCW,rdfs.comment,rdfFactory.literal("The most generic kind of creative work, including books, movies, [...], etc."),),]
Const emptyRequest
empty
Request: EmptyRequestStatus = Object.freeze({lastRequested: null,requested: false,status: null,timesRequested: 0,}) as EmptyRequestStatus
Const equals
equals: (Anonymous function) = rdfFactory.supports[Feature.identity]? (a: any, b: any): boolean => a === b: rdfFactory.supports[Feature.idStamp]? (a: any, b: any): boolean => a?.id === b?.id: (a: any, b: any): boolean => rdfFactory.equals(a, b)
Const ex
ex: (term: string) => NamedNode = createNS("http://example.com/ns#")
Type declaration
-
- (term: string): NamedNode
-
Parameters
Returns NamedNode
Const example
example: (term: string) => NamedNode = createNS("http://example.com/")
Type declaration
-
- (term: string): NamedNode
-
Parameters
Returns NamedNode
Const http
http: (term: string) => NamedNode = createNS("http://www.w3.org/2007/ont/http#")
Type declaration
-
- (term: string): NamedNode
-
Parameters
Returns NamedNode
Const httph
httph: (term: string) => NamedNode = createNS("http://www.w3.org/2007/ont/httph#")
Type declaration
-
- (term: string): NamedNode
-
Parameters
Returns NamedNode
Const ianaJSONLDResource
ianaJSONLDResource: NamedNode = ianaMT(`${F_JSONLD}#Resource`)
Const ianaJSONResource
ianaJSONResource: NamedNode = ianaMT(`${F_JSON}#Resource`)
Const ianaMT
ianaMT: (term: string) => NamedNode = createNS("http://www.w3.org/ns/iana/media-types/")
Type declaration
-
- (term: string): NamedNode
-
Parameters
Returns NamedNode
Const ianaN3Resource
ianaN3Resource: NamedNode = ianaMT(`${F_N3}#Resource`)
Const ianaNQResource
ianaNQResource: NamedNode = ianaMT(`${F_NQUADS}#Resource`)
Const ianaNTResource
ianaNTResource: NamedNode = ianaMT(`${F_NTRIPLES}#Resource`)
Const ianaPlainResource
ianaPlainResource: NamedNode = ianaMT(`${F_PLAIN}#Resource`)
Const ianaRDFXMLResource
ianaRDFXMLResource: NamedNode = ianaMT(`${F_RDF_XML}#Resource`)
Const ianaTTLResource
ianaTTLResource: NamedNode = ianaMT(`${F_TURTLE}#Resource`)
Const id
id: (Anonymous function) = rdfFactory.supports[Feature.idStamp]? (obj?: Term | Quad | any): number => (obj as any)?.id || noIdError(obj): (obj?: Term | Quad | any): number => rdfFactory.id(obj)
Const ldNS
ldNS: (term: string) => NamedNode = createNS("http://purl.org/linked-delta/")
Type declaration
-
- (term: string): NamedNode
-
Parameters
Returns NamedNode
Const link
link: (term: string) => NamedNode = createNS("http://www.w3.org/2007/ont/link#")
Type declaration
-
- (term: string): NamedNode
-
Parameters
Returns NamedNode
Const ll
ll: (term: string) => NamedNode = createNS("http://purl.org/link-lib/")
Type declaration
-
- (term: string): NamedNode
-
Parameters
Returns NamedNode
Const memberPrefix
memberPrefix: string = rdf.ns("_").value
Const nsOWLsameAs
nsOWLsameAs: NamedNode = owl.sameAs
Const quadParts
quad
Parts: Array<keyof Omit<Quad, keyof IdTerm>> = ["subject","predicate","object","graph",]
Const schemaCW
schemaCW: NamedNode = schema.CreativeWork
Const schemaT
schemaT: NamedNode = schema.Thing
Const thingStatements
thingStatements: any[] = [rdfFactory.quad(schemaT, rdf.type, rdfs.Class),rdfFactory.quad(schemaT, rdfs.comment, rdfFactory.literal("The most generic type of item.")),rdfFactory.quad(schemaT, rdfs.label, rdfFactory.literal("Thing.")),]
Implements the RDF/RDFS axioms and rules.