I wrote a new tool called shex-codegen with which you can generate the code to query and mutate shapes. It can generate shape objects that have methods through which it is very easy to read, create or modify nodes of a certain shape.
If we would want to create a solid profile e.g. with this shape expression:
PREFIX srs: <https://shaperepo.com/schemas/solidProfile#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX schem: <http://schema.org/>
PREFIX vcard: <http://www.w3.org/2006/vcard/ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
srs:SolidProfileShape EXTRA a {
a [ schem:Person ]
// rdfs:comment "Declares the node to be a schema.org Person" ;
a [ foaf:Person ]
// rdfs:comment "Declares the node to be a FOAF Person" ;
vcard:hasPhoto IRI ?
// rdfs:comment "A link to the person's photo" ;
foaf:name xsd:string ?
// rdfs:comment "An alternate way to define a person's name" ;
}
And with this config:
schema: "solidProfile.shex"
generates:
node_modules/@generated/shex.ts:
- typescript
- typescript-methods
In this example the codegen will try to read the shex file and generate a new file to node_modules/@generated/shex.ts
with roughly this content:
import { NamedNode, Literal } from "rdflib";
import { Shape } from "shex-methods";
export type SolidProfileShape = {
id: string;
hasPhoto?: string | NamedNode; // A link to the person's photo
name?: string | Literal; // An alternate way to define a person's name
} & {
type: (
| SolidProfileShapeType.SchemPerson
| SolidProfileShapeType.FoafPerson
)[]; // Defines the node as a Person
};
export enum SolidProfileShapeType {
SchemPerson = "http://schema.org/Person",
FoafPerson = "http://xmlns.com/foaf/0.1/Person",
}
export enum SolidProfileShapeContext {
"type" = "rdf:type",
"name" = "foaf:name",
"hasPhoto" = "vcard:hasPhoto",
}
export const solidProfile = new Shape<SolidProfileShape>({
id: "https://shaperepo.com/schemas/solidProfile#SolidProfileShape",
shape: solidProfileShex,
context: SolidProfileShapeContext,
type: SolidProfileShapeType,
});
You can then use the generated solidProfile
instance to create a new node that fits the shape expression:
import { solidProfile } from "@generated/shex"
const newProfile = await solidProfile.create({
doc: webIdDoc,
data: {
id: webId,
type: [SolidProfileShapeType.SchemPerson],
name: "Ludwig",
hasPhoto: "https://avatars.githubusercontent.com/u/35169452?v=4",
},
});
const { data, errors } = newProfile;
Authenticating can be done by updating the ._fetch method of the fetcher of a shape object. E.g. with solid-node-client
:
const client = new SolidNodeClient();
await client.login(config);
solidProfile.fetcher._fetch = client.fetch.bind(client);
Feel free to try it and leave some feedback or check out the repo if you want to learn more.
Now developers just have to agree on the underlying shape expression/schema and then the cost to become interoperable goes really low