Merge pull request #114 from o-development/feat/useLdoForm

Feat/use ldo form
main
jaxoncreed 3 weeks ago committed by GitHub
commit 5425b90ab4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 10
      .eslintrc
  2. 4
      .vscode/settings.json
  3. 2
      lerna.json
  4. 1525
      package-lock.json
  5. 6
      packages/cli/package.json
  6. 8
      packages/connected-nextgraph/package.json
  7. 8
      packages/connected-solid/package.json
  8. 4
      packages/connected/package.json
  9. 4
      packages/connected/src/ConnectedLdoTransactionDataset.ts
  10. 4
      packages/connected/src/trackingProxy/TrackingSubjectProxy.ts
  11. 13
      packages/connected/test/mocks/MockConnectedLdoDataset.ts
  12. 45
      packages/connected/test/mocks/MockConnectedPlugin.ts
  13. 24
      packages/connected/test/mocks/MockResource.ts
  14. 4
      packages/jsonld-dataset-proxy/package.json
  15. 4
      packages/jsonld-dataset-proxy/src/setLanguagePreferences.ts
  16. 2
      packages/jsonld-dataset-proxy/src/util/createInteractOptions.ts
  17. 4
      packages/jsonld-dataset-proxy/src/write.ts
  18. 6
      packages/ldo/package.json
  19. 18
      packages/react/package.json
  20. 30
      packages/react/src/createLdoReactMethods.tsx
  21. 5
      packages/react/src/index.ts
  22. 24
      packages/react/src/methods/change/types.ts
  23. 58
      packages/react/src/methods/change/useChangeDataset.ts
  24. 66
      packages/react/src/methods/change/useChangeMatchObject.ts
  25. 68
      packages/react/src/methods/change/useChangeMatchSubject.ts
  26. 83
      packages/react/src/methods/change/useChangeSubject.ts
  27. 17
      packages/react/src/methods/useDataset.ts
  28. 17
      packages/react/src/methods/useMatchObject.ts
  29. 17
      packages/react/src/methods/useMatchSubject.ts
  30. 24
      packages/react/src/methods/useSubject.ts
  31. 32
      packages/react/test/.ldo/post.context.ts
  32. 155
      packages/react/test/.ldo/post.schema.ts
  33. 19
      packages/react/test/.ldo/post.shapeTypes.ts
  34. 45
      packages/react/test/.ldo/post.typings.ts
  35. 459
      packages/react/test/.ldo/solidProfile.context.ts
  36. 749
      packages/react/test/.ldo/solidProfile.schema.ts
  37. 64
      packages/react/test/.ldo/solidProfile.shapeTypes.ts
  38. 293
      packages/react/test/.ldo/solidProfile.typings.ts
  39. 17
      packages/react/test/mockLdoMethods.ts
  40. 7
      packages/react/test/trivial.test.ts
  41. 242
      packages/react/test/useLdoForm.test.tsx
  42. 3
      packages/react/vitest.config.js
  43. 4
      packages/schema-converter-shex/package.json
  44. 8
      packages/solid-react/package.json
  45. 5
      packages/solid-react/src/defaultIntance.ts
  46. 6
      packages/solid-type-index/package.json
  47. 2
      packages/subscribable-dataset/package.json
  48. 4
      packages/subscribable-dataset/src/SubscribableDataset.ts
  49. 14
      packages/subscribable-dataset/src/TransactionDataset.ts
  50. 10
      packages/svelte/package.json

@ -1,6 +1,10 @@
{
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "prettier", "react"],
"plugins": [
"@typescript-eslint",
"prettier",
"react"
],
"extends": [
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
@ -10,7 +14,9 @@
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"ecmaFeatures": { "jsx": true }
"ecmaFeatures": {
"jsx": true
}
},
"settings": {
"react": {

@ -0,0 +1,4 @@
{
"typescript.preferences.importModuleSpecifierEnding": "js",
"javascript.preferences.importModuleSpecifierEnding": "js"
}

@ -1,4 +1,4 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"version": "1.0.0-alpha.30"
"version": "1.0.0-alpha.31"
}

1525
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
{
"name": "@ldo/cli",
"version": "1.0.0-alpha.30",
"version": "1.0.0-alpha.31",
"description": "A Command Line Interface for Linked Data Objects",
"main": "./dist/index.js",
"type": "module",
@ -41,8 +41,8 @@
},
"dependencies": {
"@jeswr/shacl2shex": "^1.1.0",
"@ldo/ldo": "^1.0.0-alpha.30",
"@ldo/schema-converter-shex": "^1.0.0-alpha.30",
"@ldo/ldo": "^1.0.0-alpha.31",
"@ldo/schema-converter-shex": "^1.0.0-alpha.31",
"@shexjs/parser": "^1.0.0-alpha.24",
"child-process-promise": "^2.2.1",
"commander": "^9.3.0",

@ -1,6 +1,6 @@
{
"name": "@ldo/connected-nextgraph",
"version": "1.0.0-alpha.30",
"version": "1.0.0-alpha.31",
"description": "A plugin for @ldo/connected to work with the Solid ecosystem.",
"type": "module",
"main": "./dist/cjs/index.cjs",
@ -39,7 +39,7 @@
"homepage": "https://github.com/o-development/ldo/tree/main/packages/solid#readme",
"devDependencies": {
"@inrupt/solid-client-authn-core": "^3.0.0",
"@ldo/cli": "^1.0.0-alpha.30",
"@ldo/cli": "^1.0.0-alpha.31",
"@rdfjs/types": "^1.0.1",
"@solid-notifications/types": "^0.1.2",
"@solid/community-server": "8.0.0-alpha.0",
@ -54,9 +54,9 @@
"typedoc-plugin-markdown": "^3.17.1"
},
"dependencies": {
"@ldo/connected": "^1.0.0-alpha.30",
"@ldo/connected": "^1.0.0-alpha.31",
"@ldo/dataset": "^1.0.0-alpha.30",
"@ldo/ldo": "^1.0.0-alpha.30",
"@ldo/ldo": "^1.0.0-alpha.31",
"@ldo/rdf-utils": "^1.0.0-alpha.30",
"@solid-notifications/subscription": "^0.1.2",
"cross-fetch": "^3.1.6",

@ -1,6 +1,6 @@
{
"name": "@ldo/connected-solid",
"version": "1.0.0-alpha.30",
"version": "1.0.0-alpha.31",
"description": "A plugin for @ldo/connected to work with the Solid ecosystem.",
"type": "module",
"main": "./dist/cjs/index.cjs",
@ -37,7 +37,7 @@
"homepage": "https://github.com/o-development/ldo/tree/main/packages/solid#readme",
"devDependencies": {
"@inrupt/solid-client-authn-core": "^3.0.0",
"@ldo/cli": "^1.0.0-alpha.30",
"@ldo/cli": "^1.0.0-alpha.31",
"@ldo/test-solid-server": "^1.0.0-alpha.28",
"@rdfjs/types": "^1.0.1",
"@solid-notifications/types": "^0.1.2",
@ -49,9 +49,9 @@
"typedoc-plugin-markdown": "^3.17.1"
},
"dependencies": {
"@ldo/connected": "^1.0.0-alpha.30",
"@ldo/connected": "^1.0.0-alpha.31",
"@ldo/dataset": "^1.0.0-alpha.30",
"@ldo/ldo": "^1.0.0-alpha.30",
"@ldo/ldo": "^1.0.0-alpha.31",
"@ldo/rdf-utils": "^1.0.0-alpha.30",
"@solid-notifications/subscription": "^0.1.2",
"cross-fetch": "^3.1.6",

@ -1,6 +1,6 @@
{
"name": "@ldo/connected",
"version": "1.0.0-alpha.30",
"version": "1.0.0-alpha.31",
"description": "A library for connecting LDO to resources outside the LDO environment",
"type": "module",
"main": "./dist/cjs/index.cjs",
@ -50,7 +50,7 @@
},
"dependencies": {
"@ldo/dataset": "^1.0.0-alpha.30",
"@ldo/ldo": "^1.0.0-alpha.30",
"@ldo/ldo": "^1.0.0-alpha.31",
"@ldo/rdf-utils": "^1.0.0-alpha.30"
},
"files": [

@ -65,6 +65,8 @@ export class ConnectedLdoTransactionDataset<Plugins extends ConnectedPlugin[]>
extends LdoTransactionDataset
implements IConnectedLdoDataset<Plugins>
{
public instanceId: number;
static nextId = 0;
/**
* @internal
*/
@ -91,6 +93,7 @@ export class ConnectedLdoTransactionDataset<Plugins extends ConnectedPlugin[]>
) {
super(parentDataset, datasetFactory, transactionDatasetFactory);
this.context = context;
this.instanceId = ConnectedLdoTransactionDataset.nextId++;
}
getResource<
@ -221,6 +224,7 @@ export class ConnectedLdoTransactionDataset<Plugins extends ConnectedPlugin[]>
);
// If one has errored, return error
console.log(results);
const errors = (
results.map((result) => result[2]) as (SuccessResult | ErrorResult)[]
).filter((result): result is ErrorResult => result.isError);

@ -19,7 +19,7 @@ export function createTrackingSubjectProxy(
): SubjectProxy {
const baseHandler = createSubjectHandler(proxyContext);
const oldGetFunction = baseHandler.get;
const newGetFunction: ProxyHandler<SubjectProxyTarget>["get"] = (
const trackingProxyGetFunction: ProxyHandler<SubjectProxyTarget>["get"] = (
target: SubjectProxyTarget,
key: string | symbol,
receiver,
@ -38,7 +38,7 @@ export function createTrackingSubjectProxy(
}
return oldGetFunction && oldGetFunction(target, key, receiver);
};
baseHandler.get = newGetFunction;
baseHandler.get = trackingProxyGetFunction;
baseHandler.set = () => {
console.warn(
"You've attempted to set a value on a Linked Data Object from the useSubject, useMatchingSubject, or useMatchingObject hooks. These linked data objects should only be used to render data, not modify it. To modify data, use the `changeData` function.",

@ -0,0 +1,13 @@
import { ConnectedLdoDataset } from "@ldo/connected";
import { createDatasetFactory } from "@ldo/dataset";
import { createTransactionDatasetFactory } from "@ldo/subscribable-dataset";
import { mockConnectedPlugin } from "./MockConnectedPlugin.js";
export function createMockConnectedLdoDataset() {
const nextGraphLdoDataset = new ConnectedLdoDataset(
[mockConnectedPlugin],
createDatasetFactory(),
createTransactionDatasetFactory(),
);
return nextGraphLdoDataset;
}

@ -0,0 +1,45 @@
import type { ConnectedContext, ConnectedPlugin } from "@ldo/connected";
import { MockResource } from "./MockResource.js";
import { v4 } from "uuid";
/**
* The Type of the SolidConnectedContext
*/
export interface MockConnectedContext {}
export interface MockConnectedPlugin
extends ConnectedPlugin<
"mock",
string,
MockResource,
MockConnectedContext,
undefined
> {
name: "mock";
getResource: (uri: string, context: ConnectedContext<this[]>) => MockResource;
createResource(context: ConnectedContext<this[]>): Promise<MockResource>;
}
export const mockConnectedPlugin: MockConnectedPlugin = {
name: "mock",
getResource: function (
uri: string,
context: ConnectedContext<MockConnectedPlugin[]>,
): MockResource {
return new MockResource(uri, context);
},
createResource: async function (context): Promise<MockResource> {
return new MockResource(v4(), context);
},
isUriValid: function (uri: string): uri is string {
return typeof uri === "string";
},
initialContext: {},
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore "Types" only exists for the typing system
types: {},
};

@ -1,5 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import EventEmitter from "events";
import type { ConnectedContext } from "../../src/index.js";
import {
Unfetched,
type ConnectedResult,
@ -9,8 +10,10 @@ import {
} from "../../src/index.js";
import type { DatasetChanges } from "@ldo/rdf-utils";
import type { ReadSuccess } from "../../src/results/success/ReadSuccess.js";
import type { UpdateSuccess } from "../../src/results/success/UpdateSuccess.js";
import { UpdateSuccess } from "../../src/results/success/UpdateSuccess.js";
import { vi } from "vitest";
import type { MockConnectedPlugin } from "./MockConnectedPlugin.js";
import type { Quad } from "@rdfjs/types";
export class MockResource
extends (EventEmitter as new () => ResourceEventEmitter)
@ -21,10 +24,13 @@ export class MockResource
type = "mock" as const;
status: ConnectedResult;
constructor(uri: string) {
protected context: ConnectedContext<MockConnectedPlugin[]>;
constructor(uri: string, context: ConnectedContext<MockConnectedPlugin[]>) {
super();
this.uri = uri;
this.status = new Unfetched(this);
this.context = context;
}
isLoading = vi.fn<() => boolean>();
@ -38,12 +44,14 @@ export class MockResource
read = vi.fn<() => Promise<ReadSuccess<any> | ResourceError<any>>>();
readIfUnfetched =
vi.fn<() => Promise<ReadSuccess<any> | ResourceError<any>>>();
update =
vi.fn<
(
changes: DatasetChanges,
) => Promise<UpdateSuccess<any> | ResourceError<any>>
>();
update = vi.fn<
(
changes: DatasetChanges<Quad>,
) => Promise<UpdateSuccess<any> | ResourceError<any>>
>((changes) => {
this.context.dataset.bulk(changes);
return new UpdateSuccess(this);
});
subscribeToNotifications =
vi.fn<

@ -1,6 +1,6 @@
{
"name": "@ldo/jsonld-dataset-proxy",
"version": "1.0.0-alpha.30",
"version": "1.0.0-alpha.31",
"description": "",
"type": "module",
"main": "./dist/cjs/index.cjs",
@ -51,7 +51,7 @@
],
"dependencies": {
"@ldo/rdf-utils": "^1.0.0-alpha.30",
"@ldo/subscribable-dataset": "^1.0.0-alpha.30",
"@ldo/subscribable-dataset": "^1.0.0-alpha.31",
"jsonld2graphobject": "^0.0.4"
},
"publishConfig": {

@ -1,6 +1,6 @@
import type { LanguageOrdering } from "./language/languageTypes.js";
import type { InteractOptions } from "./util/createInteractOptions.js";
import { createInteractOptions } from "./util/createInteractOptions.js";
import { createProxyInteractOptions } from "./util/createInteractOptions.js";
/**
* Set the default language pr
@ -10,5 +10,5 @@ import { createInteractOptions } from "./util/createInteractOptions.js";
export function setLanguagePreferences(
...languageOrdering: LanguageOrdering
): InteractOptions {
return createInteractOptions("languageOrdering", languageOrdering);
return createProxyInteractOptions("languageOrdering", languageOrdering);
}

@ -19,7 +19,7 @@ export interface InteractOptions {
usingCopy<T extends ObjectLike>(...objects: T[]): T[];
}
export function createInteractOptions(
export function createProxyInteractOptions(
paramKey: string,
parameter: unknown,
): InteractOptions {

@ -1,6 +1,6 @@
import type { GraphNode } from "@ldo/rdf-utils";
import type { InteractOptions } from "./util/createInteractOptions.js";
import { createInteractOptions } from "./util/createInteractOptions.js";
import { createProxyInteractOptions } from "./util/createInteractOptions.js";
/**
* Set the graphs that should be written to
@ -8,5 +8,5 @@ import { createInteractOptions } from "./util/createInteractOptions.js";
* @returns a write builder
*/
export function write(...graphs: GraphNode[]): InteractOptions {
return createInteractOptions("writeGraphs", graphs);
return createProxyInteractOptions("writeGraphs", graphs);
}

@ -1,6 +1,6 @@
{
"name": "@ldo/ldo",
"version": "1.0.0-alpha.30",
"version": "1.0.0-alpha.31",
"description": "",
"type": "module",
"main": "./dist/cjs/index.cjs",
@ -48,8 +48,8 @@
},
"dependencies": {
"@ldo/dataset": "^1.0.0-alpha.30",
"@ldo/jsonld-dataset-proxy": "^1.0.0-alpha.30",
"@ldo/subscribable-dataset": "^1.0.0-alpha.30",
"@ldo/jsonld-dataset-proxy": "^1.0.0-alpha.31",
"@ldo/subscribable-dataset": "^1.0.0-alpha.31",
"buffer": "^6.0.3",
"readable-stream": "^4.3.0"
},

@ -1,6 +1,6 @@
{
"name": "@ldo/react",
"version": "1.0.0-alpha.30",
"version": "1.0.0-alpha.31",
"description": "A React library for LDO.",
"type": "module",
"main": "./dist/cjs/index.cjs",
@ -36,16 +36,18 @@
"homepage": "https://github.com/o-development/ldo/tree/main/packages/solid-react#readme",
"devDependencies": {
"@rdfjs/types": "^1.0.1",
"@testing-library/react": "^14.1.2",
"start-server-and-test": "^2.0.3",
"ts-node": "^10.9.2"
"@testing-library/jest-dom": "^6.7.0",
"@testing-library/react": "^14.3.1",
"@testing-library/user-event": "^14.6.1",
"jsdom": "^26.1.0",
"vitest": "^3.2.4"
},
"dependencies": {
"@ldo/connected": "^1.0.0-alpha.30",
"@ldo/jsonld-dataset-proxy": "^1.0.0-alpha.30",
"@ldo/ldo": "^1.0.0-alpha.30",
"@ldo/connected": "^1.0.0-alpha.31",
"@ldo/jsonld-dataset-proxy": "^1.0.0-alpha.31",
"@ldo/ldo": "^1.0.0-alpha.31",
"@ldo/rdf-utils": "^1.0.0-alpha.30",
"@ldo/subscribable-dataset": "^1.0.0-alpha.30",
"@ldo/subscribable-dataset": "^1.0.0-alpha.31",
"cross-fetch": "^3.1.6"
},
"files": [

@ -10,6 +10,11 @@ import { createUseResource } from "./methods/useResource.js";
import { createUseSubject } from "./methods/useSubject.js";
import { createUseSubscribeToResource } from "./methods/useSubscribeToResource.js";
import { createUseLinkQuery } from "./methods/useLinkQuery.js";
import { createUseDataset } from "./methods/useDataset.js";
import { createUseChangeDataset } from "./methods/change/useChangeDataset.js";
import { createUseChangeSubject } from "./methods/change/useChangeSubject.js";
import { createUseChangeMatchObject } from "./methods/change/useChangeMatchObject.js";
import { createUseChangeMatchSubject } from "./methods/change/useChangeMatchSubject.js";
/**
* A function that creates all common react functions given specific plugin.
@ -23,14 +28,18 @@ import { createUseLinkQuery } from "./methods/useLinkQuery.js";
*
* // Export the results to be used in the reset of the application
* export const {
* dataset,
* useLdo,
* useMatchObject,
* useMatchSubject,
* useResource,
* useSubject,
* useSubscribeToResource,
* useLinkQuery,
* dataset,
* useLdo,
* useMatchObject,
* useMatchSubject,
* useResource,
* useSubject,
* useSubscribeToResource,
* useLinkQuery,
* useChangeDataset,
* useChangeSubject,
* useChangeMatchObject,
* useChangeMatchSubject,
* } = createLdoReactMethods([
* solidConnectedPlugin,
* nextGraphConnectedPlugin
@ -66,6 +75,7 @@ export function createLdoReactMethods<
return {
dataset,
useDataset: createUseDataset(dataset),
useLdo: createUseLdo(dataset),
useMatchObject: createUseMatchObject(dataset),
useMatchSubject: createUseMatchSubject(dataset),
@ -73,5 +83,9 @@ export function createLdoReactMethods<
useSubject: createUseSubject(dataset),
useSubscribeToResource: createUseSubscribeToResource(dataset),
useLinkQuery: createUseLinkQuery(dataset),
useChangeDataset: createUseChangeDataset(dataset),
useChangeSubject: createUseChangeSubject(dataset),
useChangeMatchObject: createUseChangeMatchObject(dataset),
useChangeMatchSubject: createUseChangeMatchSubject(dataset),
};
}

@ -7,5 +7,10 @@ export * from "./methods/useResource.js";
export * from "./methods/useSubject.js";
export * from "./methods/useSubscribeToResource.js";
export * from "./methods/useLinkQuery.js";
export * from "./methods/change/types.js";
export * from "./methods/change/useChangeDataset.js";
export * from "./methods/change/useChangeMatchObject.js";
export * from "./methods/change/useChangeMatchSubject.js";
export * from "./methods/change/useChangeSubject.js";
export * from "./util/useTrackingProxy.js";

@ -0,0 +1,24 @@
import type {
ConnectedLdoTransactionDataset,
ConnectedPlugin,
} from "@ldo/connected";
import type { LdoBase, LdSet } from "@ldo/ldo";
export type useChangeReturn<Type, Plugins extends ConnectedPlugin[]> = [
Type,
useChangeSetData<Type, Plugins>,
useChangeCommitData<Plugins>,
];
type BaseOtherType = LdoBase | LdSet<LdoBase>;
export type useChangeSetData<Type, Plugins extends ConnectedPlugin[]> = <
OtherType extends BaseOtherType | undefined = undefined,
>(
resource: Plugins[number]["types"]["resource"],
changer: (toChange: OtherType extends undefined ? Type : OtherType) => void,
input?: OtherType,
) => void;
export type useChangeCommitData<Plugins extends ConnectedPlugin[]> =
() => ReturnType<ConnectedLdoTransactionDataset<Plugins>["commitToRemote"]>;

@ -0,0 +1,58 @@
import { useCallback, useMemo } from "react";
import type {
ConnectedLdoDataset,
ConnectedLdoTransactionDataset,
ConnectedPlugin,
IConnectedLdoDataset,
} from "@ldo/connected";
import type { useChangeCommitData } from "./types.js";
export type useChangeDatasetReturn<Plugins extends ConnectedPlugin[]> = [
ConnectedLdoTransactionDataset<Plugins>,
useChangeSetDataset<Plugins>,
useChangeCommitData<Plugins>,
];
export type useChangeSetDataset<Plugins extends ConnectedPlugin[]> = (
changer: (toChange: ConnectedLdoTransactionDataset<Plugins>) => void,
) => void;
/**
* @internal
*
* Creates a useChangeDataset function
*/
export function createUseChangeDataset<Plugins extends ConnectedPlugin[]>(
dataset: ConnectedLdoDataset<Plugins>,
) {
/**
* Returns a transaction on the dataset that can be modified and committed
*/
return function useChangeDataset(
specificDataset?: IConnectedLdoDataset<Plugins>,
): useChangeDatasetReturn<Plugins> {
const transactionDataset = useMemo(() => {
return (
specificDataset ?? dataset
).startTransaction() as ConnectedLdoTransactionDataset<Plugins>;
}, [specificDataset]);
const setData = useCallback<useChangeSetDataset<Plugins>>(
(changer) => {
const subTransaction = transactionDataset.startTransaction();
changer(subTransaction);
subTransaction.commit();
},
[transactionDataset],
);
const commitData = useCallback<useChangeCommitData<Plugins>>(() => {
return transactionDataset.commitToRemote();
}, [transactionDataset]);
return useMemo(
() => [transactionDataset, setData, commitData],
[transactionDataset, setData, commitData],
);
};
}

@ -0,0 +1,66 @@
import { useCallback, useMemo } from "react";
import type { ConnectedLdoDataset, ConnectedPlugin } from "@ldo/connected";
import { createUseChangeDataset } from "./useChangeDataset.js";
import { write, type LdoBase, type LdSet, type ShapeType } from "@ldo/ldo";
import type { QuadMatch } from "@ldo/rdf-utils";
import type { UseMatchObjectOptions } from "../useMatchObject.js";
import { createUseMatchObject } from "../useMatchObject.js";
import type { useChangeReturn, useChangeSetData } from "./types.js";
import { createProxyInteractOptions } from "@ldo/jsonld-dataset-proxy";
/**
* @internal
*
* Creates a useChangeMatchObject function
*/
export function createUseChangeMatchObject<Plugins extends ConnectedPlugin[]>(
dataset: ConnectedLdoDataset<Plugins>,
) {
const useChangeDataset = createUseChangeDataset(dataset);
const useMatchObject = createUseMatchObject(dataset);
/**
* Returns a list of matched objects that can be modified and committed
*/
return function useChangeMatchObject<Type extends LdoBase>(
shapeType: ShapeType<Type>,
subject?: QuadMatch[0] | string,
predicate?: QuadMatch[1] | string,
graph?: QuadMatch[3] | string,
options?: UseMatchObjectOptions<Plugins>,
): useChangeReturn<LdSet<Type>, Plugins> {
const [transactionDataset, setDataset, commitData] = useChangeDataset(
options?.dataset,
);
const ldObject = useMatchObject(shapeType, subject, predicate, graph, {
dataset: transactionDataset,
});
const setData = useCallback<useChangeSetData<Type, Plugins>>(
(writeResource, changer, otherType?) => {
setDataset((dataset) => {
const ldObject = otherType
? write(writeResource.uri).usingCopy(
createProxyInteractOptions("dataset", dataset).usingCopy(
otherType,
)[0],
)[0]
: dataset
.usingType(shapeType)
.write(writeResource.uri)
.matchObject(subject, predicate, graph);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
changer(ldObject);
});
},
[setDataset, subject, predicate, graph, shapeType],
);
return useMemo(
() => [ldObject, setData, commitData],
[ldObject, setData, commitData],
);
};
}

@ -0,0 +1,68 @@
import { useCallback, useMemo } from "react";
import type { ConnectedLdoDataset, ConnectedPlugin } from "@ldo/connected";
import { createUseChangeDataset } from "./useChangeDataset.js";
import { write, type LdoBase, type LdSet, type ShapeType } from "@ldo/ldo";
import type { QuadMatch } from "@ldo/rdf-utils";
import type { useChangeReturn, useChangeSetData } from "./types.js";
import {
createUseMatchSubject,
type UseMatchSubjectOptions,
} from "../useMatchSubject.js";
import { createProxyInteractOptions } from "@ldo/jsonld-dataset-proxy";
/**
* @internal
*
* Creates a useChangeMatchSubject function
*/
export function createUseChangeMatchSubject<Plugins extends ConnectedPlugin[]>(
dataset: ConnectedLdoDataset<Plugins>,
) {
const useChangeDataset = createUseChangeDataset(dataset);
const useMatchSubject = createUseMatchSubject(dataset);
/**
* Returns a list of matched subjects that can be modified and committed
*/
return function useChangeMatchSubject<Type extends LdoBase>(
shapeType: ShapeType<Type>,
predicate?: QuadMatch[1] | string,
object?: QuadMatch[2] | string,
graph?: QuadMatch[3] | string,
options?: UseMatchSubjectOptions<Plugins>,
): useChangeReturn<LdSet<Type>, Plugins> {
const [transactionDataset, setDataset, commitData] = useChangeDataset(
options?.dataset,
);
const ldObject = useMatchSubject(shapeType, predicate, object, graph, {
dataset: transactionDataset,
});
const setData = useCallback<useChangeSetData<Type, Plugins>>(
(writeResource, changer, otherType?) => {
setDataset((dataset) => {
const ldObject = otherType
? write(writeResource.uri).usingCopy(
createProxyInteractOptions("dataset", dataset).usingCopy(
otherType,
)[0],
)[0]
: dataset
.usingType(shapeType)
.write(writeResource.uri)
.matchSubject(predicate, object, graph);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
changer(ldObject);
});
},
[setDataset, predicate, object, graph, shapeType],
);
return useMemo(
() => [ldObject, setData, commitData],
[ldObject, setData, commitData],
);
};
}

@ -0,0 +1,83 @@
import { useCallback, useMemo } from "react";
import type { ConnectedLdoDataset, ConnectedPlugin } from "@ldo/connected";
import { createUseChangeDataset } from "./useChangeDataset.js";
import type { UseSubjectOptions } from "../useSubject.js";
import { createUseSubject } from "../useSubject.js";
import { write, type LdoBase, type ShapeType } from "@ldo/ldo";
import type { SubjectNode } from "@ldo/rdf-utils";
import type { useChangeReturn, useChangeSetData } from "./types.js";
import { createProxyInteractOptions } from "@ldo/jsonld-dataset-proxy";
export type useChangeSubjectType<Plugins extends ConnectedPlugin[]> = {
<Type extends LdoBase>(
shapeType: ShapeType<Type>,
subject: string | SubjectNode,
options?: UseSubjectOptions<Plugins>,
): useChangeReturn<Type, Plugins>;
<Type extends LdoBase>(
shapeType: ShapeType<Type>,
subject?: string | SubjectNode,
options?: UseSubjectOptions<Plugins>,
): useChangeReturn<Type | undefined, Plugins>;
<Type extends LdoBase>(
shapeType: ShapeType<Type>,
subject?: string | SubjectNode,
options?: UseSubjectOptions<Plugins>,
): useChangeReturn<Type | undefined, Plugins>;
};
/**
* @internal
*
* Creates a useChangeSubject function
*/
export function createUseChangeSubject<Plugins extends ConnectedPlugin[]>(
dataset: ConnectedLdoDataset<Plugins>,
): useChangeSubjectType<Plugins> {
const useChangeDataset = createUseChangeDataset(dataset);
const useSubject = createUseSubject(dataset);
/**
* Returns a subject that can be modified and committed
*/
return function useChangeSubject<Type extends LdoBase>(
shapeType: ShapeType<Type>,
subject?: string | SubjectNode,
options?: UseSubjectOptions<Plugins>,
): useChangeReturn<Type | undefined, Plugins> {
const [transactionDataset, setDataset, commitData] = useChangeDataset(
options?.dataset,
);
const ldObject = useSubject(shapeType, subject, {
dataset: transactionDataset,
});
const setData = useCallback<useChangeSetData<Type, Plugins>>(
(writeResource, changer, otherType?) => {
if (!subject) return;
setDataset((dataset) => {
const ldObject = otherType
? write(writeResource.uri).usingCopy(
createProxyInteractOptions("dataset", dataset).usingCopy(
otherType,
)[0],
)[0]
: dataset
.usingType(shapeType)
.write(writeResource.uri)
.fromSubject(subject);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
changer(ldObject);
});
},
[setDataset, subject, shapeType],
);
return useMemo(
() => [ldObject, setData, commitData],
[ldObject, setData, commitData],
);
};
}

@ -0,0 +1,17 @@
import { ConnectedLdoDataset, ConnectedPlugin } from "@ldo/connected";
/**
* @internal
*
* Creates a useDataset function
*/
export function createUseDataset<Plugins extends ConnectedPlugin[]>(
dataset: ConnectedLdoDataset<Plugins>,
) {
/**
* Returns the global dataset for the application
*/
return function useDataset() {
return dataset;
}
}

@ -3,7 +3,15 @@ import type { QuadMatch } from "@ldo/rdf-utils";
import type { LdoBuilder } from "@ldo/ldo";
import { useCallback } from "react";
import { useTrackingProxy } from "../util/useTrackingProxy.js";
import type { ConnectedLdoDataset, ConnectedPlugin } from "@ldo/connected";
import type {
ConnectedLdoDataset,
ConnectedPlugin,
IConnectedLdoDataset,
} from "@ldo/connected";
export interface UseMatchObjectOptions<Plugins extends ConnectedPlugin[]> {
dataset?: IConnectedLdoDataset<Plugins>;
}
/**
* @internal
@ -22,6 +30,7 @@ export function createUseMatchObject<Plugins extends ConnectedPlugin[]>(
subject?: QuadMatch[0] | string,
predicate?: QuadMatch[1] | string,
graph?: QuadMatch[3] | string,
options?: UseMatchObjectOptions<Plugins>,
): LdSet<Type> {
const matchObject = useCallback(
(builder: LdoBuilder<Type>) => {
@ -30,6 +39,10 @@ export function createUseMatchObject<Plugins extends ConnectedPlugin[]>(
[subject, predicate, graph],
);
return useTrackingProxy(shapeType, matchObject, dataset);
return useTrackingProxy(
shapeType,
matchObject,
options?.dataset ?? dataset,
);
};
}

@ -3,7 +3,15 @@ import type { QuadMatch } from "@ldo/rdf-utils";
import type { LdoBuilder } from "@ldo/ldo";
import { useCallback } from "react";
import { useTrackingProxy } from "../util/useTrackingProxy.js";
import type { ConnectedLdoDataset, ConnectedPlugin } from "@ldo/connected";
import type {
ConnectedLdoDataset,
ConnectedPlugin,
IConnectedLdoDataset,
} from "@ldo/connected";
export interface UseMatchSubjectOptions<Plugins extends ConnectedPlugin[]> {
dataset?: IConnectedLdoDataset<Plugins>;
}
/**
* @internal
@ -22,6 +30,7 @@ export function createUseMatchSubject<Plugins extends ConnectedPlugin[]>(
predicate?: QuadMatch[1] | string,
object?: QuadMatch[2] | string,
graph?: QuadMatch[3] | string,
options?: UseMatchSubjectOptions<Plugins>,
): LdSet<Type> {
const matchSubject = useCallback(
(builder: LdoBuilder<Type>) => {
@ -30,6 +39,10 @@ export function createUseMatchSubject<Plugins extends ConnectedPlugin[]>(
[predicate, object, graph],
);
return useTrackingProxy(shapeType, matchSubject, dataset);
return useTrackingProxy(
shapeType,
matchSubject,
options?.dataset ?? dataset,
);
};
}

@ -5,20 +5,31 @@ import type { LdoBase } from "@ldo/ldo";
import { useCallback } from "react";
import { useTrackingProxy } from "../util/useTrackingProxy.js";
import type { ConnectedLdoDataset, ConnectedPlugin } from "@ldo/connected";
import type {
ConnectedLdoDataset,
ConnectedPlugin,
IConnectedLdoDataset,
} from "@ldo/connected";
export type useSubjectType = {
export interface UseSubjectOptions<Plugins extends ConnectedPlugin[]> {
dataset?: IConnectedLdoDataset<Plugins>;
}
export type useSubjectType<Plugins extends ConnectedPlugin[]> = {
<Type extends LdoBase>(
shapeType: ShapeType<Type>,
subject: string | SubjectNode,
options?: UseSubjectOptions<Plugins>,
): Type;
<Type extends LdoBase>(
shapeType: ShapeType<Type>,
subject?: string | SubjectNode,
options?: UseSubjectOptions<Plugins>,
): Type | undefined;
<Type extends LdoBase>(
shapeType: ShapeType<Type>,
subject?: string | SubjectNode,
options?: UseSubjectOptions<Plugins>,
): Type | undefined;
};
@ -29,7 +40,7 @@ export type useSubjectType = {
*/
export function createUseSubject<Plugins extends ConnectedPlugin[]>(
dataset: ConnectedLdoDataset<Plugins>,
): useSubjectType {
): useSubjectType<Plugins> {
/**
* Returns a Linked Data Object based on the provided subject. Triggers a
* rerender if the data is udpated.
@ -37,6 +48,7 @@ export function createUseSubject<Plugins extends ConnectedPlugin[]>(
return function useSubject<Type extends LdoBase>(
shapeType: ShapeType<Type>,
subject?: string | SubjectNode,
options?: UseSubjectOptions<Plugins>,
): Type | undefined {
const fromSubject = useCallback(
(builder: LdoBuilder<Type>) => {
@ -46,6 +58,10 @@ export function createUseSubject<Plugins extends ConnectedPlugin[]>(
[subject],
);
return useTrackingProxy(shapeType, fromSubject, dataset);
return useTrackingProxy(
shapeType,
fromSubject,
options?.dataset ?? dataset,
);
};
}

@ -0,0 +1,32 @@
import { ContextDefinition } from "jsonld";
/**
* =============================================================================
* postContext: JSONLD Context for post
* =============================================================================
*/
export const postContext: ContextDefinition = {
type: {
"@id": "@type",
},
SocialMediaPosting: "http://schema.org/SocialMediaPosting",
CreativeWork: "http://schema.org/CreativeWork",
Thing: "http://schema.org/Thing",
articleBody: {
"@id": "http://schema.org/articleBody",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
uploadDate: {
"@id": "http://schema.org/uploadDate",
"@type": "http://www.w3.org/2001/XMLSchema#date",
},
image: {
"@id": "http://schema.org/image",
"@type": "@id",
},
publisher: {
"@id": "http://schema.org/publisher",
"@type": "@id",
"@container": "@set",
},
};

@ -0,0 +1,155 @@
import { Schema } from "shexj";
/**
* =============================================================================
* postSchema: ShexJ Schema for post
* =============================================================================
*/
export const postSchema: Schema = {
type: "Schema",
shapes: [
{
id: "https://example.com/PostSh",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
type: "EachOf",
expressions: [
{
type: "TripleConstraint",
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
valueExpr: {
type: "NodeConstraint",
values: [
"http://schema.org/SocialMediaPosting",
"http://schema.org/CreativeWork",
"http://schema.org/Thing",
],
},
},
{
type: "TripleConstraint",
predicate: "http://schema.org/articleBody",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#label",
object: {
value: "articleBody",
},
},
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The actual body of the article. ",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://schema.org/uploadDate",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#date",
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#label",
object: {
value: "uploadDate",
},
},
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"Date when this media object was uploaded to this site.",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://schema.org/image",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#label",
object: {
value: "image",
},
},
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"A media object that encodes this CreativeWork. This property is a synonym for encoding.",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://schema.org/publisher",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#label",
object: {
value: "publisher",
},
},
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The publisher of the creative work.",
},
},
],
},
],
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#label",
object: {
value: "SocialMediaPost",
},
},
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"A post to a social media platform, including blog posts, tweets, Facebook posts, etc.",
},
},
],
},
},
],
};

@ -0,0 +1,19 @@
import { ShapeType } from "@ldo/ldo";
import { postSchema } from "./post.schema.js";
import { postContext } from "./post.context.js";
import { PostSh } from "./post.typings.js";
/**
* =============================================================================
* LDO ShapeTypes post
* =============================================================================
*/
/**
* PostSh ShapeType
*/
export const PostShShapeType: ShapeType<PostSh> = {
schema: postSchema,
shape: "https://example.com/PostSh",
context: postContext,
};

@ -0,0 +1,45 @@
import { LdSet, LdoJsonldContext } from "@ldo/ldo";
/**
* =============================================================================
* Typescript Typings for post
* =============================================================================
*/
/**
* PostSh Type
*/
export interface PostSh {
"@id"?: string;
"@context"?: LdoJsonldContext;
type:
| {
"@id": "SocialMediaPosting";
}
| {
"@id": "CreativeWork";
}
| {
"@id": "Thing";
};
/**
* The actual body of the article.
*/
articleBody?: string;
/**
* Date when this media object was uploaded to this site.
*/
uploadDate: string;
/**
* A media object that encodes this CreativeWork. This property is a synonym for encoding.
*/
image?: {
"@id": string;
};
/**
* The publisher of the creative work.
*/
publisher: LdSet<{
"@id": string;
}>;
}

@ -0,0 +1,459 @@
import { LdoJsonldContext } from "@ldo/ldo";
/**
* =============================================================================
* solidProfileContext: JSONLD Context for solidProfile
* =============================================================================
*/
export const solidProfileContext: LdoJsonldContext = {
type: {
"@id": "@type",
},
Person: {
"@id": "http://schema.org/Person",
"@context": {
type: {
"@id": "@type",
},
fn: {
"@id": "http://www.w3.org/2006/vcard/ns#fn",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
name: {
"@id": "http://xmlns.com/foaf/0.1/name",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasAddress: {
"@id": "http://www.w3.org/2006/vcard/ns#hasAddress",
"@type": "@id",
"@isCollection": true,
},
hasEmail: {
"@id": "http://www.w3.org/2006/vcard/ns#hasEmail",
"@type": "@id",
"@isCollection": true,
},
hasPhoto: {
"@id": "http://www.w3.org/2006/vcard/ns#hasPhoto",
"@type": "@id",
},
img: {
"@id": "http://xmlns.com/foaf/0.1/img",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasTelephone: {
"@id": "http://www.w3.org/2006/vcard/ns#hasTelephone",
"@type": "@id",
"@isCollection": true,
},
phone: {
"@id": "http://www.w3.org/2006/vcard/ns#phone",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
organizationName: {
"@id": "http://www.w3.org/2006/vcard/ns#organization-name",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
role: {
"@id": "http://www.w3.org/2006/vcard/ns#role",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
trustedApp: {
"@id": "http://www.w3.org/ns/auth/acl#trustedApp",
"@type": "@id",
"@isCollection": true,
},
key: {
"@id": "http://www.w3.org/ns/auth/cert#key",
"@type": "@id",
"@isCollection": true,
},
inbox: {
"@id": "http://www.w3.org/ns/ldp#inbox",
"@type": "@id",
},
preferencesFile: {
"@id": "http://www.w3.org/ns/pim/space#preferencesFile",
"@type": "@id",
},
storage: {
"@id": "http://www.w3.org/ns/pim/space#storage",
"@type": "@id",
"@isCollection": true,
},
account: {
"@id": "http://www.w3.org/ns/solid/terms#account",
"@type": "@id",
},
privateTypeIndex: {
"@id": "http://www.w3.org/ns/solid/terms#privateTypeIndex",
"@type": "@id",
"@isCollection": true,
},
publicTypeIndex: {
"@id": "http://www.w3.org/ns/solid/terms#publicTypeIndex",
"@type": "@id",
"@isCollection": true,
},
knows: {
"@id": "http://xmlns.com/foaf/0.1/knows",
"@type": "@id",
"@isCollection": true,
},
},
},
Person2: {
"@id": "http://xmlns.com/foaf/0.1/Person",
"@context": {
type: {
"@id": "@type",
},
fn: {
"@id": "http://www.w3.org/2006/vcard/ns#fn",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
name: {
"@id": "http://xmlns.com/foaf/0.1/name",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasAddress: {
"@id": "http://www.w3.org/2006/vcard/ns#hasAddress",
"@type": "@id",
"@isCollection": true,
},
hasEmail: {
"@id": "http://www.w3.org/2006/vcard/ns#hasEmail",
"@type": "@id",
"@isCollection": true,
},
hasPhoto: {
"@id": "http://www.w3.org/2006/vcard/ns#hasPhoto",
"@type": "@id",
},
img: {
"@id": "http://xmlns.com/foaf/0.1/img",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasTelephone: {
"@id": "http://www.w3.org/2006/vcard/ns#hasTelephone",
"@type": "@id",
"@isCollection": true,
},
phone: {
"@id": "http://www.w3.org/2006/vcard/ns#phone",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
organizationName: {
"@id": "http://www.w3.org/2006/vcard/ns#organization-name",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
role: {
"@id": "http://www.w3.org/2006/vcard/ns#role",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
trustedApp: {
"@id": "http://www.w3.org/ns/auth/acl#trustedApp",
"@type": "@id",
"@isCollection": true,
},
key: {
"@id": "http://www.w3.org/ns/auth/cert#key",
"@type": "@id",
"@isCollection": true,
},
inbox: {
"@id": "http://www.w3.org/ns/ldp#inbox",
"@type": "@id",
},
preferencesFile: {
"@id": "http://www.w3.org/ns/pim/space#preferencesFile",
"@type": "@id",
},
storage: {
"@id": "http://www.w3.org/ns/pim/space#storage",
"@type": "@id",
"@isCollection": true,
},
account: {
"@id": "http://www.w3.org/ns/solid/terms#account",
"@type": "@id",
},
privateTypeIndex: {
"@id": "http://www.w3.org/ns/solid/terms#privateTypeIndex",
"@type": "@id",
"@isCollection": true,
},
publicTypeIndex: {
"@id": "http://www.w3.org/ns/solid/terms#publicTypeIndex",
"@type": "@id",
"@isCollection": true,
},
knows: {
"@id": "http://xmlns.com/foaf/0.1/knows",
"@type": "@id",
"@isCollection": true,
},
},
},
fn: {
"@id": "http://www.w3.org/2006/vcard/ns#fn",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
name: {
"@id": "http://xmlns.com/foaf/0.1/name",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasAddress: {
"@id": "http://www.w3.org/2006/vcard/ns#hasAddress",
"@type": "@id",
"@isCollection": true,
},
countryName: {
"@id": "http://www.w3.org/2006/vcard/ns#country-name",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
locality: {
"@id": "http://www.w3.org/2006/vcard/ns#locality",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
postalCode: {
"@id": "http://www.w3.org/2006/vcard/ns#postal-code",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
region: {
"@id": "http://www.w3.org/2006/vcard/ns#region",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
streetAddress: {
"@id": "http://www.w3.org/2006/vcard/ns#street-address",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasEmail: {
"@id": "http://www.w3.org/2006/vcard/ns#hasEmail",
"@type": "@id",
"@isCollection": true,
},
Dom: {
"@id": "http://www.w3.org/2006/vcard/ns#Dom",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Home: {
"@id": "http://www.w3.org/2006/vcard/ns#Home",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
ISDN: {
"@id": "http://www.w3.org/2006/vcard/ns#ISDN",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Internet: {
"@id": "http://www.w3.org/2006/vcard/ns#Internet",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Intl: {
"@id": "http://www.w3.org/2006/vcard/ns#Intl",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Label: {
"@id": "http://www.w3.org/2006/vcard/ns#Label",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Parcel: {
"@id": "http://www.w3.org/2006/vcard/ns#Parcel",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Postal: {
"@id": "http://www.w3.org/2006/vcard/ns#Postal",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Pref: {
"@id": "http://www.w3.org/2006/vcard/ns#Pref",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
Work: {
"@id": "http://www.w3.org/2006/vcard/ns#Work",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
X400: {
"@id": "http://www.w3.org/2006/vcard/ns#X400",
"@context": {
type: {
"@id": "@type",
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
},
},
value: {
"@id": "http://www.w3.org/2006/vcard/ns#value",
"@type": "@id",
},
hasPhoto: {
"@id": "http://www.w3.org/2006/vcard/ns#hasPhoto",
"@type": "@id",
},
img: {
"@id": "http://xmlns.com/foaf/0.1/img",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
hasTelephone: {
"@id": "http://www.w3.org/2006/vcard/ns#hasTelephone",
"@type": "@id",
"@isCollection": true,
},
phone: {
"@id": "http://www.w3.org/2006/vcard/ns#phone",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
organizationName: {
"@id": "http://www.w3.org/2006/vcard/ns#organization-name",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
role: {
"@id": "http://www.w3.org/2006/vcard/ns#role",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
trustedApp: {
"@id": "http://www.w3.org/ns/auth/acl#trustedApp",
"@type": "@id",
"@isCollection": true,
},
mode: {
"@id": "http://www.w3.org/ns/auth/acl#mode",
"@isCollection": true,
},
Append: "http://www.w3.org/ns/auth/acl#Append",
Control: "http://www.w3.org/ns/auth/acl#Control",
Read: "http://www.w3.org/ns/auth/acl#Read",
Write: "http://www.w3.org/ns/auth/acl#Write",
origin: {
"@id": "http://www.w3.org/ns/auth/acl#origin",
"@type": "@id",
},
key: {
"@id": "http://www.w3.org/ns/auth/cert#key",
"@type": "@id",
"@isCollection": true,
},
modulus: {
"@id": "http://www.w3.org/ns/auth/cert#modulus",
"@type": "http://www.w3.org/2001/XMLSchema#string",
},
exponent: {
"@id": "http://www.w3.org/ns/auth/cert#exponent",
"@type": "http://www.w3.org/2001/XMLSchema#integer",
},
inbox: {
"@id": "http://www.w3.org/ns/ldp#inbox",
"@type": "@id",
},
preferencesFile: {
"@id": "http://www.w3.org/ns/pim/space#preferencesFile",
"@type": "@id",
},
storage: {
"@id": "http://www.w3.org/ns/pim/space#storage",
"@type": "@id",
"@isCollection": true,
},
account: {
"@id": "http://www.w3.org/ns/solid/terms#account",
"@type": "@id",
},
privateTypeIndex: {
"@id": "http://www.w3.org/ns/solid/terms#privateTypeIndex",
"@type": "@id",
"@isCollection": true,
},
publicTypeIndex: {
"@id": "http://www.w3.org/ns/solid/terms#publicTypeIndex",
"@type": "@id",
"@isCollection": true,
},
knows: {
"@id": "http://xmlns.com/foaf/0.1/knows",
"@type": "@id",
"@isCollection": true,
},
};

@ -0,0 +1,749 @@
import { Schema } from "shexj";
/**
* =============================================================================
* solidProfileSchema: ShexJ Schema for solidProfile
* =============================================================================
*/
export const solidProfileSchema: Schema = {
type: "Schema",
shapes: [
{
id: "https://shaperepo.com/schemas/solidProfile#SolidProfileShape",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
type: "EachOf",
expressions: [
{
type: "TripleConstraint",
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
valueExpr: {
type: "NodeConstraint",
values: ["http://schema.org/Person"],
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "Defines the node as a Person (from Schema.org)",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
valueExpr: {
type: "NodeConstraint",
values: ["http://xmlns.com/foaf/0.1/Person"],
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "Defines the node as a Person (from foaf)",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#fn",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"The formatted name of a person. Example: John Smith",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://xmlns.com/foaf/0.1/name",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "An alternate way to define a person's name.",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#hasAddress",
valueExpr:
"https://shaperepo.com/schemas/solidProfile#AddressShape",
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The person's street address.",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#hasEmail",
valueExpr:
"https://shaperepo.com/schemas/solidProfile#EmailShape",
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The person's email.",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#hasPhoto",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "A link to the person's photo",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://xmlns.com/foaf/0.1/img",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "Photo link but in string form",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#hasTelephone",
valueExpr:
"https://shaperepo.com/schemas/solidProfile#PhoneNumberShape",
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "Person's telephone number",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#phone",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"An alternative way to define a person's telephone number using a string",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#organization-name",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"The name of the organization with which the person is affiliated",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#role",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"The name of the person's role in their organization",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/auth/acl#trustedApp",
valueExpr:
"https://shaperepo.com/schemas/solidProfile#TrustedAppShape",
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"A list of app origins that are trusted by this user",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/auth/cert#key",
valueExpr:
"https://shaperepo.com/schemas/solidProfile#RSAPublicKeyShape",
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"A list of RSA public keys that are associated with private keys the user holds.",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/ldp#inbox",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"The user's LDP inbox to which apps can post notifications",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/pim/space#preferencesFile",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The user's preferences",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/pim/space#storage",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"The location of a Solid storage server related to this WebId",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/solid/terms#account",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The user's account",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/solid/terms#privateTypeIndex",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"A registry of all types used on the user's Pod (for private access only)",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/solid/terms#publicTypeIndex",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"A registry of all types used on the user's Pod (for public access)",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://xmlns.com/foaf/0.1/knows",
valueExpr:
"https://shaperepo.com/schemas/solidProfile#SolidProfileShape",
min: 0,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"A list of WebIds for all the people this user knows.",
},
},
],
},
],
},
extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"],
},
},
{
id: "https://shaperepo.com/schemas/solidProfile#AddressShape",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
type: "EachOf",
expressions: [
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#country-name",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The name of the user's country of residence",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#locality",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"The name of the user's locality (City, Town etc.) of residence",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#postal-code",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The user's postal code",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#region",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"The name of the user's region (State, Province etc.) of residence",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#street-address",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The user's street address",
},
},
],
},
],
},
},
},
{
id: "https://shaperepo.com/schemas/solidProfile#EmailShape",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
type: "EachOf",
expressions: [
{
type: "TripleConstraint",
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
valueExpr: {
type: "NodeConstraint",
values: [
"http://www.w3.org/2006/vcard/ns#Dom",
"http://www.w3.org/2006/vcard/ns#Home",
"http://www.w3.org/2006/vcard/ns#ISDN",
"http://www.w3.org/2006/vcard/ns#Internet",
"http://www.w3.org/2006/vcard/ns#Intl",
"http://www.w3.org/2006/vcard/ns#Label",
"http://www.w3.org/2006/vcard/ns#Parcel",
"http://www.w3.org/2006/vcard/ns#Postal",
"http://www.w3.org/2006/vcard/ns#Pref",
"http://www.w3.org/2006/vcard/ns#Work",
"http://www.w3.org/2006/vcard/ns#X400",
],
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The type of email.",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#value",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"The value of an email as a mailto link (Example <mailto:jane@example.com>)",
},
},
],
},
],
},
extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"],
},
},
{
id: "https://shaperepo.com/schemas/solidProfile#PhoneNumberShape",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
type: "EachOf",
expressions: [
{
type: "TripleConstraint",
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
valueExpr: {
type: "NodeConstraint",
values: [
"http://www.w3.org/2006/vcard/ns#Dom",
"http://www.w3.org/2006/vcard/ns#Home",
"http://www.w3.org/2006/vcard/ns#ISDN",
"http://www.w3.org/2006/vcard/ns#Internet",
"http://www.w3.org/2006/vcard/ns#Intl",
"http://www.w3.org/2006/vcard/ns#Label",
"http://www.w3.org/2006/vcard/ns#Parcel",
"http://www.w3.org/2006/vcard/ns#Postal",
"http://www.w3.org/2006/vcard/ns#Pref",
"http://www.w3.org/2006/vcard/ns#Work",
"http://www.w3.org/2006/vcard/ns#X400",
],
},
min: 0,
max: 1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "They type of Phone Number",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/2006/vcard/ns#value",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value:
"The value of a phone number as a tel link (Example <tel:555-555-5555>)",
},
},
],
},
],
},
extra: ["http://www.w3.org/1999/02/22-rdf-syntax-ns#type"],
},
},
{
id: "https://shaperepo.com/schemas/solidProfile#TrustedAppShape",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
type: "EachOf",
expressions: [
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/auth/acl#mode",
valueExpr: {
type: "NodeConstraint",
values: [
"http://www.w3.org/ns/auth/acl#Append",
"http://www.w3.org/ns/auth/acl#Control",
"http://www.w3.org/ns/auth/acl#Read",
"http://www.w3.org/ns/auth/acl#Write",
],
},
min: 1,
max: -1,
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The level of access provided to this origin",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/auth/acl#origin",
valueExpr: {
type: "NodeConstraint",
nodeKind: "iri",
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "The app origin the user trusts",
},
},
],
},
],
},
},
},
{
id: "https://shaperepo.com/schemas/solidProfile#RSAPublicKeyShape",
type: "ShapeDecl",
shapeExpr: {
type: "Shape",
expression: {
type: "EachOf",
expressions: [
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/auth/cert#modulus",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#string",
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "RSA Modulus",
},
},
],
},
{
type: "TripleConstraint",
predicate: "http://www.w3.org/ns/auth/cert#exponent",
valueExpr: {
type: "NodeConstraint",
datatype: "http://www.w3.org/2001/XMLSchema#integer",
},
annotations: [
{
type: "Annotation",
predicate: "http://www.w3.org/2000/01/rdf-schema#comment",
object: {
value: "RSA Exponent",
},
},
],
},
],
},
},
},
],
};

@ -0,0 +1,64 @@
import { ShapeType } from "@ldo/ldo";
import { solidProfileSchema } from "./solidProfile.schema.js";
import { solidProfileContext } from "./solidProfile.context.js";
import { AddressShape, EmailShape, PhoneNumberShape, RSAPublicKeyShape, SolidProfileShape, TrustedAppShape } from "./solidProfile.typings.js";
/**
* =============================================================================
* LDO ShapeTypes solidProfile
* =============================================================================
*/
/**
* SolidProfileShape ShapeType
*/
export const SolidProfileShapeShapeType: ShapeType<SolidProfileShape> = {
schema: solidProfileSchema,
shape: "https://shaperepo.com/schemas/solidProfile#SolidProfileShape",
context: solidProfileContext,
};
/**
* AddressShape ShapeType
*/
export const AddressShapeShapeType: ShapeType<AddressShape> = {
schema: solidProfileSchema,
shape: "https://shaperepo.com/schemas/solidProfile#AddressShape",
context: solidProfileContext,
};
/**
* EmailShape ShapeType
*/
export const EmailShapeShapeType: ShapeType<EmailShape> = {
schema: solidProfileSchema,
shape: "https://shaperepo.com/schemas/solidProfile#EmailShape",
context: solidProfileContext,
};
/**
* PhoneNumberShape ShapeType
*/
export const PhoneNumberShapeShapeType: ShapeType<PhoneNumberShape> = {
schema: solidProfileSchema,
shape: "https://shaperepo.com/schemas/solidProfile#PhoneNumberShape",
context: solidProfileContext,
};
/**
* TrustedAppShape ShapeType
*/
export const TrustedAppShapeShapeType: ShapeType<TrustedAppShape> = {
schema: solidProfileSchema,
shape: "https://shaperepo.com/schemas/solidProfile#TrustedAppShape",
context: solidProfileContext,
};
/**
* RSAPublicKeyShape ShapeType
*/
export const RSAPublicKeyShapeShapeType: ShapeType<RSAPublicKeyShape> = {
schema: solidProfileSchema,
shape: "https://shaperepo.com/schemas/solidProfile#RSAPublicKeyShape",
context: solidProfileContext,
};

@ -0,0 +1,293 @@
import { LdoJsonldContext, LdSet } from "@ldo/ldo";
/**
* =============================================================================
* Typescript Typings for solidProfile
* =============================================================================
*/
/**
* SolidProfileShape Type
*/
export interface SolidProfileShape {
"@id"?: string;
"@context"?: LdoJsonldContext;
/**
* Defines the node as a Person (from Schema.org) | Defines the node as a Person (from foaf)
*/
type: LdSet<
| {
"@id": "Person";
}
| {
"@id": "Person2";
}
>;
/**
* The formatted name of a person. Example: John Smith
*/
fn?: string;
/**
* An alternate way to define a person's name.
*/
name?: string;
/**
* The person's street address.
*/
hasAddress?: LdSet<AddressShape>;
/**
* The person's email.
*/
hasEmail?: LdSet<EmailShape>;
/**
* A link to the person's photo
*/
hasPhoto?: {
"@id": string;
};
/**
* Photo link but in string form
*/
img?: string;
/**
* Person's telephone number
*/
hasTelephone?: LdSet<PhoneNumberShape>;
/**
* An alternative way to define a person's telephone number using a string
*/
phone?: string;
/**
* The name of the organization with which the person is affiliated
*/
organizationName?: string;
/**
* The name of the person's role in their organization
*/
role?: string;
/**
* A list of app origins that are trusted by this user
*/
trustedApp?: LdSet<TrustedAppShape>;
/**
* A list of RSA public keys that are associated with private keys the user holds.
*/
key?: LdSet<RSAPublicKeyShape>;
/**
* The user's LDP inbox to which apps can post notifications
*/
inbox: {
"@id": string;
};
/**
* The user's preferences
*/
preferencesFile?: {
"@id": string;
};
/**
* The location of a Solid storage server related to this WebId
*/
storage?: LdSet<{
"@id": string;
}>;
/**
* The user's account
*/
account?: {
"@id": string;
};
/**
* A registry of all types used on the user's Pod (for private access only)
*/
privateTypeIndex?: LdSet<{
"@id": string;
}>;
/**
* A registry of all types used on the user's Pod (for public access)
*/
publicTypeIndex?: LdSet<{
"@id": string;
}>;
/**
* A list of WebIds for all the people this user knows.
*/
knows?: LdSet<SolidProfileShape>;
}
/**
* AddressShape Type
*/
export interface AddressShape {
"@id"?: string;
"@context"?: LdoJsonldContext;
/**
* The name of the user's country of residence
*/
countryName?: string;
/**
* The name of the user's locality (City, Town etc.) of residence
*/
locality?: string;
/**
* The user's postal code
*/
postalCode?: string;
/**
* The name of the user's region (State, Province etc.) of residence
*/
region?: string;
/**
* The user's street address
*/
streetAddress?: string;
}
/**
* EmailShape Type
*/
export interface EmailShape {
"@id"?: string;
"@context"?: LdoJsonldContext;
/**
* The type of email.
*/
type?:
| {
"@id": "Dom";
}
| {
"@id": "Home";
}
| {
"@id": "ISDN";
}
| {
"@id": "Internet";
}
| {
"@id": "Intl";
}
| {
"@id": "Label";
}
| {
"@id": "Parcel";
}
| {
"@id": "Postal";
}
| {
"@id": "Pref";
}
| {
"@id": "Work";
}
| {
"@id": "X400";
};
/**
* The value of an email as a mailto link (Example <mailto:jane@example.com>)
*/
value: {
"@id": string;
};
}
/**
* PhoneNumberShape Type
*/
export interface PhoneNumberShape {
"@id"?: string;
"@context"?: LdoJsonldContext;
/**
* They type of Phone Number
*/
type?:
| {
"@id": "Dom";
}
| {
"@id": "Home";
}
| {
"@id": "ISDN";
}
| {
"@id": "Internet";
}
| {
"@id": "Intl";
}
| {
"@id": "Label";
}
| {
"@id": "Parcel";
}
| {
"@id": "Postal";
}
| {
"@id": "Pref";
}
| {
"@id": "Work";
}
| {
"@id": "X400";
};
/**
* The value of a phone number as a tel link (Example <tel:555-555-5555>)
*/
value: {
"@id": string;
};
}
/**
* TrustedAppShape Type
*/
export interface TrustedAppShape {
"@id"?: string;
"@context"?: LdoJsonldContext;
/**
* The level of access provided to this origin
*/
mode: LdSet<
| {
"@id": "Append";
}
| {
"@id": "Control";
}
| {
"@id": "Read";
}
| {
"@id": "Write";
}
>;
/**
* The app origin the user trusts
*/
origin: {
"@id": string;
};
}
/**
* RSAPublicKeyShape Type
*/
export interface RSAPublicKeyShape {
"@id"?: string;
"@context"?: LdoJsonldContext;
/**
* RSA Modulus
*/
modulus: string;
/**
* RSA Exponent
*/
exponent: number;
}

@ -0,0 +1,17 @@
import { createLdoReactMethods } from "../src/createLdoReactMethods.js";
import { mockConnectedPlugin } from "../../connected/test/mocks/MockConnectedPlugin.js";
export const {
dataset,
useLdo,
useMatchObject,
useMatchSubject,
useResource,
useSubject,
useSubscribeToResource,
useLinkQuery,
useChangeDataset,
useChangeSubject,
useChangeMatchSubject,
useChangeMatchObject,
} = createLdoReactMethods([mockConnectedPlugin]);

@ -1,7 +0,0 @@
import { describe, it, expect } from "vitest";
describe("react", () => {
it("trivial", () => {
expect(true).toBe(true);
});
});

@ -0,0 +1,242 @@
// useChangeSubject.spec.tsx
/// <reference types="@testing-library/jest-dom" />
import { useResource, useChangeSubject, useSubject } from "./mockLdoMethods.js";
import type { FunctionComponent } from "react";
import React, { useState } from "react";
import { describe, it, expect, beforeEach } from "vitest";
import { render, screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { SolidProfileShapeShapeType } from "./.ldo/solidProfile.shapeTypes.js";
import { set } from "@ldo/jsonld-dataset-proxy";
import "@testing-library/jest-dom/vitest";
/**
* Test component: deterministic friend IDs (Example1, Example2, ...),
* accessible labels, and committed data shown via useSubject.
*/
const FormTest: FunctionComponent = () => {
const randomResource = useResource("http://example.com/resource.ttl");
const submittedData = useSubject(SolidProfileShapeShapeType, "Example0");
const [count, setCount] = useState(1);
const [data, setData, commitData] = useChangeSubject(
SolidProfileShapeShapeType,
"Example0",
);
return (
<div>
<h1>Form</h1>
<button onClick={() => setCount(count + 1)}>Rerender {count}</button>
<form
onSubmit={async (e) => {
e.preventDefault();
await commitData();
}}
>
{/* Primary name field */}
<input
aria-label="Name"
value={data?.fn ?? ""}
onChange={(e) => {
setData(randomResource, (profile) => {
profile.fn = e.target.value;
});
}}
/>
{/* Friends */}
{data?.knows?.map((person) => (
<div key={person["@id"]} data-testid={`friend-${person["@id"]}`}>
<p>{person["@id"]}</p>
<input
aria-label={`Friend name for ${person["@id"]}`}
value={person?.fn ?? ""}
onChange={(e) =>
setData(
randomResource,
(p) => {
p.fn = e.target.value;
},
person,
)
}
/>
<button
type="button"
onClick={() => {
setData(randomResource, (cData) => {
cData.knows?.delete(person);
});
}}
>
Remove Friend
</button>
</div>
))}
<button
type="button"
onClick={() => {
// Auto-generate deterministic IDs: Example1, Example2, ...
const friendId = `Example${count}`;
setCount(count + 1);
setData(randomResource, (cData) => {
cData.knows?.add({
"@id": friendId,
type: set({ "@id": "Person" }),
inbox: { "@id": "someInbox" },
});
});
}}
>
Add Friend
</button>
<input type="submit" value="Submit" />
</form>
<hr />
{/* Committed view */}
<h1>Submitted Data</h1>
<section aria-label="Submitted Data">
<p data-testid="submitted-name">Name: {submittedData?.fn ?? ""}</p>
<ul data-testid="submitted-list">
{submittedData?.knows?.map((person) => (
<li key={person["@id"]}>
Id: {person["@id"]} Name: {person.fn}
</li>
))}
</ul>
</section>
</div>
);
};
/**
* Spec: drives the UI as requested.
*/
describe("useChangeSubject", () => {
let user: ReturnType<typeof userEvent.setup>;
beforeEach(() => {
user = userEvent.setup();
});
it("handles typing, list add/remove, and commit cycles", async () => {
render(<FormTest />);
// 1) Type "Example0" into the Name field, assert after each keystroke
const nameInput = screen.getByRole("textbox", { name: "Name" });
const targetName = "Example0";
let progressive = "";
for (const c of targetName) {
progressive += c;
await user.type(nameInput, c);
expect(nameInput).toHaveValue(progressive);
}
// Submitted is blank so far
const submittedSection = screen.getByRole("region", {
name: /submitted data/i,
});
const submittedName =
within(submittedSection).getByTestId("submitted-name");
const submittedList =
within(submittedSection).getByTestId("submitted-list");
expect(submittedName).toHaveTextContent("Name:");
expect(within(submittedList).queryAllByRole("listitem")).toHaveLength(0);
// 2) Add two friends -> Example1, Example2
const addFriendBtn = screen.getByRole("button", { name: /add friend/i });
await user.click(addFriendBtn);
await user.click(addFriendBtn);
const friend1 = screen.getByTestId("friend-Example1");
const friend2 = screen.getByTestId("friend-Example2");
expect(within(friend1).getByText("Example1")).toBeInTheDocument();
expect(within(friend2).getByText("Example2")).toBeInTheDocument();
// 3) Type friend names with per-keystroke assertions
const friend1Input = within(friend1).getByRole("textbox", {
name: "Friend name for Example1",
});
const friend2Input = within(friend2).getByRole("textbox", {
name: "Friend name for Example2",
});
const friend1Name = "Example1";
const friend2Name = "Example2";
let p = "";
for (const c of friend1Name) {
p += c;
await user.type(friend1Input, c);
expect(friend1Input).toHaveValue(p);
}
p = "";
for (const c of friend2Name) {
p += c;
await user.type(friend2Input, c);
expect(friend2Input).toHaveValue(p);
}
// Still nothing committed
expect(submittedName).toHaveTextContent("Name:");
expect(within(submittedList).queryAllByRole("listitem")).toHaveLength(0);
// 4) Remove Example2
await user.click(
within(friend2).getByRole("button", { name: /remove friend/i }),
);
expect(screen.queryByTestId("friend-Example2")).not.toBeInTheDocument();
// 5) Submit -> committed data reflects Example0 + Example1 only
await user.click(screen.getByRole("button", { name: /Submit/i }));
// Form retained its values
expect(nameInput).toHaveValue("Example0");
expect(friend1Input).toHaveValue("Example1");
expect(screen.queryByTestId("friend-Example2")).not.toBeInTheDocument();
// Wait for the submitted data to appear in the document before asserting
const submittedSection2 = screen.getByRole("region", {
name: /submitted data/i,
});
const submittedName2 =
within(submittedSection2).getByTestId("submitted-name");
// Use `findByText` from the `within` helper to wait for the change
await within(submittedSection2).findByText("Name: Example0");
// Now that we've successfully waited, we can safely make our assertions
expect(submittedName2).toHaveTextContent("Name: Example0");
const itemsAfterSubmit = within(submittedList).getAllByRole("listitem");
expect(itemsAfterSubmit).toHaveLength(1);
expect(itemsAfterSubmit[0]).toHaveTextContent(
"Id: Example1 Name: Example1",
);
// 6) Change name and resubmit
await user.clear(nameInput);
const newName = "anotherExample0";
let q = "";
for (const c of newName) {
q += c;
await user.type(nameInput, c);
expect(nameInput).toHaveValue(q);
}
await user.click(screen.getByRole("button", { name: /submit/i }));
expect(submittedName).toHaveTextContent(`Name: ${newName}`);
const itemsAfterSecondSubmit =
within(submittedList).getAllByRole("listitem");
expect(itemsAfterSecondSubmit).toHaveLength(1);
expect(itemsAfterSecondSubmit[0]).toHaveTextContent(
"Id: Example1 Name: Example1",
);
});
});

@ -1,9 +1,12 @@
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
test: {
coverage: {
provider: "istanbul",
},
environment: "jsdom",
},
});

@ -1,6 +1,6 @@
{
"name": "@ldo/schema-converter-shex",
"version": "1.0.0-alpha.30",
"version": "1.0.0-alpha.31",
"description": "",
"type": "module",
"main": "./dist/cjs/index.cjs",
@ -34,7 +34,7 @@
},
"homepage": "https://github.com/o-development/ldo/tree/main/packages/schema-converter-shex#readme",
"devDependencies": {
"@ldo/jsonld-dataset-proxy": "^1.0.0-alpha.30",
"@ldo/jsonld-dataset-proxy": "^1.0.0-alpha.31",
"@shexjs/parser": "^1.0.0-alpha.24",
"@types/jsonld": "^1.5.6",
"@types/shexj": "^2.1.3",

@ -1,6 +1,6 @@
{
"name": "@ldo/solid-react",
"version": "1.0.0-alpha.30",
"version": "1.0.0-alpha.31",
"description": "A React library for LDO and Solid",
"type": "module",
"main": "./dist/cjs/index.cjs",
@ -45,9 +45,9 @@
},
"dependencies": {
"@inrupt/solid-client-authn-browser": "^3.0.0",
"@ldo/connected": "^1.0.0-alpha.30",
"@ldo/connected-solid": "^1.0.0-alpha.30",
"@ldo/react": "^1.0.0-alpha.30",
"@ldo/connected": "^1.0.0-alpha.31",
"@ldo/connected-solid": "^1.0.0-alpha.31",
"@ldo/react": "^1.0.0-alpha.31",
"cross-fetch": "^3.1.6"
},
"files": [

@ -7,6 +7,7 @@ import { createBrowserSolidReactMethods } from "./createBrowserSolidReactMethods
*/
export const {
dataset,
useDataset,
useLdo,
useMatchObject,
useMatchSubject,
@ -14,6 +15,10 @@ export const {
useSubject,
useSubscribeToResource,
useLinkQuery,
useChangeDataset,
useChangeSubject,
useChangeMatchObject,
useChangeMatchSubject,
} = createLdoReactMethods([solidConnectedPlugin]);
export const { BrowserSolidLdoProvider, useSolidAuth, useRootContainerFor } =

@ -1,6 +1,6 @@
{
"name": "@ldo/solid-type-index",
"version": "1.0.0-alpha.30",
"version": "1.0.0-alpha.31",
"description": "Solid Type Index support for LDO",
"type": "module",
"main": "./dist/cjs/index.cjs",
@ -44,8 +44,8 @@
"ts-node": "^10.9.2"
},
"dependencies": {
"@ldo/connected-solid": "^1.0.0-alpha.30",
"@ldo/solid-react": "^1.0.0-alpha.30"
"@ldo/connected-solid": "^1.0.0-alpha.31",
"@ldo/solid-react": "^1.0.0-alpha.31"
},
"files": [
"dist",

@ -1,6 +1,6 @@
{
"name": "@ldo/subscribable-dataset",
"version": "1.0.0-alpha.30",
"version": "1.0.0-alpha.31",
"description": "An RDFJS dataset implementation that can be subscribed to for updates",
"type": "module",
"main": "./dist/cjs/index.cjs",

@ -42,7 +42,7 @@ export class SubscribableDataset<InAndOutQuad extends BaseQuad = BaseQuad>
/**
* Helps find all the events for a given listener
*/
private listenerHashMap: Map<nodeEventListener<InAndOutQuad>, Set<string>> =
protected listenerHashMap: Map<nodeEventListener<InAndOutQuad>, Set<string>> =
new Map();
/**
@ -170,7 +170,7 @@ export class SubscribableDataset<InAndOutQuad extends BaseQuad = BaseQuad>
* Triggers all subscriptions based on an updated quads
* @param changed The changed triples of the transaction
*/
private triggerSubscriptionForQuads(
protected triggerSubscriptionForQuads(
changed: DatasetChanges<InAndOutQuad>,
): void {
// A mapping of serialized QuadMatches to the changed quads

@ -1,6 +1,9 @@
import type { Dataset, BaseQuad, Term, DatasetFactory } from "@rdfjs/types";
import type { DatasetChanges } from "@ldo/rdf-utils";
import type { ITransactionDataset, ITransactionDatasetFactory } from "./types.js";
import type {
ITransactionDataset,
ITransactionDatasetFactory,
} from "./types.js";
import { mergeDatasetChanges } from "./mergeDatasetChanges.js";
import { SubscribableDataset } from "./SubscribableDataset.js";
import { updateDatasetInBulk } from "./util.js";
@ -232,15 +235,18 @@ export class TransactionDataset<InAndOutQuad extends BaseQuad = BaseQuad>
removed?: Dataset<InAndOutQuad> | InAndOutQuad[];
}): void {
this.checkIfTransactionCommitted();
mergeDatasetChanges(this.datasetChanges, {
const newDatasetChanges = {
added: changes.added
? this.datasetFactory.dataset(changes.added)
: undefined,
removed: changes.removed
? this.datasetFactory.dataset(changes.removed)
: undefined,
});
};
mergeDatasetChanges(this.datasetChanges, newDatasetChanges);
this.triggerSubscriptionForQuads(newDatasetChanges);
}
/**

@ -1,6 +1,6 @@
{
"name": "@ldo/svelte",
"version": "1.0.0-alpha.30",
"version": "1.0.0-alpha.31",
"description": "A Svelte library for LDO.",
"type": "module",
"main": "./dist/cjs/index.cjs",
@ -65,11 +65,11 @@
"svelte": "^3.50.0"
},
"dependencies": {
"@ldo/connected": "^1.0.0-alpha.30",
"@ldo/jsonld-dataset-proxy": "^1.0.0-alpha.30",
"@ldo/ldo": "^1.0.0-alpha.30",
"@ldo/connected": "^1.0.0-alpha.31",
"@ldo/jsonld-dataset-proxy": "^1.0.0-alpha.31",
"@ldo/ldo": "^1.0.0-alpha.31",
"@ldo/rdf-utils": "^1.0.0-alpha.30",
"@ldo/subscribable-dataset": "^1.0.0-alpha.30",
"@ldo/subscribable-dataset": "^1.0.0-alpha.31",
"tsx": "^4.19.4"
},
"files": [

Loading…
Cancel
Save