diff --git a/packages/cli/README.md b/packages/cli/README.md index e88f798..648aff0 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -12,7 +12,10 @@ cd my-typescript-project npx @ldo/cli init ``` -### Manual Setup +
+ +Manual Setup + The following is handled by the __automatic setup__: Install the LDO dependencies. @@ -38,6 +41,7 @@ Create a script to build ShEx shapes and convert them into Linked Data Objects. ... } ``` +
## Generating a ShapeType @@ -67,7 +71,7 @@ This script will generate a project with a place to put your shapes. Running `np - [`init` command](https://ldo.js.org/api/cli/init/) - [`build` command](https://ldo.js.org/api/cli/build/) - [`create` command](https://ldo.js.org/api/cli/create/) -``` + ## Sponsorship This project was made possible by a grant from NGI Zero Entrust via nlnet. Learn more on the [NLnet project page](https://nlnet.nl/project/SolidUsableApps/). diff --git a/packages/dataset/Readme.md b/packages/dataset/Readme.md index 6769e81..e485aea 100644 --- a/packages/dataset/Readme.md +++ b/packages/dataset/Readme.md @@ -11,7 +11,7 @@ npm i @ldo/dataset ## Simple Example ```typescript -import { createDataset } from "o-dataset-pack"; +import { createDataset } from "@ldo/dataset"; import { quad, namedNode } from "@rdfjs/data-model"; const dataset = createDataset(); dataset.add( @@ -38,8 +38,8 @@ import { createDataset } from "@ldo/dataset"; import { quad, namedNode, literal } from "@rdfjs/data-model"; // Required for advanced features: import { dataset as initializeDatasetCore } from "@rdfjs/dataset"; -import { ExtendedDatasetFactory } from "o-dataset-pack"; -import { Dataset, Quad, DatasetCoreFactory, DatasetCore } from "rdf-js"; +import { ExtendedDatasetFactory } from "@ldo/dataset"; +import { Dataset, Quad, DatasetCoreFactory, DatasetCore } from "@rdfjs/types"; /** * Create a dataset with default settings diff --git a/packages/jsonld-dataset-proxy/README.md b/packages/jsonld-dataset-proxy/README.md index 5527f81..55840d9 100644 --- a/packages/jsonld-dataset-proxy/README.md +++ b/packages/jsonld-dataset-proxy/README.md @@ -10,7 +10,7 @@ const person = jsonldDatasetProxy( PersonContext ).fromSubject(namedNode("http://example.com/Person1")); person.age = 23; -person.name.push("John"); +person.name.add("John"); ``` are equivalent to: @@ -47,9 +47,9 @@ npm install @ldo/jsonld-dataset-proxy ## Simple Example ```typescript -import jsonldDatasetProxy, { write } from "jsonld-dataset-proxy"; +import jsonldDatasetProxy, { write, LdSet } from "jsonld-dataset-proxy"; import { ContextDefinition } from "jsonld"; -import { serializedToDataset } from "o-dataset-pack"; +import { serializedToDataset } from "@ldo/dataset"; import { namedNode } from "@rdfjs/data-model"; async function start() { @@ -72,9 +72,9 @@ async function start() { ).fromSubject(namedNode("http://example.com/Person1")); // Make Modifications person.age = 23; - person.name.push("John"); + person.name.add("John"); write(namedNode("http://example.com/otherGraph")).using(person); - person.name.push("Smith"); + person.name.add("Smith"); console.log(dataset.toString()); // Logs: @@ -86,7 +86,7 @@ async function start() { // Person Typescript Typing interface IPerson { - name: string[]; + name: LdSet; age: number; } @@ -117,7 +117,7 @@ start(); - [Getting Field Values and Traversing](#getting-field-values-and-traversing) - [Setting a Primitive](#setting-a-primitive) - [Setting an Object](#setting-an-object) - - [Array Methods](#array-methods) + - [Set Methods](#set-methods) - [Overwriting an Object](#overwriting-an-object) - [Changing an Object's Id](#changing-an-objects-id) - [Removing an Object Connection](#removing-an-object-connection) @@ -129,23 +129,23 @@ start(); - [`write(...graphs).usingCopy(...jsonldDatasetProxies)`](#writegraphsusingcopyjsonlddatasetproxies) - [Detecting a the graph of specific information](#detecting-a-the-graph-of-specific-information) -For the most part, a JSONLD Dataset Proxy has parity with JavaScript Object Literals. However, there are a few differences to highlight. This section details how you would do different tasks. +For the most part, you can think of a JSONLD Dataset Proxy as a JavaScript Object Literal with "Sets" instead of arrays. ### Defining a Context and Type -The first step to getting a JSONLD Dataset Proxy is defining the JSONLD Context and TypeScript Typings. This can either be done through a [generator](https://github.com/o-development/shexj2typeandcontext) or defining them manually. +The first step to getting a JSONLD Dataset Proxy is defining the JSONLD Context and TypeScript Typings. This can either be done through a [generator](https://ldo.js.org/api/cli/build/) or defining them manually. In this example typescript typing `IPerson` is an interface that represents a person. Notice the `@id` and `@context` fields. Be sure to include them in your interfaces if you wish to use those properties. ```typescript -import { ContextDefinition } from "jsonld"; +import { LdoJsonldContext, LdSet } from "@ldo/jsonld-dataset-proxy"; interface IPerson { "@id"?: string; - "@context"?: ContextDefinition; - name?: string[]; + "@context"?: LdoJsonldContext; + name?: LdSet; age?: number; bestFriend?: IPerson; - knows?: IPerson[]; + knows?: LdSet; } ``` @@ -250,12 +250,14 @@ friendsOfPerson1.forEach((person) => { `fromJson` will take any regular Json, add the information to the dataset, and return a Jsonld Dataset Proxy representing the given data. ```typescript +import { jsonldDatasetProxy, set } from "@ldo/jsonld-dataset-proxy"; + const person2 = jsonldDatasetProxy( dataset, PersonContext ).fromJson({ "@id": "http://example.com/Person2", - name: ["Jane", "Doe"], + name: set("Jane", "Doe"), birthdate: "1990/11/03", age: 33, }); @@ -300,7 +302,7 @@ console.log(person.name?.reduce((agg, cur) => agg + cur, "")); // JonathanJohn // But this isn't recommened. The library will do its best to maintain the // ordering in the array, but as datasets have no concept of order, this is // not always accurate. -console.log(person.name?.[1]); // John +console.log(person.name?.toArray()[0]); // John // Get the id of the object // (If the node is a blankNode the @id will be undefined) console.log(person.bestFriend?.["@id"]); // "http://example.com/Person2" @@ -328,6 +330,8 @@ console.log(dataset.toString()); Setting a field to a JavaScript object literal will recursively add all parts of the object literal to the dataset. ```typescript +import { set } from "@ldo/jsonld-dataset-pack"; + const dataset = createDataset(); const person = jsonldDatasetProxy( dataset, @@ -335,10 +339,10 @@ const person = jsonldDatasetProxy( ).fromSubject(namedNode("http://example.com/Person1")); person.bestFriend = { "@id": "http://example.com/Person2", - name: ["Alice"], + name: set("Alice"), bestFriend: { "@id": "http://example.com/Person3", - name: ["Bob"], + name: set("Bob"), }, }; console.log(dataset.toString()); @@ -348,8 +352,9 @@ console.log(dataset.toString()); // "Bob" . ``` -### Array Methods -Any methods that modify arrays work as expected. +### Set Methods +Any methods that on a [JavaScript Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) are available. + ```typescript const dataset = await serializedToDataset(` @@ -364,13 +369,48 @@ const person = jsonldDatasetProxy( dataset, PersonContext ).fromSubject(namedNode("http://example.com/Person1")); -person.name?.push("Ferguson"); +person.name?.add("Ferguson"); console.log(dataset.toString()); // "Garrett" . // "Bobby" . // "Ferguson" . ``` +For convenience, some methods commonly used on arrays have been added. The methods available on Sets are defined as follows: + +```typescript +LdSet { + add(value: T): this; + clear(): void; + delete(value: T): boolean; + has(value: T): boolean; + readonly size: number; + [Symbol.iterator](): IterableIterator; + entries(): IterableIterator<[T, T]>; + keys(): IterableIterator; + values(): IterableIterator; + every(predicate: (value: T, set: LdSet) => value is S, thisArg?: any): this is LdSet; + every(predicate: (value: T, set: LdSet) => unknown, thisArg?: any): boolean; + some(predicate: (value: T, set: LdSet) => unknown, thisArg?: any): boolean; + forEach(callbackfn: (value: T, value2: T, set: LdSet) => void, thisArg?: any): void; + map(callbackfn: (value: T, set: LdSet) => U, thisArg?: any): U[]; + filter(predicate: (value: T, set: LdSet) => value is S, thisArg?: any): LdSet; + filter(predicate: (value: T, set: LdSet) => unknown, thisArg?: any): LdSet; + reduce(callbackfn: (previousValue: T, currentValue: T, set: LdSet) => T): T; + reduce(callbackfn: (previousValue: T, currentValue: T, set: LdSet) => T, initialValue: T): T; + reduce(callbackfn: (previousValue: U, currentValue: T, array: LdSet) => U, initialValue: U): U; + toArray(): T[]; + toJSON(): T[]; + difference(other: Set): LdSet; + intersection(other: Set): LdSet; + isDisjointFrom(other: Set): boolean; + isSubsetOf(other: Set): boolean; + isSupersetOf(other: Set): boolean; + symmetricDifference(other: Set): LdSet; + union(other: Set): LdSet; +} +``` + ### Overwriting an Object If an object literal is set and the id is equivalent to an existing id, that node will be overwritten. All triples from the previous object are removed and replaced with triples from the new object. @@ -390,7 +430,7 @@ const person = jsonldDatasetProxy( ).fromSubject(namedNode("http://example.com/Person1")); person.bestFriend = { "@id": "http://example.com/Person2", - name: ["Jane"], + name: set("Jane"), }; console.log(dataset.toString()); // "Jane" . @@ -398,7 +438,7 @@ console.log(dataset.toString()); ``` ### Changing an Object's Id -You can rename an object by setting its `@id` field. This will update all triples that reference the id to the new id. +You can rename an object by setting its `@id` field. This will update all triples that reference the id to the new id. Setting the `@id` field to `undefined` will turn it into a blank node. ```typescript const dataset = await serializedToDataset(` @@ -425,7 +465,7 @@ console.log(dataset.toString()); ``` ### Removing an Object Connection -Removing one triple can be done by setting a property to `undefined`; +Removing a connection between nodes can be done by setting a field to `undefined` or using the `delete` operator. Values can be removed from a set by using the `delete` method or the `clear` method to remove all connections. ```typescript const dataset = await serializedToDataset(` @@ -445,41 +485,16 @@ const person = jsonldDatasetProxy( dataset, PersonContext ).fromSubject(namedNode("http://example.com/Person1")); +perons.bestFriend.name.delete("Bob"); person.bestFriend = undefined; console.log(dataset.toString()); // "Alice" . -// "Bob" . // . ``` ### Deleting an Entire Object -If you want to delete all triples represented by an object, there are two ways using the `delete` operator. - -First, you can call `delete` on a specific property: -```typescript -const dataset = await serializedToDataset(` - @prefix example: . - @prefix foaf: . - @prefix xsd: . - - example:Person1 - foaf:name "Alice"^^xsd:string; - foaf:bestFriend example:Person2. - - example:Person2 - foaf:name "Bob"^^xsd:string; - foaf:bestFriend example:Person1. -`); -const person = jsonldDatasetProxy( - dataset, - PersonContext -).fromSubject(namedNode("http://example.com/Person1")); -delete person.bestFriend; -console.log(dataset.toString()); -// "Alice" . -``` +If you want to delete all triples represented by an object you can call `delete` on the `@id` property. -And secondly, you can call `delete` on the `@id` property. ```typescript const dataset = await serializedToDataset(` @prefix example: . @@ -512,7 +527,7 @@ const person = jsonldDatasetProxy( PersonContext ).fromSubject(namedNode("http://example.com/Person1")); person.bestFriend = { - name: ["Charlie"], + name: set("Charlie"), }; console.log(dataset.toString()); // _:b1 . @@ -536,7 +551,7 @@ const person = jsonldDatasetProxy( PersonContext, ).fromSubject(namedNode("http://example.com/Person1")); -const alice = person.knows?.[0]; +const alice = person.knows?.toArray()[0]; person.bestFriend = alice; console.log(dataset.toString()); // _:n3-0 "Alice" . @@ -556,7 +571,7 @@ The write graph can be set upon creating a jsonld dataset proxy by using the `wr const person1 = jsonldDatasetProxy(dataset, PersonContext) .write(namedNode("http://example.com/ExampleGraph")) .fromSubject(namedNode("http://example.com/Person1")); -person1.name.push("Jack"); +person1.name.add("Jack"); console.log(dataset.toString()); // Logs: // "Jack" . @@ -574,10 +589,10 @@ const person1 = jsonldDatasetProxy( ).fromSubject(namedNode("http://example.com/Person1")); // Now all additions with person1 will be on ExampleGraph1 write(namedNode("http://example.com/ExampleGraph1")).using(person1); -person1.name.push("Jack"); +person1.name.add("Jack"); // Now all additions with person1 will be on ExampleGraph2 write(namedNode("http://example.com/ExampleGraph2")).using(person1); -person1.name.push("Spicer"); +person1.name.add("Spicer"); console.log(dataset.toString()); // Logs: @@ -592,19 +607,19 @@ const person1 = jsonldDatasetProxy( dataset, PersonContext ).fromSubject(namedNode("http://example.com/Person1")); -person1.name.push("default"); +person1.name.add("default"); const end1 = write(namedNode("http://example.com/Graph1")).using(person1); -person1.name.push("1"); +person1.name.add("1"); const end2 = write(namedNode("http://example.com/Graph2")).using(person1); -person1.name.push("2"); +person1.name.add("2"); const end3 = write(namedNode("http://example.com/Graph3")).using(person1); -person1.name.push("3"); +person1.name.add("3"); end3(); -person1.name.push("2 again"); +person1.name.add("2 again"); end2(); -person1.name.push("1 again"); +person1.name.add("1 again"); end1(); -person1.name.push("default again"); +person1.name.add("default again"); console.log(dataset.toString()); // Logs: // "default" . @@ -627,8 +642,8 @@ const person1 = jsonldDatasetProxy( const [person1WritingToNewGraph] = write( namedNode("http://example.com/NewGraph") ).usingCopy(person1); -person1WritingToNewGraph.name.push("Brandon"); -person1.name.push("Sanderson"); +person1WritingToNewGraph.name.add("Brandon"); +person1.name.add("Sanderson"); console.log(dataset.toString()); // Logs: // "Brandon" . @@ -641,10 +656,10 @@ The graph of specific information can be detected using the `graphOf(subject, pr - `subject`: A Jsonld Dataset Proxy that represents the subject of a quad. - `predicate`: A string key - - `object?`: An optional parameter that represents the direct object of a statement. This could be a Jsonld Dataset Proxy or a number to indicate the location in an array. This argument can be left blank if the given field is not an array. + - `object?`: A representation of the direct object of the triple in question. This could be a jsonld-dataset-proxy or simply and object with an `@id` field. ```typescript -graphOf(person, "name", 0); // returns defaultGraph() +graphOf(person, "name", "Bob"); // returns defaultGraph() graphOf(person, "age"); // returns defaultGraph() ``` @@ -723,17 +738,17 @@ const hospitalInfo = jsonldDatasetProxy(dataset, PersonContext) .fromSubject(namedNode("http://example.com/Hospital")); console.log(hospitalInfo.label); // Logs "병원" -console.log(hospitalInfo.description.length); // Logs "2" for the 2 korean entries -console.log(hospitalInfo.description[0]); // Logs "환자를 치료하다" -console.log(hospitalInfo.description[1]); // Logs "의사 있음" +console.log(hospitalInfo.description.size); // Logs "2" for the 2 korean entries +console.log(hospitalInfo.description.toArray()[0]); // Logs "환자를 치료하다" +console.log(hospitalInfo.description.toArray()[1]); // Logs "의사 있음" // Adds a string to the description in spanish, because spanish if the first // language in the language preference -hospitalInfo.description.push("Cura a las pacientes"); +hospitalInfo.description.add("Cura a las pacientes"); // Now that a spanish entry exists, JSON-LD dataset proxy focuses on that console.log(hospitalInfo.description.length); // Logs "1" for the 1 spanish entry -console.log(hospitalInfo.description[0]); // Logs "Cura a las pacientes" +console.log(hospitalInfo.description.toArray()[0]); // Logs "Cura a las pacientes" ``` ### `setLanguagePreferences(...languagePreferences).using(...jsonldDatasetProxies)` diff --git a/packages/jsonld-dataset-proxy/readme-images/Intellisense.png b/packages/jsonld-dataset-proxy/readme-images/Intellisense.png index 9c25bec..6a9f53b 100644 Binary files a/packages/jsonld-dataset-proxy/readme-images/Intellisense.png and b/packages/jsonld-dataset-proxy/readme-images/Intellisense.png differ diff --git a/packages/ldo/README.md b/packages/ldo/README.md index 2b83a88..f54d157 100644 --- a/packages/ldo/README.md +++ b/packages/ldo/README.md @@ -16,20 +16,30 @@ cd my_project/ npx run @ldo/cli init ``` -### Manual Installation +
+ +Manual Installation + If you already have generated ShapeTypes, you may install the `@ldo/ldo` library independently. ``` npm i @ldo/ldo ``` +
## Simple Example Below is a simple example of LDO in a real use-case (changing the name on a Solid Pod). Assume that a ShapeType was previously generated and placed at `./.ldo/foafProfile.shapeTypes`. ```typescript -import { parseRdf, startTransaction, toSparqlUpdate, toTurtle } from "@ldo/ldo"; +import { + parseRdf, + startTransaction, + toSparqlUpdate, + toTurtle, + set, +} from "@ldo/ldo"; import { FoafProfileShapeType } from "./.ldo/foafProfile.shapeTypes"; async function run() { @@ -60,26 +70,26 @@ async function run() { // Logs "Person" console.log(janeProfile.type); // Logs 0 - console.log(janeProfile.knows?.length); + console.log(janeProfile.knows?.size); // Begins a transaction that tracks your changes startTransaction(janeProfile); janeProfile.name = "Jane Smith"; - janeProfile.knows?.push({ + janeProfile.knows?.add({ "@id": "https://solidweb.me/john_smith/profile/card#me", type: { "@id": "Person", }, name: "John Smith", - knows: [janeProfile], + knows: set(janeProfile), }); // Logs "Jane Smith" console.log(janeProfile.name); // Logs "John Smith" - console.log(janeProfile.knows?.[0].name); + console.log(janeProfile.knows?.toArray()[0].name); // Logs "Jane Smith" - console.log(janeProfile.knows?.[0].knows?.[0].name); + console.log(janeProfile.knows?.toArray()[0].knows?.toArray()[0].name); /** * Step 3: Convert it back to RDF diff --git a/packages/schema-converter-shex/README.md b/packages/schema-converter-shex/README.md index c732a6a..b4db894 100644 --- a/packages/schema-converter-shex/README.md +++ b/packages/schema-converter-shex/README.md @@ -7,9 +7,6 @@ Turn ShexJ into typescript typings and JSON-LD context. npm i @ldo/schema-converter-shex ``` -## API -See the [full API docs](docs/modules.md). - ## Usage ```typescript @@ -83,14 +80,15 @@ async function run() { /* Logs: - declare namespace { - interface EmployeeShape { - givenName: string[]; - familyName: string; - phone?: string[]; - mbox: string; - } + import { LdoJsonldContext, LdSet } from "@ldo/ldo"; + interface EmployeeShape { + "@id"?: string; + "@context"?: LdoJsonldContext; + givenName: LdSet; + familyName: string; + phone?: LdSet; + mbox: string; } */ console.log(typings.typingsString); diff --git a/packages/solid-react/README.md b/packages/solid-react/README.md index 12948c0..9eb85fd 100644 --- a/packages/solid-react/README.md +++ b/packages/solid-react/README.md @@ -1,8 +1,132 @@ # @ldo/solid-react -Alpha +`@ldo/solid-react` provides tool and hooks for easily building Solid applications using react. -// TODO: Write readme +## Guide + +A full walkthrough for using the `@ldo/solid` library can be found in the [For Solid + React Guide](https://ldo.js.org/guides/solid_react/) + +## Installation + +Navigate into your project's root folder and run the following command: +``` +cd my_project/ +npx run @ldo/cli init +``` + +Now install the @ldo/solid library + +``` +npm i @ldo/solid @ldo/solid-react +``` + +
+ +Manual Installation + + +If you already have generated ShapeTypes, you may install the `@ldo/ldo` and `@ldo/solid` libraries independently. + +``` +npm i @ldo/ldo @ldo/solid @ldo/solid-react +``` +
+ +## Simple Example + +Below is a simple example of @ldo/solid-react in a real use-case. Assume that a ShapeType was previously generated and placed at `./.ldo/solidProfile.shapeTypess`. + + +```typescript +import type { FunctionComponent } from "react"; +import React, { useCallback } from "react"; +import { + BrowserSolidLdoProvider, + useResource, + useSolidAuth, + useSubject, +} from "@ldo/solid-react"; +import { SolidProfileShapeShapeType } from "./.ldo/solidProfile.shapeTypes"; +import { changeData, commitData } from "@ldo/solid"; + +// The base component for the app +const App: FunctionComponent = () => { + return ( + /* The application should be surrounded with the BrowserSolidLdoProvider + this will set up all the underlying infrastructure for the application */ + + + + ); +}; + +// A component that handles login +const Login: FunctionComponent = () => { + // Get login information using the "useSolidAuth" hook + const { login, logout, session } = useSolidAuth(); + + const onLogin = useCallback(() => { + const issuer = prompt("What is your Solid IDP?"); + // Call the "login" function to initiate login + if (issuer) login(issuer); + }, []); + + // You can use session.isLoggedIn to check if the user is logged in + if (session.isLoggedIn) { + return ( +
+ {/* Get the user's webId from session.webId */} +

Logged in as {session.webId}

+ {/* Use the logout function to log out */} + + +
+ ); + } + return ; +}; + +// Renders the name on the profile +const Profile: FunctionComponent = () => { + const { session } = useSolidAuth(); + // With useResource, you can automatically fetch a resource + const resource = useResource(session.webId); + // With useSubject, you can extract data from that resource + const profile = useSubject(SolidProfileShapeShapeType, session.webId); + + const onNameChange = useCallback(async (e) => { + // Ensure that the + if (!profile || !resource) return; + // Change data lets you create a new object to make changes to + const cProfile = changeData(profile, resource); + // Change the name + cProfile.name = e.target.value; + // Commit the data back to the Pod + await commitData(cProfile); + }, []); + + return ; +}; + +export default App; +``` + +## API Details + +Providers + + - [BrowserSolidLdoProvider](https://ldo.js.org/api/solid-react/BrowserSolidLdoProvider/) + - [SolidLdoProvider](https://ldo.js.org/api/solid-react/SolidLdoProvider/) + +Hooks + - [useLdo](https://ldo.js.org/api/solid-react/useLdo/) + - [useResource](https://ldo.js.org/api/solid-react/useResource/) + - [useRootContainer](https://ldo.js.org/api/solid-react/useRootContainer/) + - [useSolidAuth](https://ldo.js.org/api/solid-react/useSolidAuth/) + - [useSubject](https://ldo.js.org/api/solid-react/useSubject/) + - [useMatchSubject](https://ldo.js.org/api/solid-react/useMatchSubject/) + - [useMatchObject](https://ldo.js.org/api/solid-react/useMatchSubject/) + - [useSubscribeToResource](https://ldo.js.org/api/solid-react/useMatchSubject/) ## Sponsorship This project was made possible by a grant from NGI Zero Entrust via nlnet. Learn more on the [NLnet project page](https://nlnet.nl/project/SolidUsableApps/). @@ -11,4 +135,4 @@ This project was made possible by a grant from NGI Zero Entrust via nlnet. Learn [NGI Zero Entrust Logo](https://nlnet.nl/) ## Liscense -MIT +MIT \ No newline at end of file diff --git a/packages/solid/README.md b/packages/solid/README.md index ecdeab6..8216254 100644 --- a/packages/solid/README.md +++ b/packages/solid/README.md @@ -16,13 +16,17 @@ Now install the @ldo/solid library npm i @ldo/solid ``` -### Manual Installation +
+ +Manual Installation + If you already have generated ShapeTypes, you may install the `@ldo/ldo` and `@ldo/solid` libraries independently. ``` npm i @ldo/ldo @ldo/solid ``` +
## Simple Examples