commit
ff92c8b67a
@ -1,4 +1,4 @@ |
|||||||
{ |
{ |
||||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json", |
"$schema": "node_modules/lerna/schemas/lerna-schema.json", |
||||||
"version": "1.0.0-alpha.8" |
"version": "1.0.0-alpha.9" |
||||||
} |
} |
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,3 +0,0 @@ |
|||||||
import { config } from "dotenv"; |
|
||||||
|
|
||||||
config(); |
|
@ -0,0 +1,43 @@ |
|||||||
|
import type { LdoBase, ShapeType } from "@ldo/ldo"; |
||||||
|
import { LdoBuilder } from "@ldo/ldo"; |
||||||
|
import type { IConnectedLdoBuilder } from "./types/IConnectedLdoBuilder"; |
||||||
|
import type { JsonldDatasetProxyBuilder } from "@ldo/jsonld-dataset-proxy"; |
||||||
|
import type { SubjectNode } from "@ldo/rdf-utils"; |
||||||
|
import type { LQInput } from "./types/ILinkQuery"; |
||||||
|
import { ResourceLinkQuery } from "./linkTraversal/ResourceLinkQuery"; |
||||||
|
import type { ConnectedPlugin } from "./types/ConnectedPlugin"; |
||||||
|
import type { IConnectedLdoDataset } from "./types/IConnectedLdoDataset"; |
||||||
|
|
||||||
|
export class ConnectedLdoBuilder< |
||||||
|
Type extends LdoBase, |
||||||
|
Plugins extends ConnectedPlugin[], |
||||||
|
> |
||||||
|
extends LdoBuilder<Type> |
||||||
|
implements IConnectedLdoBuilder<Type, Plugins> |
||||||
|
{ |
||||||
|
protected parentDataset: IConnectedLdoDataset<Plugins>; |
||||||
|
|
||||||
|
constructor( |
||||||
|
parentDataset: IConnectedLdoDataset<Plugins>, |
||||||
|
jsonldDatasetProxyBuilder: JsonldDatasetProxyBuilder, |
||||||
|
shapeType: ShapeType<Type>, |
||||||
|
) { |
||||||
|
super(jsonldDatasetProxyBuilder, shapeType); |
||||||
|
this.parentDataset = parentDataset; |
||||||
|
} |
||||||
|
|
||||||
|
startLinkQuery<Input extends LQInput<Type>>( |
||||||
|
startingResource: Plugins[number]["types"]["resource"], |
||||||
|
startingSubject: SubjectNode | string, |
||||||
|
linkQueryInput: Input, |
||||||
|
): ResourceLinkQuery<Type, Input, Plugins> { |
||||||
|
return new ResourceLinkQuery( |
||||||
|
this.parentDataset, |
||||||
|
this.shapeType, |
||||||
|
this, |
||||||
|
startingResource, |
||||||
|
startingSubject, |
||||||
|
linkQueryInput, |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,287 @@ |
|||||||
|
import type { LdoBase, ShapeType } from "@ldo/ldo"; |
||||||
|
import type { |
||||||
|
ExpandDeep, |
||||||
|
ILinkQuery, |
||||||
|
LQInput, |
||||||
|
LQReturn, |
||||||
|
} from "../types/ILinkQuery"; |
||||||
|
import type { ConnectedPlugin } from "../types/ConnectedPlugin"; |
||||||
|
import type { SubjectNode } from "@ldo/rdf-utils"; |
||||||
|
import { exploreLinks } from "./exploreLinks"; |
||||||
|
import type { IConnectedLdoDataset } from "../types/IConnectedLdoDataset"; |
||||||
|
import type { IConnectedLdoBuilder } from "../types/IConnectedLdoBuilder"; |
||||||
|
import { v4 } from "uuid"; |
||||||
|
import type { nodeEventListener } from "@ldo/subscribable-dataset"; |
||||||
|
import type { Quad } from "@rdfjs/types"; |
||||||
|
|
||||||
|
/** |
||||||
|
* Represents a query over multiple datasources and constituting muliple |
||||||
|
* resources. |
||||||
|
* |
||||||
|
* @example |
||||||
|
* ```typescript
|
||||||
|
* import { ProfileShapeType } from "./.ldo/Profile.shapeType.ts"; |
||||||
|
* |
||||||
|
* // Create a link query
|
||||||
|
* const linkQuery = ldoDataset |
||||||
|
* .usingType(ProfileShapeType) |
||||||
|
* .startLinkQuery( |
||||||
|
* "http://example.com/profile/card", |
||||||
|
* "http://example.com/profile/card#me", |
||||||
|
* { |
||||||
|
* name: true, |
||||||
|
* knows: { |
||||||
|
* name: true, |
||||||
|
* }, |
||||||
|
* }, |
||||||
|
* } |
||||||
|
* ); |
||||||
|
* // Susbscribe to this link query, automaticically updating the dataset when
|
||||||
|
* // something from the link query is changed.
|
||||||
|
* await linkQuery.subscribe(); |
||||||
|
* ``` |
||||||
|
*/ |
||||||
|
export class ResourceLinkQuery< |
||||||
|
Type extends LdoBase, |
||||||
|
QueryInput extends LQInput<Type>, |
||||||
|
Plugins extends ConnectedPlugin[], |
||||||
|
> implements ILinkQuery<Type, QueryInput> |
||||||
|
{ |
||||||
|
protected previousTransactionId: string = "INIT"; |
||||||
|
|
||||||
|
// Resource Subscriptions uri -> unsubscribeId
|
||||||
|
protected activeResourceSubscriptions: Record<string, string> = {}; |
||||||
|
// Unsubscribe IDs for this ResourceLinkQuery
|
||||||
|
protected thisUnsubscribeIds = new Set<string>(); |
||||||
|
|
||||||
|
protected curOnDataChanged: nodeEventListener<Quad> | undefined; |
||||||
|
|
||||||
|
protected resourcesWithSubscriptionInProgress: Record< |
||||||
|
string, |
||||||
|
Promise<void> | undefined |
||||||
|
> = {}; |
||||||
|
|
||||||
|
/** |
||||||
|
* @internal |
||||||
|
* @param parentDataset The dataset for which this link query is a part |
||||||
|
* @param shapeType A ShapeType for the link query to follow |
||||||
|
* @param ldoBuilder An LdoBuilder associated with the dataset |
||||||
|
* @param startingResource The resource to explore first in the link query |
||||||
|
* @param startingSubject The starting point of the link query |
||||||
|
* @param linkQueryInput A definition of the link query |
||||||
|
*/ |
||||||
|
constructor( |
||||||
|
protected parentDataset: IConnectedLdoDataset<Plugins>, |
||||||
|
protected shapeType: ShapeType<Type>, |
||||||
|
protected ldoBuilder: IConnectedLdoBuilder<Type, Plugins>, |
||||||
|
protected startingResource: Plugins[number]["types"]["resource"], |
||||||
|
protected startingSubject: SubjectNode | string, |
||||||
|
protected linkQueryInput: QueryInput, |
||||||
|
) {} |
||||||
|
|
||||||
|
/** |
||||||
|
* Runs this link query, returning the result |
||||||
|
* @param options Options for how to run the link query |
||||||
|
* @returns A subset of the ShapeType as defined by the LinkQuery |
||||||
|
* |
||||||
|
* @example |
||||||
|
* ``` |
||||||
|
* import { ProfileShapeType } from "./.ldo/Profile.shapeType.ts"; |
||||||
|
* |
||||||
|
* // Create a link query
|
||||||
|
* const linkQuery = ldoDataset |
||||||
|
* .usingType(ProfileShapeType) |
||||||
|
* .startLinkQuery( |
||||||
|
* "http://example.com/profile/card", |
||||||
|
* "http://example.com/profile/card#me", |
||||||
|
* { |
||||||
|
* name: true, |
||||||
|
* knows: { |
||||||
|
* name: true, |
||||||
|
* }, |
||||||
|
* }, |
||||||
|
* } |
||||||
|
* ); |
||||||
|
* // Susbscribe to this link query, automaticically updating the dataset when
|
||||||
|
* // something from the link query is changed.
|
||||||
|
* const result = await linkQuery.read(); |
||||||
|
* console.log(result.name); |
||||||
|
* result.knows.forEach((person) => console.log(person.name)); |
||||||
|
* // The following will type-error. Despite "phone" existing on a Profile,
|
||||||
|
* // it was not covered by the link query.
|
||||||
|
* console.log(result.phone); |
||||||
|
* ``` |
||||||
|
*/ |
||||||
|
async run(options?: { |
||||||
|
reload?: boolean; |
||||||
|
}): Promise<ExpandDeep<LQReturn<Type, QueryInput>>> { |
||||||
|
await exploreLinks( |
||||||
|
this.parentDataset, |
||||||
|
this.shapeType, |
||||||
|
this.startingResource, |
||||||
|
this.startingSubject, |
||||||
|
this.linkQueryInput, |
||||||
|
{ shouldRefreshResources: options?.reload }, |
||||||
|
); |
||||||
|
return this.fromSubject(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Subscribes to the data defined by the link query, updating the dataset if |
||||||
|
* any changes are made. |
||||||
|
* @returns An unsubscribeId |
||||||
|
* |
||||||
|
* @example |
||||||
|
* ``` |
||||||
|
* import { ProfileShapeType } from "./.ldo/Profile.shapeType.ts"; |
||||||
|
* |
||||||
|
* // Create a link query
|
||||||
|
* const linkQuery = ldoDataset |
||||||
|
* .usingType(ProfileShapeType) |
||||||
|
* .startLinkQuery( |
||||||
|
* "http://example.com/profile/card", |
||||||
|
* "http://example.com/profile/card#me", |
||||||
|
* { |
||||||
|
* name: true, |
||||||
|
* knows: { |
||||||
|
* name: true, |
||||||
|
* }, |
||||||
|
* }, |
||||||
|
* } |
||||||
|
* ); |
||||||
|
* // Susbscribe to this link query, automaticically updating the dataset when
|
||||||
|
* // something from the link query is changed.
|
||||||
|
* const unsubscribeId = await linkQuery.subscribe(); |
||||||
|
* |
||||||
|
* // Now, let's imagine the following triple was added to
|
||||||
|
* "http://example.com/profile/card": |
||||||
|
* <http://example.com/profile/card#me> <http://xmlns.com/foaf/0.1/knows> <http://example2.com/profile/card#me> |
||||||
|
* Because you're subscribed, the dataset will automatically be updated. |
||||||
|
* |
||||||
|
* // End subscription
|
||||||
|
* linkQuery.unsubscribe(unsubscribeId); |
||||||
|
* ``` |
||||||
|
*/ |
||||||
|
async subscribe(): Promise<string> { |
||||||
|
const subscriptionId = v4(); |
||||||
|
this.thisUnsubscribeIds.add(subscriptionId); |
||||||
|
// If there's already a registered onDataChange, we don't need to make a new
|
||||||
|
// on for this new subscription
|
||||||
|
if (this.curOnDataChanged) { |
||||||
|
return subscriptionId; |
||||||
|
} |
||||||
|
this.curOnDataChanged = async ( |
||||||
|
_changes, |
||||||
|
transactionId: string, |
||||||
|
_triggering, |
||||||
|
) => { |
||||||
|
// Set a transaction Id, so that we only trigger one re-render
|
||||||
|
if (transactionId === this.previousTransactionId) return; |
||||||
|
this.previousTransactionId = transactionId; |
||||||
|
// Remove previous registration
|
||||||
|
this.parentDataset.removeListenerFromAllEvents(this.curOnDataChanged!); |
||||||
|
|
||||||
|
// Explore the links, with a subscription to re-explore the links if any
|
||||||
|
// covered information changes
|
||||||
|
const resourcesToUnsubscribeFrom = new Set( |
||||||
|
Object.keys(this.activeResourceSubscriptions), |
||||||
|
); |
||||||
|
|
||||||
|
// Only add the listeners if we're currently subscribed
|
||||||
|
const exploreOptions = this.curOnDataChanged |
||||||
|
? { |
||||||
|
onCoveredDataChanged: this.curOnDataChanged, |
||||||
|
onResourceEncountered: async (resource) => { |
||||||
|
// Wait for the the in progress registration to complete. Once it
|
||||||
|
// is complete, you're subscribed, so we can remove this from the
|
||||||
|
// resources to unsubscribe from.
|
||||||
|
if (this.resourcesWithSubscriptionInProgress[resource.uri]) { |
||||||
|
await this.resourcesWithSubscriptionInProgress[resource.uri]; |
||||||
|
resourcesToUnsubscribeFrom.delete(resource.uri); |
||||||
|
return; |
||||||
|
} |
||||||
|
// No need to do anything if we're already subscribed
|
||||||
|
if (resourcesToUnsubscribeFrom.has(resource.uri)) { |
||||||
|
resourcesToUnsubscribeFrom.delete(resource.uri); |
||||||
|
return; |
||||||
|
} |
||||||
|
// Otherwise begin the subscription
|
||||||
|
let resolve; |
||||||
|
this.resourcesWithSubscriptionInProgress[resource.uri] = |
||||||
|
new Promise<void>((res) => { |
||||||
|
resolve = res; |
||||||
|
}); |
||||||
|
const unsubscribeId = await resource.subscribeToNotifications(); |
||||||
|
this.activeResourceSubscriptions[resource.uri] = unsubscribeId; |
||||||
|
// Unsubscribe in case unsubscribe call came in mid subscription
|
||||||
|
if (!this.curOnDataChanged) { |
||||||
|
await this.unsubscribeFromResource(resource.uri); |
||||||
|
} |
||||||
|
resolve(); |
||||||
|
this.resourcesWithSubscriptionInProgress[resource.uri] = |
||||||
|
undefined; |
||||||
|
}, |
||||||
|
} |
||||||
|
: {}; |
||||||
|
await exploreLinks( |
||||||
|
this.parentDataset, |
||||||
|
this.shapeType, |
||||||
|
this.startingResource, |
||||||
|
this.startingSubject, |
||||||
|
this.linkQueryInput, |
||||||
|
exploreOptions, |
||||||
|
); |
||||||
|
// Clean up unused subscriptions
|
||||||
|
await Promise.all( |
||||||
|
Array.from(resourcesToUnsubscribeFrom).map(async (uri) => |
||||||
|
this.unsubscribeFromResource(uri), |
||||||
|
), |
||||||
|
); |
||||||
|
}; |
||||||
|
await this.curOnDataChanged({}, "BEGIN_SUB", [null, null, null, null]); |
||||||
|
return subscriptionId; |
||||||
|
} |
||||||
|
|
||||||
|
private async unsubscribeFromResource(uri) { |
||||||
|
const resource = this.parentDataset.getResource(uri); |
||||||
|
const unsubscribeId = this.activeResourceSubscriptions[uri]; |
||||||
|
delete this.activeResourceSubscriptions[uri]; |
||||||
|
await resource.unsubscribeFromNotifications(unsubscribeId); |
||||||
|
} |
||||||
|
|
||||||
|
private async fullUnsubscribe(): Promise<void> { |
||||||
|
if (this.curOnDataChanged) { |
||||||
|
this.parentDataset.removeListenerFromAllEvents(this.curOnDataChanged); |
||||||
|
this.curOnDataChanged = undefined; |
||||||
|
} |
||||||
|
await Promise.all( |
||||||
|
Object.keys(this.activeResourceSubscriptions).map(async (uri) => { |
||||||
|
this.unsubscribeFromResource(uri); |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
async unsubscribe(unsubscribeId: string): Promise<void> { |
||||||
|
this.thisUnsubscribeIds.delete(unsubscribeId); |
||||||
|
if (this.thisUnsubscribeIds.size === 0) { |
||||||
|
await this.fullUnsubscribe(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
async unsubscribeAll() { |
||||||
|
this.thisUnsubscribeIds.clear(); |
||||||
|
await this.fullUnsubscribe(); |
||||||
|
} |
||||||
|
|
||||||
|
fromSubject(): ExpandDeep<LQReturn<Type, QueryInput>> { |
||||||
|
return this.ldoBuilder.fromSubject( |
||||||
|
this.startingSubject, |
||||||
|
) as unknown as ExpandDeep<LQReturn<Type, QueryInput>>; |
||||||
|
} |
||||||
|
|
||||||
|
getSubscribedResources(): Plugins[number]["types"]["resource"][] { |
||||||
|
return Object.keys(this.activeResourceSubscriptions).map((uri) => |
||||||
|
this.parentDataset.getResource(uri), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,162 @@ |
|||||||
|
import type { LdoBase, ShapeType } from "@ldo/ldo"; |
||||||
|
import type { ConnectedPlugin } from "../types/ConnectedPlugin"; |
||||||
|
import type { SubjectNode } from "@ldo/rdf-utils"; |
||||||
|
import type { LQInput } from "../types/ILinkQuery"; |
||||||
|
import { BasicLdSet } from "@ldo/jsonld-dataset-proxy"; |
||||||
|
import type { IConnectedLdoDataset } from "../types/IConnectedLdoDataset"; |
||||||
|
import { createTrackingProxyBuilder } from "../trackingProxy/createTrackingProxy"; |
||||||
|
import type { nodeEventListener } from "@ldo/subscribable-dataset"; |
||||||
|
import type { Quad } from "@rdfjs/types"; |
||||||
|
|
||||||
|
/** |
||||||
|
* @internal |
||||||
|
*/ |
||||||
|
interface ExploreLinksOptions<Plugins extends ConnectedPlugin[]> { |
||||||
|
onResourceEncountered?: ( |
||||||
|
resource: Plugins[number]["types"]["resource"], |
||||||
|
) => Promise<void>; |
||||||
|
onCoveredDataChanged?: nodeEventListener<Quad>; |
||||||
|
shouldRefreshResources?: boolean; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @internal |
||||||
|
*/ |
||||||
|
export async function exploreLinks< |
||||||
|
Type extends LdoBase, |
||||||
|
Plugins extends ConnectedPlugin[], |
||||||
|
>( |
||||||
|
dataset: IConnectedLdoDataset<Plugins>, |
||||||
|
shapeType: ShapeType<Type>, |
||||||
|
startingResource: Plugins[number]["types"]["resource"], |
||||||
|
startingSubject: SubjectNode | string, |
||||||
|
queryInput: LQInput<Type>, |
||||||
|
options?: ExploreLinksOptions<Plugins>, |
||||||
|
): Promise<void> { |
||||||
|
// Do an initial check of the resources.
|
||||||
|
const readResult = options?.shouldRefreshResources |
||||||
|
? await startingResource.read() |
||||||
|
: await startingResource.readIfUnfetched(); |
||||||
|
if (readResult.isError) return; |
||||||
|
|
||||||
|
if (options?.onResourceEncountered) |
||||||
|
await options?.onResourceEncountered(startingResource); |
||||||
|
|
||||||
|
const proxyBuilder = options?.onCoveredDataChanged |
||||||
|
? createTrackingProxyBuilder( |
||||||
|
dataset, |
||||||
|
shapeType, |
||||||
|
options?.onCoveredDataChanged, |
||||||
|
) |
||||||
|
: dataset.usingType(shapeType); |
||||||
|
const ldObject = proxyBuilder.fromSubject(startingSubject); |
||||||
|
|
||||||
|
const encounteredDuringThisExploration = new Set<string>([ |
||||||
|
startingResource.uri, |
||||||
|
]); |
||||||
|
|
||||||
|
// Recursively explore the rest
|
||||||
|
await exploreLinksRecursive( |
||||||
|
dataset, |
||||||
|
ldObject, |
||||||
|
queryInput, |
||||||
|
encounteredDuringThisExploration, |
||||||
|
options, |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
export async function exploreLinksRecursive< |
||||||
|
Type extends LdoBase, |
||||||
|
Plugins extends ConnectedPlugin[], |
||||||
|
>( |
||||||
|
dataset: IConnectedLdoDataset<Plugins>, |
||||||
|
ldObject: Type, |
||||||
|
queryInput: LQInput<Type>, |
||||||
|
encounteredDuringThisExploration: Set<string>, |
||||||
|
options?: ExploreLinksOptions<Plugins>, |
||||||
|
): Promise<void> { |
||||||
|
const shouldFetch = shouldFetchResource( |
||||||
|
dataset, |
||||||
|
ldObject, |
||||||
|
queryInput, |
||||||
|
encounteredDuringThisExploration, |
||||||
|
); |
||||||
|
const resourceToFetch = dataset.getResource(ldObject["@id"]); |
||||||
|
if (shouldFetch) { |
||||||
|
const readResult = options?.shouldRefreshResources |
||||||
|
? await resourceToFetch.read() |
||||||
|
: await resourceToFetch.readIfUnfetched(); |
||||||
|
// If there was an error with the read, the traversal is done.
|
||||||
|
if (readResult.isError) { |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
if (!encounteredDuringThisExploration.has(resourceToFetch.uri)) { |
||||||
|
encounteredDuringThisExploration.add(resourceToFetch.uri); |
||||||
|
if (options?.onResourceEncountered) |
||||||
|
await options.onResourceEncountered(resourceToFetch); |
||||||
|
} |
||||||
|
// Recurse through the other elemenets
|
||||||
|
await Promise.all( |
||||||
|
Object.entries(queryInput).map(async ([queryKey, queryValue]) => { |
||||||
|
if ( |
||||||
|
queryValue != undefined && |
||||||
|
queryValue !== true && |
||||||
|
ldObject[queryKey] != undefined |
||||||
|
) { |
||||||
|
if (ldObject[queryKey] instanceof BasicLdSet) { |
||||||
|
await Promise.all( |
||||||
|
ldObject[queryKey].map(async (item) => { |
||||||
|
await exploreLinksRecursive( |
||||||
|
dataset, |
||||||
|
item, |
||||||
|
queryValue, |
||||||
|
encounteredDuringThisExploration, |
||||||
|
options, |
||||||
|
); |
||||||
|
}), |
||||||
|
); |
||||||
|
} else { |
||||||
|
await exploreLinksRecursive( |
||||||
|
dataset, |
||||||
|
ldObject[queryKey], |
||||||
|
queryValue, |
||||||
|
encounteredDuringThisExploration, |
||||||
|
options, |
||||||
|
); |
||||||
|
} |
||||||
|
} |
||||||
|
}), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Determines if a resource needs to be fetched based on given data |
||||||
|
*/ |
||||||
|
export function shouldFetchResource< |
||||||
|
Type extends LdoBase, |
||||||
|
Plugins extends ConnectedPlugin[], |
||||||
|
>( |
||||||
|
dataset: IConnectedLdoDataset<Plugins>, |
||||||
|
ldObject: Type, |
||||||
|
queryInput: LQInput<Type>, |
||||||
|
encounteredDuringThisExploration: Set<string>, |
||||||
|
): boolean { |
||||||
|
const linkedResourceUri: string | undefined = ldObject["@id"]; |
||||||
|
// If it's a blank node, no need to fetch
|
||||||
|
if (!linkedResourceUri) return false; |
||||||
|
const linkedResource = dataset.getResource(linkedResourceUri); |
||||||
|
// If we've already explored the resource in this exporation, do not fetch
|
||||||
|
if (encounteredDuringThisExploration.has(linkedResource.uri)) return false; |
||||||
|
|
||||||
|
return Object.entries(queryInput).some(([queryKey, queryValue]) => { |
||||||
|
// If value is undefined then no need to fetch
|
||||||
|
if (!queryValue) return false; |
||||||
|
// Always fetch if there's a set in the object
|
||||||
|
if (ldObject[queryKey] instanceof BasicLdSet) return true; |
||||||
|
// Fetch if a singleton set is not present
|
||||||
|
if (ldObject[queryKey] == undefined) return true; |
||||||
|
// Otherwise no need t to fetch
|
||||||
|
return false; |
||||||
|
}); |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
import { |
||||||
|
ContextUtil, |
||||||
|
JsonldDatasetProxyBuilder, |
||||||
|
} from "@ldo/jsonld-dataset-proxy"; |
||||||
|
import { LdoBuilder } from "@ldo/ldo"; |
||||||
|
import type { LdoBase, LdoDataset, ShapeType } from "@ldo/ldo"; |
||||||
|
import { TrackingProxyContext } from "./TrackingProxyContext"; |
||||||
|
import { defaultGraph } from "@rdfjs/data-model"; |
||||||
|
import type { nodeEventListener } from "@ldo/subscribable-dataset"; |
||||||
|
import type { Quad } from "@rdfjs/types"; |
||||||
|
|
||||||
|
/** |
||||||
|
* @internal |
||||||
|
* Creates a Linked Data Object builder that when creating linked data objects |
||||||
|
* it tracks when something that was read from it is updated and triggers some |
||||||
|
* action based on that. |
||||||
|
*/ |
||||||
|
export function createTrackingProxyBuilder<Type extends LdoBase>( |
||||||
|
dataset: LdoDataset, |
||||||
|
shapeType: ShapeType<Type>, |
||||||
|
onUpdate: nodeEventListener<Quad>, |
||||||
|
): LdoBuilder<Type> { |
||||||
|
// Remove all current subscriptions
|
||||||
|
// dataset.removeListenerFromAllEvents(onUpdate);
|
||||||
|
|
||||||
|
// Rebuild the LdoBuilder from scratch to inject TrackingProxyContext
|
||||||
|
const contextUtil = new ContextUtil(shapeType.context); |
||||||
|
const proxyContext = new TrackingProxyContext( |
||||||
|
{ |
||||||
|
dataset, |
||||||
|
contextUtil, |
||||||
|
writeGraphs: [defaultGraph()], |
||||||
|
languageOrdering: ["none", "en", "other"], |
||||||
|
}, |
||||||
|
onUpdate, |
||||||
|
); |
||||||
|
const builder = new LdoBuilder( |
||||||
|
new JsonldDatasetProxyBuilder(proxyContext), |
||||||
|
shapeType, |
||||||
|
); |
||||||
|
return builder; |
||||||
|
} |
@ -1,7 +1,7 @@ |
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */ |
/* eslint-disable @typescript-eslint/no-explicit-any */ |
||||||
import type { ConnectedContext } from "./ConnectedContext"; |
import type { ConnectedContext } from "./ConnectedContext"; |
||||||
import type { Resource } from "./Resource"; |
import type { Resource } from "../Resource"; |
||||||
import type { ErrorResult } from "./results/error/ErrorResult"; |
import type { ErrorResult } from "../results/error/ErrorResult"; |
||||||
|
|
||||||
/** |
/** |
||||||
* A ConnectedPlugin can be passed to a ConnectedDataset to allow it to connect |
* A ConnectedPlugin can be passed to a ConnectedDataset to allow it to connect |
@ -0,0 +1,15 @@ |
|||||||
|
import type { LdoBase, LdoBuilder } from "@ldo/ldo"; |
||||||
|
import type { ConnectedPlugin } from "./ConnectedPlugin"; |
||||||
|
import type { SubjectNode } from "@ldo/rdf-utils"; |
||||||
|
import type { ILinkQuery, LQInput } from "./ILinkQuery"; |
||||||
|
|
||||||
|
export interface IConnectedLdoBuilder< |
||||||
|
Type extends LdoBase, |
||||||
|
Plugins extends ConnectedPlugin[], |
||||||
|
> extends LdoBuilder<Type> { |
||||||
|
startLinkQuery<Input extends LQInput<Type>>( |
||||||
|
startingResource: Plugins[number]["types"]["resource"], |
||||||
|
startingSubject: SubjectNode | string, |
||||||
|
linkQueryInput: Input, |
||||||
|
): ILinkQuery<Type, Input>; |
||||||
|
} |
@ -0,0 +1,126 @@ |
|||||||
|
// This file is a stripped down version of a full-implmentation of a global
|
||||||
|
// query interface found here https://github.com/o-development/ldo-query/blob/main/lib/ShapeQuery.ts
|
||||||
|
// If I ever want to implement a global query interface, this is a good place
|
||||||
|
// to start.
|
||||||
|
|
||||||
|
import type { LdoBase, LdSet } from "@ldo/ldo"; |
||||||
|
// import { SolidProfileShapeShapeType } from "../../test/.ldo/solidProfile.shapeTypes";
|
||||||
|
// import type { SolidProfileShape } from "../../test/.ldo/solidProfile.typings";
|
||||||
|
|
||||||
|
/** |
||||||
|
* Link Query Input |
||||||
|
*/ |
||||||
|
export type LQInput<Type> = LQInputObject<Type>; |
||||||
|
|
||||||
|
export type LQInputObject<Type> = Partial<{ |
||||||
|
[key in Exclude<keyof Type, "@context">]: LQInputFlattenSet<Type[key]>; |
||||||
|
}>; |
||||||
|
|
||||||
|
export type LQInputSubSet<Type> = Type extends object |
||||||
|
? LQInputObject<Type> |
||||||
|
: true; |
||||||
|
|
||||||
|
export type LQInputFlattenSet<Type> = Type extends LdSet<infer SetSubType> |
||||||
|
? LQInputSubSet<SetSubType> |
||||||
|
: LQInputSubSet<Type>; |
||||||
|
|
||||||
|
/** |
||||||
|
* Link Query Input Default |
||||||
|
*/ |
||||||
|
// TODO: I don't remember why I need this. Delete if unneeded
|
||||||
|
// export type LQInputDefaultType<Type> = {
|
||||||
|
// [key in keyof Type]: Type[key] extends object ? undefined : true;
|
||||||
|
// };
|
||||||
|
|
||||||
|
// export type LQInputDefault<Type> =
|
||||||
|
// LQInputDefaultType<Type> extends LQInput<Type>
|
||||||
|
// ? LQInputDefaultType<Type>
|
||||||
|
// : never;
|
||||||
|
|
||||||
|
/** |
||||||
|
* Link Query Return |
||||||
|
*/ |
||||||
|
export type LQReturn<Type, Input extends LQInput<Type>> = LQReturnObject< |
||||||
|
Type, |
||||||
|
Input |
||||||
|
>; |
||||||
|
|
||||||
|
export type LQReturnObject<Type, Input extends LQInputObject<Type>> = { |
||||||
|
[key in Exclude< |
||||||
|
keyof Required<Type>, |
||||||
|
"@context" |
||||||
|
> as undefined extends Input[key] |
||||||
|
? never |
||||||
|
: key]: Input[key] extends LQInputFlattenSet<Type[key]> |
||||||
|
? undefined extends Type[key] |
||||||
|
? LQReturnExpandSet<Type[key], Input[key]> | undefined |
||||||
|
: LQReturnExpandSet<Type[key], Input[key]> |
||||||
|
: never; |
||||||
|
}; |
||||||
|
|
||||||
|
export type LQReturnSubSet<Type, Input> = Input extends LQInputSubSet<Type> |
||||||
|
? Input extends LQInputObject<Type> |
||||||
|
? Input extends true |
||||||
|
? Type |
||||||
|
: LQReturnObject<Type, Input> |
||||||
|
: Type |
||||||
|
: never; |
||||||
|
|
||||||
|
export type LQReturnExpandSet< |
||||||
|
Type, |
||||||
|
Input extends LQInputFlattenSet<Type>, |
||||||
|
> = NonNullable<Type> extends LdSet<infer SetSubType> |
||||||
|
? LdSet<LQReturnSubSet<SetSubType, Input>> |
||||||
|
: LQReturnSubSet<Type, Input>; |
||||||
|
|
||||||
|
export type ExpandDeep<T> = T extends LdSet<infer U> |
||||||
|
? LdSet<ExpandDeep<U>> // recursively expand sets
|
||||||
|
: T extends object |
||||||
|
? { [K in keyof T]: ExpandDeep<T[K]> } // recursively expand objects
|
||||||
|
: T; // base case (primitive types)
|
||||||
|
|
||||||
|
/** |
||||||
|
* ILinkQuery: Manages resources in a link query |
||||||
|
*/ |
||||||
|
export interface LinkQueryRunOptions { |
||||||
|
reload?: boolean; |
||||||
|
} |
||||||
|
|
||||||
|
export interface ILinkQuery<Type extends LdoBase, Input extends LQInput<Type>> { |
||||||
|
run( |
||||||
|
options?: LinkQueryRunOptions, |
||||||
|
): Promise<ExpandDeep<LQReturn<Type, Input>>>; |
||||||
|
subscribe(): Promise<string>; |
||||||
|
unsubscribe(subscriptionId: string): Promise<void>; |
||||||
|
unsubscribeAll(): Promise<void>; |
||||||
|
fromSubject(): ExpandDeep<LQReturn<Type, Input>>; |
||||||
|
} |
||||||
|
|
||||||
|
// function test<Type extends LdoBase, Input extends LQInput<Type>>(
|
||||||
|
// shapeType: ShapeType<Type>,
|
||||||
|
// input: Input,
|
||||||
|
// ): ExpandDeep<LQReturn<Type, Input>> {
|
||||||
|
// throw new Error("Not Implemented");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// type TestLQInput = {
|
||||||
|
// name: true;
|
||||||
|
// knows: {
|
||||||
|
// name: true;
|
||||||
|
// };
|
||||||
|
// };
|
||||||
|
|
||||||
|
// type testReturn = LQReturn<SolidProfileShape, TestLQInput>;
|
||||||
|
|
||||||
|
// type test2 = LQReturnSubSet<string | undefined, true>;
|
||||||
|
|
||||||
|
// type lqInputObject = LQInputObject<string | undefined>;
|
||||||
|
|
||||||
|
// type meh = TestLQInput extends true ? true : false;
|
||||||
|
|
||||||
|
// const thing = test(SolidProfileShapeShapeType, {
|
||||||
|
// name: true,
|
||||||
|
// knows: {
|
||||||
|
// name: true,
|
||||||
|
// },
|
||||||
|
// });
|
@ -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,71 @@ |
|||||||
|
import { ShapeType } from "@ldo/ldo"; |
||||||
|
import { solidProfileSchema } from "./solidProfile.schema"; |
||||||
|
import { solidProfileContext } from "./solidProfile.context"; |
||||||
|
import { |
||||||
|
SolidProfileShape, |
||||||
|
AddressShape, |
||||||
|
EmailShape, |
||||||
|
PhoneNumberShape, |
||||||
|
TrustedAppShape, |
||||||
|
RSAPublicKeyShape, |
||||||
|
} from "./solidProfile.typings"; |
||||||
|
|
||||||
|
/** |
||||||
|
* ============================================================================= |
||||||
|
* 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,121 @@ |
|||||||
|
PREFIX srs: <https://shaperepo.com/schemas/solidProfile#> |
||||||
|
PREFIX foaf: <http://xmlns.com/foaf/0.1/> |
||||||
|
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> |
||||||
|
PREFIX schem: <http://schema.org/> |
||||||
|
PREFIX vcard: <http://www.w3.org/2006/vcard/ns#> |
||||||
|
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> |
||||||
|
PREFIX acl: <http://www.w3.org/ns/auth/acl#> |
||||||
|
PREFIX cert: <http://www.w3.org/ns/auth/cert#> |
||||||
|
PREFIX ldp: <http://www.w3.org/ns/ldp#> |
||||||
|
PREFIX sp: <http://www.w3.org/ns/pim/space#> |
||||||
|
PREFIX solid: <http://www.w3.org/ns/solid/terms#> |
||||||
|
|
||||||
|
srs:SolidProfileShape EXTRA a { |
||||||
|
a [ schem:Person ] |
||||||
|
// rdfs:comment "Defines the node as a Person (from Schema.org)" ; |
||||||
|
a [ foaf:Person ] |
||||||
|
// rdfs:comment "Defines the node as a Person (from foaf)" ; |
||||||
|
vcard:fn xsd:string ? |
||||||
|
// rdfs:comment "The formatted name of a person. Example: John Smith" ; |
||||||
|
foaf:name xsd:string ? |
||||||
|
// rdfs:comment "An alternate way to define a person's name." ; |
||||||
|
vcard:hasAddress @srs:AddressShape * |
||||||
|
// rdfs:comment "The person's street address." ; |
||||||
|
vcard:hasEmail @srs:EmailShape * |
||||||
|
// rdfs:comment "The person's email." ; |
||||||
|
vcard:hasPhoto IRI ? |
||||||
|
// rdfs:comment "A link to the person's photo" ; |
||||||
|
foaf:img xsd:string ? |
||||||
|
// rdfs:comment "Photo link but in string form" ; |
||||||
|
vcard:hasTelephone @srs:PhoneNumberShape * |
||||||
|
// rdfs:comment "Person's telephone number" ; |
||||||
|
vcard:phone xsd:string ? |
||||||
|
// rdfs:comment "An alternative way to define a person's telephone number using a string" ; |
||||||
|
vcard:organization-name xsd:string ? |
||||||
|
// rdfs:comment "The name of the organization with which the person is affiliated" ; |
||||||
|
vcard:role xsd:string ? |
||||||
|
// rdfs:comment "The name of the person's role in their organization" ; |
||||||
|
acl:trustedApp @srs:TrustedAppShape * |
||||||
|
// rdfs:comment "A list of app origins that are trusted by this user" ; |
||||||
|
cert:key @srs:RSAPublicKeyShape * |
||||||
|
// rdfs:comment "A list of RSA public keys that are associated with private keys the user holds." ; |
||||||
|
ldp:inbox IRI |
||||||
|
// rdfs:comment "The user's LDP inbox to which apps can post notifications" ; |
||||||
|
sp:preferencesFile IRI ? |
||||||
|
// rdfs:comment "The user's preferences" ; |
||||||
|
sp:storage IRI * |
||||||
|
// rdfs:comment "The location of a Solid storage server related to this WebId" ; |
||||||
|
solid:account IRI ? |
||||||
|
// rdfs:comment "The user's account" ; |
||||||
|
solid:privateTypeIndex IRI * |
||||||
|
// rdfs:comment "A registry of all types used on the user's Pod (for private access only)" ; |
||||||
|
solid:publicTypeIndex IRI * |
||||||
|
// rdfs:comment "A registry of all types used on the user's Pod (for public access)" ; |
||||||
|
foaf:knows @srs:SolidProfileShape * |
||||||
|
// rdfs:comment "A list of WebIds for all the people this user knows." ; |
||||||
|
} |
||||||
|
|
||||||
|
srs:AddressShape { |
||||||
|
vcard:country-name xsd:string ? |
||||||
|
// rdfs:comment "The name of the user's country of residence" ; |
||||||
|
vcard:locality xsd:string ? |
||||||
|
// rdfs:comment "The name of the user's locality (City, Town etc.) of residence" ; |
||||||
|
vcard:postal-code xsd:string ? |
||||||
|
// rdfs:comment "The user's postal code" ; |
||||||
|
vcard:region xsd:string ? |
||||||
|
// rdfs:comment "The name of the user's region (State, Province etc.) of residence" ; |
||||||
|
vcard:street-address xsd:string ? |
||||||
|
// rdfs:comment "The user's street address" ; |
||||||
|
} |
||||||
|
|
||||||
|
srs:EmailShape EXTRA a { |
||||||
|
a [ |
||||||
|
vcard:Dom |
||||||
|
vcard:Home |
||||||
|
vcard:ISDN |
||||||
|
vcard:Internet |
||||||
|
vcard:Intl |
||||||
|
vcard:Label |
||||||
|
vcard:Parcel |
||||||
|
vcard:Postal |
||||||
|
vcard:Pref |
||||||
|
vcard:Work |
||||||
|
vcard:X400 |
||||||
|
] ? |
||||||
|
// rdfs:comment "The type of email." ; |
||||||
|
vcard:value IRI |
||||||
|
// rdfs:comment "The value of an email as a mailto link (Example <mailto:jane@example.com>)" ; |
||||||
|
} |
||||||
|
|
||||||
|
srs:PhoneNumberShape EXTRA a { |
||||||
|
a [ |
||||||
|
vcard:Dom |
||||||
|
vcard:Home |
||||||
|
vcard:ISDN |
||||||
|
vcard:Internet |
||||||
|
vcard:Intl |
||||||
|
vcard:Label |
||||||
|
vcard:Parcel |
||||||
|
vcard:Postal |
||||||
|
vcard:Pref |
||||||
|
vcard:Work |
||||||
|
vcard:X400 |
||||||
|
] ? |
||||||
|
// rdfs:comment "They type of Phone Number" ; |
||||||
|
vcard:value IRI |
||||||
|
// rdfs:comment "The value of a phone number as a tel link (Example <tel:555-555-5555>)" ; |
||||||
|
} |
||||||
|
|
||||||
|
srs:TrustedAppShape { |
||||||
|
acl:mode [acl:Append acl:Control acl:Read acl:Write] + |
||||||
|
// rdfs:comment "The level of access provided to this origin" ; |
||||||
|
acl:origin IRI |
||||||
|
// rdfs:comment "The app origin the user trusts" |
||||||
|
} |
||||||
|
|
||||||
|
srs:RSAPublicKeyShape { |
||||||
|
cert:modulus xsd:string |
||||||
|
// rdfs:comment "RSA Modulus" ; |
||||||
|
cert:exponent xsd:integer |
||||||
|
// rdfs:comment "RSA Exponent" ; |
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
import type { ResourceInfo } from "@ldo/test-solid-server"; |
||||||
|
|
||||||
|
export const BASE_CONTAINER = "http://localhost:3005/test-container/"; |
||||||
|
export const MAIN_PROFILE_URI = `${BASE_CONTAINER}mainProfile.ttl`; |
||||||
|
export const MAIN_PROFILE_SUBJECT = `${MAIN_PROFILE_URI}#me`; |
||||||
|
export const OTHER_PROFILE_URI = `${BASE_CONTAINER}otherProfile.ttl`; |
||||||
|
export const OTHER_PROFILE_SUBJECT = `${OTHER_PROFILE_URI}#me`; |
||||||
|
export const THIRD_PROFILE_URI = `${BASE_CONTAINER}thirdProfile.ttl`; |
||||||
|
export const THIRD_PROFILE_SUBJECT = `${THIRD_PROFILE_URI}#me`; |
||||||
|
|
||||||
|
export const linkTraversalData: ResourceInfo = { |
||||||
|
slug: "test-container/", |
||||||
|
isContainer: true, |
||||||
|
contains: [ |
||||||
|
{ |
||||||
|
slug: "mainProfile.ttl", |
||||||
|
isContainer: false, |
||||||
|
mimeType: "text/turtle", |
||||||
|
data: ` |
||||||
|
@prefix foaf: <http://xmlns.com/foaf/0.1/> . |
||||||
|
@prefix : <#> . |
||||||
|
|
||||||
|
:me a foaf:Person ; |
||||||
|
foaf:name "Main User" ; |
||||||
|
foaf:mbox <mailto:main@example.org> ; |
||||||
|
foaf:knows <http://localhost:3005/test-container/otherProfile.ttl#me> . |
||||||
|
`,
|
||||||
|
}, |
||||||
|
{ |
||||||
|
slug: "otherProfile.ttl", |
||||||
|
isContainer: false, |
||||||
|
mimeType: "text/turtle", |
||||||
|
data: ` |
||||||
|
@prefix foaf: <http://xmlns.com/foaf/0.1/> . |
||||||
|
@prefix : <#> . |
||||||
|
|
||||||
|
:me a foaf:Person ; |
||||||
|
foaf:name "Other User" ; |
||||||
|
foaf:mbox <mailto:other@example.org> ; |
||||||
|
foaf:knows <http://localhost:3005/test-container/mainProfile.ttl#me> . |
||||||
|
`,
|
||||||
|
}, |
||||||
|
{ |
||||||
|
slug: "thirdProfile.ttl", |
||||||
|
isContainer: false, |
||||||
|
mimeType: "text/turtle", |
||||||
|
data: ` |
||||||
|
@prefix foaf: <http://xmlns.com/foaf/0.1/> . |
||||||
|
@prefix : <#> . |
||||||
|
|
||||||
|
:me a foaf:Person ; |
||||||
|
foaf:name "Third User" ; |
||||||
|
foaf:mbox <mailto:third@example.org> ; |
||||||
|
foaf:knows <http://localhost:3005/test-container/mainProfile.ttl#me> . |
||||||
|
`,
|
||||||
|
}, |
||||||
|
], |
||||||
|
}; |
@ -0,0 +1,216 @@ |
|||||||
|
import type { ConnectedLdoDataset } from "../src/ConnectedLdoDataset"; |
||||||
|
import { changeData, commitData, createConnectedLdoDataset } from "../src"; |
||||||
|
import { |
||||||
|
solidConnectedPlugin, |
||||||
|
type SolidConnectedPlugin, |
||||||
|
} from "@ldo/connected-solid"; |
||||||
|
import { setupServer } from "@ldo/test-solid-server"; |
||||||
|
import { |
||||||
|
linkTraversalData, |
||||||
|
MAIN_PROFILE_SUBJECT, |
||||||
|
MAIN_PROFILE_URI, |
||||||
|
OTHER_PROFILE_URI, |
||||||
|
THIRD_PROFILE_SUBJECT, |
||||||
|
THIRD_PROFILE_URI, |
||||||
|
} from "./LinkTraversalData"; |
||||||
|
import { SolidProfileShapeShapeType } from "./.ldo/solidProfile.shapeTypes"; |
||||||
|
import { wait } from "./util/wait"; |
||||||
|
|
||||||
|
describe("Link Traversal", () => { |
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
let solidLdoDataset: ConnectedLdoDataset<SolidConnectedPlugin[]>; |
||||||
|
|
||||||
|
const s = setupServer(3005, linkTraversalData); |
||||||
|
|
||||||
|
beforeEach(async () => { |
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
solidLdoDataset = createConnectedLdoDataset([solidConnectedPlugin]); |
||||||
|
solidLdoDataset.setContext("solid", { fetch: s.fetchMock }); |
||||||
|
}); |
||||||
|
|
||||||
|
it("does a simple run to traverse data", async () => { |
||||||
|
const mainProfileResource = solidLdoDataset.getResource(MAIN_PROFILE_URI); |
||||||
|
const data = await solidLdoDataset |
||||||
|
.usingType(SolidProfileShapeShapeType) |
||||||
|
.startLinkQuery(mainProfileResource, MAIN_PROFILE_SUBJECT, { |
||||||
|
name: true, |
||||||
|
knows: { |
||||||
|
name: true, |
||||||
|
}, |
||||||
|
}) |
||||||
|
.run(); |
||||||
|
const resourceUris = solidLdoDataset |
||||||
|
.getResources() |
||||||
|
.map((resource) => resource.uri); |
||||||
|
expect(resourceUris.length).toBe(3); |
||||||
|
expect(resourceUris).toContain(MAIN_PROFILE_URI); |
||||||
|
expect(resourceUris).toContain(OTHER_PROFILE_URI); |
||||||
|
expect(data.name).toBe("Main User"); |
||||||
|
expect(data.knows?.toArray()[0].name).toBe("Other User"); |
||||||
|
}); |
||||||
|
|
||||||
|
it("handles subscriptions if data changes locally", async () => { |
||||||
|
const mainProfileResource = solidLdoDataset.getResource(MAIN_PROFILE_URI); |
||||||
|
const linkQuery = solidLdoDataset |
||||||
|
.usingType(SolidProfileShapeShapeType) |
||||||
|
.startLinkQuery(mainProfileResource, MAIN_PROFILE_SUBJECT, { |
||||||
|
name: true, |
||||||
|
knows: { |
||||||
|
name: true, |
||||||
|
}, |
||||||
|
}); |
||||||
|
await linkQuery.subscribe(); |
||||||
|
|
||||||
|
// Should have regular information
|
||||||
|
let mainProfile = solidLdoDataset |
||||||
|
.usingType(SolidProfileShapeShapeType) |
||||||
|
.fromSubject(MAIN_PROFILE_SUBJECT); |
||||||
|
let resourceUris = solidLdoDataset |
||||||
|
.getResources() |
||||||
|
.map((resource) => resource.uri); |
||||||
|
expect(resourceUris.length).toBe(3); |
||||||
|
expect(resourceUris).toContain(MAIN_PROFILE_URI); |
||||||
|
expect(resourceUris).toContain(OTHER_PROFILE_URI); |
||||||
|
expect(mainProfile.name).toBe("Main User"); |
||||||
|
expect(mainProfile.knows?.size).toBe(1); |
||||||
|
expect(mainProfile.knows?.toArray()[0].name).toBe("Other User"); |
||||||
|
|
||||||
|
// Update to include a new document
|
||||||
|
const cMainProfile = changeData(mainProfile, mainProfileResource); |
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
cMainProfile.knows?.add({ "@id": THIRD_PROFILE_SUBJECT }); |
||||||
|
await commitData(cMainProfile); |
||||||
|
|
||||||
|
// Wait for 200ms to allow the other file to be fetched
|
||||||
|
await wait(200); |
||||||
|
|
||||||
|
// After the data is committed, the third profile should be present
|
||||||
|
mainProfile = solidLdoDataset |
||||||
|
.usingType(SolidProfileShapeShapeType) |
||||||
|
.fromSubject(MAIN_PROFILE_SUBJECT); |
||||||
|
resourceUris = solidLdoDataset |
||||||
|
.getResources() |
||||||
|
.map((resource) => resource.uri); |
||||||
|
expect(resourceUris.length).toBe(4); |
||||||
|
expect(resourceUris).toContain(MAIN_PROFILE_URI); |
||||||
|
expect(resourceUris).toContain(OTHER_PROFILE_URI); |
||||||
|
expect(resourceUris).toContain(THIRD_PROFILE_URI); |
||||||
|
expect(mainProfile.name).toBe("Main User"); |
||||||
|
expect(mainProfile.knows?.size).toBe(2); |
||||||
|
const knowNames = mainProfile.knows?.map((knowsPerson) => knowsPerson.name); |
||||||
|
expect(knowNames).toContain("Other User"); |
||||||
|
expect(knowNames).toContain("Third User"); |
||||||
|
|
||||||
|
// Unsubscribe
|
||||||
|
}); |
||||||
|
|
||||||
|
it.only("handles subscriptions if data changes on the Pod", async () => { |
||||||
|
const mainProfileResource = solidLdoDataset.getResource(MAIN_PROFILE_URI); |
||||||
|
const linkQuery = solidLdoDataset |
||||||
|
.usingType(SolidProfileShapeShapeType) |
||||||
|
.startLinkQuery(mainProfileResource, MAIN_PROFILE_SUBJECT, { |
||||||
|
name: true, |
||||||
|
knows: { |
||||||
|
name: true, |
||||||
|
}, |
||||||
|
}); |
||||||
|
|
||||||
|
const unsubscribeId = await linkQuery.subscribe(); |
||||||
|
|
||||||
|
// Should have regular information
|
||||||
|
let mainProfile = solidLdoDataset |
||||||
|
.usingType(SolidProfileShapeShapeType) |
||||||
|
.fromSubject(MAIN_PROFILE_SUBJECT); |
||||||
|
let resourceUris = solidLdoDataset |
||||||
|
.getResources() |
||||||
|
.map((resource) => resource.uri); |
||||||
|
expect(resourceUris.length).toBe(3); |
||||||
|
expect(resourceUris).toContain(MAIN_PROFILE_URI); |
||||||
|
expect(resourceUris).toContain(OTHER_PROFILE_URI); |
||||||
|
expect(mainProfile.name).toBe("Main User"); |
||||||
|
expect(mainProfile.knows?.size).toBe(1); |
||||||
|
expect(mainProfile.knows?.toArray()[0].name).toBe("Other User"); |
||||||
|
|
||||||
|
let subscribedResources = linkQuery |
||||||
|
.getSubscribedResources() |
||||||
|
.map((resource) => resource.uri); |
||||||
|
expect(subscribedResources.length).toBe(2); |
||||||
|
expect(subscribedResources).toContain(MAIN_PROFILE_URI); |
||||||
|
expect(subscribedResources).toContain(OTHER_PROFILE_URI); |
||||||
|
|
||||||
|
// Update data on the Pod
|
||||||
|
await s.authFetch(MAIN_PROFILE_URI, { |
||||||
|
method: "PATCH", |
||||||
|
body: "INSERT DATA { <http://localhost:3005/test-container/mainProfile.ttl#me> <http://xmlns.com/foaf/0.1/knows> <http://localhost:3005/test-container/thirdProfile.ttl#me> . }", |
||||||
|
headers: { |
||||||
|
"Content-Type": "application/sparql-update", |
||||||
|
}, |
||||||
|
}); |
||||||
|
await wait(1000); |
||||||
|
|
||||||
|
// After the data is committed, the third profile should be present
|
||||||
|
mainProfile = solidLdoDataset |
||||||
|
.usingType(SolidProfileShapeShapeType) |
||||||
|
.fromSubject(MAIN_PROFILE_SUBJECT); |
||||||
|
resourceUris = solidLdoDataset |
||||||
|
.getResources() |
||||||
|
.map((resource) => resource.uri); |
||||||
|
expect(resourceUris.length).toBe(4); |
||||||
|
expect(resourceUris).toContain(MAIN_PROFILE_URI); |
||||||
|
expect(resourceUris).toContain(OTHER_PROFILE_URI); |
||||||
|
expect(resourceUris).toContain(THIRD_PROFILE_URI); |
||||||
|
expect(mainProfile.name).toBe("Main User"); |
||||||
|
expect(mainProfile.knows?.size).toBe(2); |
||||||
|
const knowNames = mainProfile.knows?.map((knowsPerson) => knowsPerson.name); |
||||||
|
expect(knowNames).toContain("Other User"); |
||||||
|
expect(knowNames).toContain("Third User"); |
||||||
|
|
||||||
|
subscribedResources = linkQuery |
||||||
|
.getSubscribedResources() |
||||||
|
.map((resource) => resource.uri); |
||||||
|
expect(subscribedResources.length).toBe(3); |
||||||
|
expect(subscribedResources).toContain(MAIN_PROFILE_URI); |
||||||
|
expect(subscribedResources).toContain(OTHER_PROFILE_URI); |
||||||
|
expect(subscribedResources).toContain(THIRD_PROFILE_URI); |
||||||
|
|
||||||
|
// Unsubscribe
|
||||||
|
await linkQuery.unsubscribe(unsubscribeId); |
||||||
|
|
||||||
|
await wait(200); |
||||||
|
|
||||||
|
s.fetchMock.mockClear(); |
||||||
|
|
||||||
|
// Does not update when unsubscribed
|
||||||
|
await s.authFetch(MAIN_PROFILE_URI, { |
||||||
|
method: "PATCH", |
||||||
|
body: "INSERT DATA { <http://localhost:3005/test-container/mainProfile.ttl#me> <http://xmlns.com/foaf/0.1/knows> <http://localhost:3005/test-container/fourthProfile.ttl#me> . }", |
||||||
|
headers: { |
||||||
|
"Content-Type": "application/sparql-update", |
||||||
|
}, |
||||||
|
}); |
||||||
|
await wait(1000); |
||||||
|
|
||||||
|
expect(s.fetchMock).not.toHaveBeenCalled(); |
||||||
|
subscribedResources = linkQuery |
||||||
|
.getSubscribedResources() |
||||||
|
.map((resource) => resource.uri); |
||||||
|
expect(subscribedResources.length).toBe(0); |
||||||
|
|
||||||
|
// Check that all resources are unsubscribed from notifications
|
||||||
|
const resources = solidLdoDataset.getResources(); |
||||||
|
resources.forEach((resource) => { |
||||||
|
expect(resource.isSubscribedToNotifications()).toBe(false); |
||||||
|
}); |
||||||
|
|
||||||
|
const cMainProfile = changeData(mainProfile, mainProfileResource); |
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
cMainProfile.knows?.add({ |
||||||
|
"@id": "http://localhost:3005/test-container/fifthProfile.ttl#me", |
||||||
|
}); |
||||||
|
await commitData(cMainProfile); |
||||||
|
}); |
||||||
|
}); |
@ -1,73 +0,0 @@ |
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */ |
|
||||||
import EventEmitter from "events"; |
|
||||||
import type { ResourceError } from "../src"; |
|
||||||
import { |
|
||||||
Unfetched, |
|
||||||
type ConnectedResult, |
|
||||||
type Resource, |
|
||||||
type ResourceEventEmitter, |
|
||||||
} from "../src"; |
|
||||||
import type { DatasetChanges } from "@ldo/rdf-utils"; |
|
||||||
import type { ReadSuccess } from "../src/results/success/ReadSuccess"; |
|
||||||
import type { UpdateSuccess } from "../src/results/success/UpdateSuccess"; |
|
||||||
|
|
||||||
export class MockResouce |
|
||||||
extends (EventEmitter as new () => ResourceEventEmitter) |
|
||||||
implements Resource |
|
||||||
{ |
|
||||||
isError = false as const; |
|
||||||
uri: string; |
|
||||||
type = "mock" as const; |
|
||||||
status: ConnectedResult; |
|
||||||
|
|
||||||
constructor(uri: string) { |
|
||||||
super(); |
|
||||||
this.uri = uri; |
|
||||||
this.status = new Unfetched(this); |
|
||||||
} |
|
||||||
|
|
||||||
isLoading(): boolean { |
|
||||||
throw new Error("Method not implemented."); |
|
||||||
} |
|
||||||
isFetched(): boolean { |
|
||||||
throw new Error("Method not implemented."); |
|
||||||
} |
|
||||||
isUnfetched(): boolean { |
|
||||||
throw new Error("Method not implemented."); |
|
||||||
} |
|
||||||
isDoingInitialFetch(): boolean { |
|
||||||
throw new Error("Method not implemented."); |
|
||||||
} |
|
||||||
isPresent(): boolean | undefined { |
|
||||||
throw new Error("Method not implemented."); |
|
||||||
} |
|
||||||
isAbsent(): boolean | undefined { |
|
||||||
throw new Error("Method not implemented."); |
|
||||||
} |
|
||||||
isSubscribedToNotifications(): boolean { |
|
||||||
throw new Error("Method not implemented."); |
|
||||||
} |
|
||||||
read(): Promise<ReadSuccess<any> | ResourceError<any>> { |
|
||||||
throw new Error("Method not implemented."); |
|
||||||
} |
|
||||||
readIfUnfetched(): Promise<ReadSuccess<any> | ResourceError<any>> { |
|
||||||
throw new Error("Method not implemented."); |
|
||||||
} |
|
||||||
update( |
|
||||||
_datasetChanges: DatasetChanges, |
|
||||||
): Promise<UpdateSuccess<any> | ResourceError<any>> { |
|
||||||
throw new Error("Method not implemented."); |
|
||||||
} |
|
||||||
subscribeToNotifications(_callbacks?: { |
|
||||||
onNotification: (message: any) => void; |
|
||||||
onNotificationError: (err: Error) => void; |
|
||||||
}): Promise<string> { |
|
||||||
throw new Error("Method not implemented."); |
|
||||||
} |
|
||||||
unsubscribeFromNotifications(_subscriptionId: string): Promise<void> { |
|
||||||
throw new Error("Method not implemented."); |
|
||||||
} |
|
||||||
unsubscribeFromAllNotifications(): Promise<void> { |
|
||||||
throw new Error("Method not implemented."); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,59 @@ |
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */ |
||||||
|
import EventEmitter from "events"; |
||||||
|
import type { ResourceError } from "../../src"; |
||||||
|
import { |
||||||
|
Unfetched, |
||||||
|
type ConnectedResult, |
||||||
|
type Resource, |
||||||
|
type ResourceEventEmitter, |
||||||
|
} from "../../src"; |
||||||
|
import type { DatasetChanges } from "@ldo/rdf-utils"; |
||||||
|
import type { ReadSuccess } from "../../src/results/success/ReadSuccess"; |
||||||
|
import type { UpdateSuccess } from "../../src/results/success/UpdateSuccess"; |
||||||
|
|
||||||
|
export class MockResource |
||||||
|
extends (EventEmitter as new () => ResourceEventEmitter) |
||||||
|
implements Resource |
||||||
|
{ |
||||||
|
isError = false as const; |
||||||
|
uri: string; |
||||||
|
type = "mock" as const; |
||||||
|
status: ConnectedResult; |
||||||
|
|
||||||
|
constructor(uri: string) { |
||||||
|
super(); |
||||||
|
this.uri = uri; |
||||||
|
this.status = new Unfetched(this); |
||||||
|
} |
||||||
|
|
||||||
|
isLoading = jest.fn<boolean, []>(); |
||||||
|
isFetched = jest.fn<boolean, []>(); |
||||||
|
isUnfetched = jest.fn<boolean, []>(); |
||||||
|
isDoingInitialFetch = jest.fn<boolean, []>(); |
||||||
|
isPresent = jest.fn<boolean | undefined, []>(); |
||||||
|
isAbsent = jest.fn<boolean | undefined, []>(); |
||||||
|
isSubscribedToNotifications = jest.fn<boolean, []>(); |
||||||
|
|
||||||
|
read = jest.fn<Promise<ReadSuccess<any> | ResourceError<any>>, []>(); |
||||||
|
readIfUnfetched = jest.fn< |
||||||
|
Promise<ReadSuccess<any> | ResourceError<any>>, |
||||||
|
[] |
||||||
|
>(); |
||||||
|
update = jest.fn< |
||||||
|
Promise<UpdateSuccess<any> | ResourceError<any>>, |
||||||
|
[DatasetChanges] |
||||||
|
>(); |
||||||
|
|
||||||
|
subscribeToNotifications = jest.fn< |
||||||
|
Promise<string>, |
||||||
|
[ |
||||||
|
{ |
||||||
|
onNotification: (message: any) => void; |
||||||
|
onNotificationError: (err: Error) => void; |
||||||
|
}?, |
||||||
|
] |
||||||
|
>(); |
||||||
|
|
||||||
|
unsubscribeFromNotifications = jest.fn<Promise<void>, [string]>(); |
||||||
|
unsubscribeFromAllNotifications = jest.fn<Promise<void>, []>(); |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
export async function wait(time: number) { |
||||||
|
return new Promise((resolve) => setTimeout(resolve, time)); |
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
import type { |
||||||
|
ConnectedLdoDataset, |
||||||
|
ConnectedPlugin, |
||||||
|
ExpandDeep, |
||||||
|
LQInput, |
||||||
|
LQReturn, |
||||||
|
ResourceLinkQuery, |
||||||
|
} from "@ldo/connected"; |
||||||
|
import type { LdoBase, LdoBuilder, ShapeType } from "@ldo/ldo"; |
||||||
|
import type { SubjectNode } from "@ldo/rdf-utils"; |
||||||
|
import { useCallback, useEffect, useRef, useState } from "react"; |
||||||
|
import { useTrackingProxy } from "../util/useTrackingProxy"; |
||||||
|
|
||||||
|
/** |
||||||
|
* @internal |
||||||
|
* |
||||||
|
* Creates a useMatchSubject function. |
||||||
|
*/ |
||||||
|
export function createUseLinkQuery<Plugins extends ConnectedPlugin[]>( |
||||||
|
dataset: ConnectedLdoDataset<Plugins>, |
||||||
|
) { |
||||||
|
/** |
||||||
|
* Returns an array of matching linked data objects. Triggers a rerender if |
||||||
|
* the data is updated. |
||||||
|
*/ |
||||||
|
return function useQueryLink< |
||||||
|
Type extends LdoBase, |
||||||
|
QueryInput extends LQInput<Type>, |
||||||
|
>( |
||||||
|
shapeType: ShapeType<Type>, |
||||||
|
startingResource: string, |
||||||
|
startingSubject: SubjectNode | string, |
||||||
|
linkQuery: QueryInput, |
||||||
|
): ExpandDeep<LQReturn<Type, QueryInput>> | undefined { |
||||||
|
const linkQueryRef = useRef< |
||||||
|
ResourceLinkQuery<Type, QueryInput, Plugins> | undefined |
||||||
|
>(); |
||||||
|
|
||||||
|
const [isLoading, setIsLoading] = useState(true); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (linkQueryRef.current) { |
||||||
|
linkQueryRef.current.unsubscribeAll(); |
||||||
|
} |
||||||
|
const resource = dataset.getResource(startingResource); |
||||||
|
setIsLoading(true); |
||||||
|
linkQueryRef.current = dataset |
||||||
|
.usingType(shapeType) |
||||||
|
.startLinkQuery(resource, startingSubject, linkQuery); |
||||||
|
|
||||||
|
linkQueryRef.current.subscribe().then(() => setIsLoading(false)); |
||||||
|
|
||||||
|
return () => { |
||||||
|
linkQueryRef.current?.unsubscribeAll(); |
||||||
|
}; |
||||||
|
}, [shapeType, startingResource, startingSubject, linkQuery]); |
||||||
|
|
||||||
|
const fromSubject = useCallback( |
||||||
|
(builder: LdoBuilder<Type>) => { |
||||||
|
if (!startingSubject) return; |
||||||
|
return builder.fromSubject(startingSubject); |
||||||
|
}, |
||||||
|
[startingSubject], |
||||||
|
); |
||||||
|
|
||||||
|
const linkedDataObject = useTrackingProxy(shapeType, fromSubject, dataset); |
||||||
|
|
||||||
|
return isLoading |
||||||
|
? undefined |
||||||
|
: (linkedDataObject as unknown as ExpandDeep<LQReturn<Type, QueryInput>>); |
||||||
|
}; |
||||||
|
} |
@ -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,71 @@ |
|||||||
|
import { ShapeType } from "@ldo/ldo"; |
||||||
|
import { solidProfileSchema } from "./solidProfile.schema"; |
||||||
|
import { solidProfileContext } from "./solidProfile.context"; |
||||||
|
import { |
||||||
|
SolidProfileShape, |
||||||
|
AddressShape, |
||||||
|
EmailShape, |
||||||
|
PhoneNumberShape, |
||||||
|
TrustedAppShape, |
||||||
|
RSAPublicKeyShape, |
||||||
|
} from "./solidProfile.typings"; |
||||||
|
|
||||||
|
/** |
||||||
|
* ============================================================================= |
||||||
|
* 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,7 @@ |
|||||||
|
@prefix foaf: <http://xmlns.com/foaf/0.1/> . |
||||||
|
@prefix : <#> . |
||||||
|
|
||||||
|
:me a foaf:Person ; |
||||||
|
foaf:name "Main User" ; |
||||||
|
foaf:mbox <mailto:main@example.org> ; |
||||||
|
foaf:knows <http://localhost:3002/example/link-query/other-profile.ttl#me> . |
@ -0,0 +1,7 @@ |
|||||||
|
@prefix foaf: <http://xmlns.com/foaf/0.1/> . |
||||||
|
@prefix : <#> . |
||||||
|
|
||||||
|
:me a foaf:Person ; |
||||||
|
foaf:name "Other User" ; |
||||||
|
foaf:mbox <mailto:other@example.org> ; |
||||||
|
foaf:knows <http://localhost:3002/example/link-query/main-profile.ttl#me> . |
@ -0,0 +1,7 @@ |
|||||||
|
@prefix foaf: <http://xmlns.com/foaf/0.1/> . |
||||||
|
@prefix : <#> . |
||||||
|
|
||||||
|
:me a foaf:Person ; |
||||||
|
foaf:name "Third User" ; |
||||||
|
foaf:mbox <mailto:third@example.org> ; |
||||||
|
foaf:knows <http://localhost:3002/example/link-query/main-profile.ttl#me> . |
@ -0,0 +1,5 @@ |
|||||||
|
{ |
||||||
|
"extends": [ |
||||||
|
"../../.eslintrc" |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,2 @@ |
|||||||
|
node_modules |
||||||
|
*/data |
@ -0,0 +1,21 @@ |
|||||||
|
MIT License |
||||||
|
|
||||||
|
Copyright (c) 2023 Jackson Morgan |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||||
|
of this software and associated documentation files (the "Software"), to deal |
||||||
|
in the Software without restriction, including without limitation the rights |
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||||
|
copies of the Software, and to permit persons to whom the Software is |
||||||
|
furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all |
||||||
|
copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||||
|
SOFTWARE. |
@ -0,0 +1,17 @@ |
|||||||
|
# @ldo/test-solid-server |
||||||
|
|
||||||
|
This is a reusable Solid Server to be used in Jest integration tests. |
||||||
|
|
||||||
|
## Setup |
||||||
|
|
||||||
|
Install cross-env |
||||||
|
|
||||||
|
``` |
||||||
|
npm i --save-dev cross-env |
||||||
|
``` |
||||||
|
|
||||||
|
Use the following to run your tests |
||||||
|
|
||||||
|
``` |
||||||
|
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage", |
||||||
|
``` |
@ -0,0 +1,34 @@ |
|||||||
|
{ |
||||||
|
"name": "@ldo/test-solid-server", |
||||||
|
"version": "1.0.0-alpha.9", |
||||||
|
"description": "A solid server to be used in jest tests", |
||||||
|
"main": "dist/index.js", |
||||||
|
"scripts": { |
||||||
|
"build": "tsc --project tsconfig.build.json && npm run copy-configs", |
||||||
|
"prepublishOnly": "npm run build", |
||||||
|
"copy-configs": "cp -r src/configs dist/configs", |
||||||
|
"lint": "eslint src/** --fix --no-error-on-unmatched-pattern" |
||||||
|
}, |
||||||
|
"repository": { |
||||||
|
"type": "git", |
||||||
|
"url": "git+https://github.com/o-development/ldo.git" |
||||||
|
}, |
||||||
|
"author": "Jackson Morgan", |
||||||
|
"license": "MIT", |
||||||
|
"bugs": { |
||||||
|
"url": "https://github.com/o-development/ldo/issues" |
||||||
|
}, |
||||||
|
"homepage": "https://github.com/o-development/ldo/tree/main/packages/solid#readme", |
||||||
|
"dependencies": { |
||||||
|
"@inrupt/solid-client-authn-core": "^2.2.6", |
||||||
|
"@solid/community-server": "^7.1.3", |
||||||
|
"cross-env": "^7.0.3" |
||||||
|
}, |
||||||
|
"files": [ |
||||||
|
"dist", |
||||||
|
"src" |
||||||
|
], |
||||||
|
"publishConfig": { |
||||||
|
"access": "public" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
{ |
||||||
|
"@context": "https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^7.0.0/components/context.jsonld", |
||||||
|
"import": [ |
||||||
|
"css:config/app/init/initialize-root.json", |
||||||
|
"css:config/app/main/default.json", |
||||||
|
"css:config/app/variables/default.json", |
||||||
|
"css:config/http/handler/default.json", |
||||||
|
"css:config/http/middleware/default.json", |
||||||
|
"css:config/http/notifications/webhooks.json", |
||||||
|
"css:config/http/server-factory/http.json", |
||||||
|
"css:config/http/static/default.json", |
||||||
|
"css:config/identity/access/public.json", |
||||||
|
"css:config/identity/email/default.json", |
||||||
|
"css:config/identity/handler/no-accounts.json", |
||||||
|
"css:config/identity/oidc/default.json", |
||||||
|
"css:config/identity/ownership/token.json", |
||||||
|
"css:config/identity/pod/static.json", |
||||||
|
"css:config/ldp/authentication/dpop-bearer.json", |
||||||
|
"css:config/ldp/authorization/webacl.json", |
||||||
|
"css:config/ldp/handler/default.json", |
||||||
|
"css:config/ldp/metadata-parser/default.json", |
||||||
|
"css:config/ldp/metadata-writer/default.json", |
||||||
|
"css:config/ldp/modes/default.json", |
||||||
|
"css:config/storage/backend/file.json", |
||||||
|
"css:config/storage/key-value/resource-store.json", |
||||||
|
"css:config/storage/location/root.json", |
||||||
|
"css:config/storage/middleware/default.json", |
||||||
|
"css:config/util/auxiliary/acl.json", |
||||||
|
"css:config/util/identifiers/suffix.json", |
||||||
|
"css:config/util/index/default.json", |
||||||
|
"css:config/util/logging/winston.json", |
||||||
|
"css:config/util/representation-conversion/default.json", |
||||||
|
"css:config/util/resource-locker/file.json", |
||||||
|
"css:config/util/variables/default.json" |
||||||
|
], |
||||||
|
"@graph": [ |
||||||
|
{ |
||||||
|
"comment": [ |
||||||
|
"A Solid server that stores its resources on disk and uses WAC for authorization.", |
||||||
|
"No registration and the root container is initialized to allow full access for everyone so make sure to change this." |
||||||
|
] |
||||||
|
} |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,3 @@ |
|||||||
|
export * from "./createServer"; |
||||||
|
export * from "./setupTestServer"; |
||||||
|
export * from "./resourceUtils"; |
@ -0,0 +1,75 @@ |
|||||||
|
export type ResourceInfo = ContainerInfo | LeafInfo; |
||||||
|
|
||||||
|
interface ContainerInfo { |
||||||
|
slug: string; |
||||||
|
isContainer: true; |
||||||
|
shouldNotInit?: boolean; |
||||||
|
contains: (ContainerInfo | LeafInfo)[]; |
||||||
|
} |
||||||
|
|
||||||
|
interface LeafInfo { |
||||||
|
slug: string; |
||||||
|
isContainer: false; |
||||||
|
data: string; |
||||||
|
shouldNotInit?: boolean; |
||||||
|
mimeType: string; |
||||||
|
} |
||||||
|
|
||||||
|
export async function initResources( |
||||||
|
rootUri: string, |
||||||
|
resourceInfo: ResourceInfo, |
||||||
|
authFetch: typeof fetch, |
||||||
|
): Promise<void> { |
||||||
|
if (resourceInfo?.shouldNotInit) return; |
||||||
|
if (resourceInfo.isContainer) { |
||||||
|
await authFetch(rootUri, { |
||||||
|
method: "POST", |
||||||
|
headers: { |
||||||
|
link: '<http://www.w3.org/ns/ldp#Container>; rel="type"', |
||||||
|
slug: resourceInfo.slug, |
||||||
|
}, |
||||||
|
}); |
||||||
|
await Promise.all( |
||||||
|
resourceInfo.contains.map((subResourceInfo) => |
||||||
|
initResources( |
||||||
|
`${rootUri}${resourceInfo.slug}`, |
||||||
|
subResourceInfo, |
||||||
|
authFetch, |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
} else { |
||||||
|
await authFetch(`${rootUri}${resourceInfo.slug}`, { |
||||||
|
method: "PUT", |
||||||
|
headers: { |
||||||
|
"content-type": resourceInfo.mimeType, |
||||||
|
}, |
||||||
|
body: resourceInfo.data, |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export async function cleanResources( |
||||||
|
rootUri: string, |
||||||
|
resourceInfo: ResourceInfo, |
||||||
|
authFetch: typeof fetch, |
||||||
|
): Promise<void> { |
||||||
|
if (resourceInfo.isContainer) { |
||||||
|
await Promise.all( |
||||||
|
resourceInfo.contains.map((subResourceInfo) => |
||||||
|
cleanResources( |
||||||
|
`${rootUri}${resourceInfo.slug}`, |
||||||
|
subResourceInfo, |
||||||
|
authFetch, |
||||||
|
), |
||||||
|
), |
||||||
|
); |
||||||
|
await authFetch(`${rootUri}${resourceInfo.slug}`, { |
||||||
|
method: "DELETE", |
||||||
|
}); |
||||||
|
} else { |
||||||
|
await authFetch(`${rootUri}${resourceInfo.slug}`, { |
||||||
|
method: "DELETE", |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */ |
||||||
|
import type { App } from "@solid/community-server"; |
||||||
|
import { createApp } from "./createServer"; |
||||||
|
import path from "path"; |
||||||
|
import type { ResourceInfo } from "./resourceUtils"; |
||||||
|
import { cleanResources, initResources } from "./resourceUtils"; |
||||||
|
import { generateAuthFetch } from "./authFetch"; |
||||||
|
import fs from "fs/promises"; |
||||||
|
|
||||||
|
export function setupServer( |
||||||
|
port: number, |
||||||
|
resourceInfo: ResourceInfo, |
||||||
|
customConfigPath?: string, |
||||||
|
) { |
||||||
|
const data: { |
||||||
|
app: App; |
||||||
|
fetchMock: jest.Mock< |
||||||
|
Promise<Response>, |
||||||
|
[input: RequestInfo | URL, init?: RequestInit | undefined] |
||||||
|
>; |
||||||
|
authFetch: typeof fetch; |
||||||
|
rootUri: string; |
||||||
|
} = { |
||||||
|
rootUri: `http://localhost:${port}/`, |
||||||
|
} as any; |
||||||
|
|
||||||
|
let previousJestId: string | undefined; |
||||||
|
let previousNodeEnv: string | undefined; |
||||||
|
beforeAll(async () => { |
||||||
|
// Remove Jest ID so that community solid server doesn't use the Jest Import
|
||||||
|
previousJestId = process.env.JEST_WORKER_ID; |
||||||
|
previousNodeEnv = process.env.NODE_ENV; |
||||||
|
delete process.env.JEST_WORKER_ID; |
||||||
|
process.env.NODE_ENV = "other_test"; |
||||||
|
// Start up the server
|
||||||
|
data.app = await createApp(port, customConfigPath); |
||||||
|
await data.app.start(); |
||||||
|
data.authFetch = await generateAuthFetch(port); |
||||||
|
}); |
||||||
|
|
||||||
|
afterAll(async () => { |
||||||
|
data.app.stop(); |
||||||
|
process.env.JEST_WORKER_ID = previousJestId; |
||||||
|
process.env.NODE_ENV = previousNodeEnv; |
||||||
|
const testDataPath = path.join(__dirname, "./data"); |
||||||
|
await fs.rm(testDataPath, { recursive: true, force: true }); |
||||||
|
}); |
||||||
|
|
||||||
|
beforeEach(async () => { |
||||||
|
data.fetchMock = jest.fn(data.authFetch); |
||||||
|
// Create a new document called sample.ttl
|
||||||
|
await initResources(data.rootUri, resourceInfo, data.authFetch); |
||||||
|
}); |
||||||
|
|
||||||
|
afterEach(async () => { |
||||||
|
await cleanResources(data.rootUri, resourceInfo, data.authFetch); |
||||||
|
}); |
||||||
|
|
||||||
|
return data; |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
{ |
||||||
|
"extends": "../../tsconfig.base.json", |
||||||
|
"compilerOptions": { |
||||||
|
"outDir": "./dist" |
||||||
|
}, |
||||||
|
"include": [ |
||||||
|
"./src" |
||||||
|
], |
||||||
|
"exclude": [ |
||||||
|
"./dist", |
||||||
|
"./coverage" |
||||||
|
] |
||||||
|
} |
Loading…
Reference in new issue