commit
59a10acda1
@ -1,4 +1,4 @@ |
||||
{ |
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json", |
||||
"version": "0.0.1-alpha.29" |
||||
"version": "1.0.0-alpha.1" |
||||
} |
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,3 +0,0 @@ |
||||
{ |
||||
"extends": ["../../.eslintrc"] |
||||
} |
@ -1,23 +0,0 @@ |
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. |
||||
|
||||
# dependencies |
||||
/node_modules |
||||
/.pnp |
||||
.pnp.js |
||||
|
||||
# testing |
||||
/coverage |
||||
|
||||
# production |
||||
/build |
||||
|
||||
# misc |
||||
.DS_Store |
||||
.env.local |
||||
.env.development.local |
||||
.env.test.local |
||||
.env.production.local |
||||
|
||||
npm-debug.log* |
||||
yarn-debug.log* |
||||
yarn-error.log* |
@ -1,21 +0,0 @@ |
||||
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. |
@ -1,12 +0,0 @@ |
||||
# LDO Demo-React |
||||
|
||||
A demo app to show off the use of LDO. |
||||
|
||||
## Sponsorship |
||||
This project was made possible by a grant from NGI Zero Entrust via nlnet. Learn more on the [NLnet project page](https://nlnet.nl/project/SolidUsableApps/). |
||||
|
||||
[<img src="https://nlnet.nl/logo/banner.png" alt="nlnet foundation logo" width="300" />](https://nlnet.nl/) |
||||
[<img src="https://nlnet.nl/image/logos/NGI0Entrust_tag.svg" alt="NGI Zero Entrust Logo" width="300" />](https://nlnet.nl/) |
||||
|
||||
## Liscense |
||||
MIT |
@ -1,28 +0,0 @@ |
||||
// this file overrides the default CRA configurations (webpack, eslint, babel, etc)
|
||||
// Ingnore because config scripts can't use the import variable
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin"); |
||||
|
||||
module.exports = { |
||||
webpack: { |
||||
configure: (config) => { |
||||
// Remove ModuleScopePlugin which throws when we try to import something
|
||||
// outside of src/.
|
||||
config.resolve.plugins.pop(); |
||||
|
||||
// Resolve the path aliases.
|
||||
config.resolve.plugins.push(new TsconfigPathsPlugin()); |
||||
|
||||
// Let Babel compile outside of src/.
|
||||
const oneOfRule = config.module.rules.find((rule) => rule.oneOf); |
||||
const tsRule = oneOfRule.oneOf.find((rule) => |
||||
rule.test.toString().includes("ts|tsx"), |
||||
); |
||||
|
||||
tsRule.include = undefined; |
||||
tsRule.exclude = /node_modules/; |
||||
|
||||
return config; |
||||
}, |
||||
}, |
||||
}; |
@ -1,50 +0,0 @@ |
||||
{ |
||||
"name": "@ldo/demo-react", |
||||
"version": "0.0.1-alpha.29", |
||||
"dependencies": { |
||||
"@inrupt/solid-client-authn-browser": "^2.0.0", |
||||
"@ldo/solid-react": "^0.0.1-alpha.29", |
||||
"react": "^18.2.0", |
||||
"react-dom": "^18.2.0", |
||||
"react-router-dom": "^6.15.0", |
||||
"react-scripts": "5.0.1", |
||||
"uuid": "^9.0.1" |
||||
}, |
||||
"scripts": { |
||||
"start": "craco start", |
||||
"build": "craco build", |
||||
"eject": "react-scripts eject", |
||||
"lint": "eslint src/** --fix --no-error-on-unmatched-pattern", |
||||
"build:ldo": "ldo build --input src/.shapes --output src/.ldo" |
||||
}, |
||||
"eslintConfig": { |
||||
"extends": [ |
||||
"react-app", |
||||
"react-app/jest" |
||||
] |
||||
}, |
||||
"browserslist": { |
||||
"production": [ |
||||
">0.2%", |
||||
"not dead", |
||||
"not op_mini all" |
||||
], |
||||
"development": [ |
||||
"last 1 firefox version", |
||||
"last 1 chrome version", |
||||
"last 1 safari version" |
||||
] |
||||
}, |
||||
"devDependencies": { |
||||
"@craco/craco": "^7.1.0", |
||||
"@ldo/cli": "^0.0.1-alpha.29", |
||||
"@types/jsonld": "^1.5.9", |
||||
"@types/react": "^18.2.21", |
||||
"@types/shexj": "^2.1.4", |
||||
"tsconfig-paths-webpack-plugin": "^4.1.0" |
||||
}, |
||||
"gitHead": "c63f055aab22155b60a5fdee4172979b9c287dfa", |
||||
"publishConfig": { |
||||
"access": "public" |
||||
} |
||||
} |
@ -1,41 +0,0 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<meta charset="utf-8" /> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1" /> |
||||
<meta name="theme-color" content="#000000" /> |
||||
<meta |
||||
name="description" |
||||
content="Web site created using create-react-app" |
||||
/> |
||||
<!-- |
||||
manifest.json provides metadata used when your web app is installed on a |
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ |
||||
--> |
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> |
||||
<!-- |
||||
Notice the use of %PUBLIC_URL% in the tags above. |
||||
It will be replaced with the URL of the `public` folder during the build. |
||||
Only files inside the `public` folder can be referenced from the HTML. |
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will |
||||
work correctly both with client-side routing and a non-root public URL. |
||||
Learn how to configure a non-root public URL by running `npm run build`. |
||||
--> |
||||
<title>React App</title> |
||||
</head> |
||||
<body> |
||||
<noscript>You need to enable JavaScript to run this app.</noscript> |
||||
<div id="root"></div> |
||||
<!-- |
||||
This HTML file is a template. |
||||
If you open it directly in the browser, you will see an empty page. |
||||
|
||||
You can add webfonts, meta tags, or analytics to this file. |
||||
The build step will place the bundled scripts into the <body> tag. |
||||
|
||||
To begin the development, run `npm start` or `yarn start`. |
||||
To create a production bundle, use `npm run build` or `yarn build`. |
||||
--> |
||||
</body> |
||||
</html> |
@ -1,25 +0,0 @@ |
||||
{ |
||||
"short_name": "React App", |
||||
"name": "Create React App Sample", |
||||
"icons": [ |
||||
{ |
||||
"src": "favicon.ico", |
||||
"sizes": "64x64 32x32 24x24 16x16", |
||||
"type": "image/x-icon" |
||||
}, |
||||
{ |
||||
"src": "logo192.png", |
||||
"type": "image/png", |
||||
"sizes": "192x192" |
||||
}, |
||||
{ |
||||
"src": "logo512.png", |
||||
"type": "image/png", |
||||
"sizes": "512x512" |
||||
} |
||||
], |
||||
"start_url": ".", |
||||
"display": "standalone", |
||||
"theme_color": "#000000", |
||||
"background_color": "#ffffff" |
||||
} |
@ -1,3 +0,0 @@ |
||||
# https://www.robotstxt.org/robotstxt.html |
||||
User-agent: * |
||||
Disallow: |
@ -1,31 +0,0 @@ |
||||
import { ContextDefinition } from "jsonld"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* postContext: JSONLD Context for post |
||||
* ============================================================================= |
||||
*/ |
||||
export const postContext: ContextDefinition = { |
||||
type: { |
||||
"@id": "@type", |
||||
}, |
||||
SocialMediaPosting: "http://schema.org/SocialMediaPosting", |
||||
CreativeWork: "http://schema.org/CreativeWork", |
||||
Thing: "http://schema.org/Thing", |
||||
articleBody: { |
||||
"@id": "http://schema.org/articleBody", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
uploadDate: { |
||||
"@id": "http://schema.org/uploadDate", |
||||
"@type": "http://www.w3.org/2001/XMLSchema#date", |
||||
}, |
||||
image: { |
||||
"@id": "http://schema.org/image", |
||||
"@type": "@id", |
||||
}, |
||||
publisher: { |
||||
"@id": "http://schema.org/publisher", |
||||
"@type": "@id", |
||||
}, |
||||
}; |
@ -1,155 +0,0 @@ |
||||
import { Schema } from "shexj"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* postSchema: ShexJ Schema for post |
||||
* ============================================================================= |
||||
*/ |
||||
export const postSchema: Schema = { |
||||
type: "Schema", |
||||
shapes: [ |
||||
{ |
||||
id: "https://example.com/PostSh", |
||||
type: "ShapeDecl", |
||||
shapeExpr: { |
||||
type: "Shape", |
||||
expression: { |
||||
type: "EachOf", |
||||
expressions: [ |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
values: [ |
||||
"http://schema.org/SocialMediaPosting", |
||||
"http://schema.org/CreativeWork", |
||||
"http://schema.org/Thing", |
||||
], |
||||
}, |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://schema.org/articleBody", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#string", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#label", |
||||
object: { |
||||
value: "articleBody", |
||||
}, |
||||
}, |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "The actual body of the article. ", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://schema.org/uploadDate", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
datatype: "http://www.w3.org/2001/XMLSchema#date", |
||||
}, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#label", |
||||
object: { |
||||
value: "uploadDate", |
||||
}, |
||||
}, |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"Date when this media object was uploaded to this site.", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://schema.org/image", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
nodeKind: "iri", |
||||
}, |
||||
min: 0, |
||||
max: 1, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#label", |
||||
object: { |
||||
value: "image", |
||||
}, |
||||
}, |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"A media object that encodes this CreativeWork. This property is a synonym for encoding.", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
type: "TripleConstraint", |
||||
predicate: "http://schema.org/publisher", |
||||
valueExpr: { |
||||
type: "NodeConstraint", |
||||
nodeKind: "iri", |
||||
}, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#label", |
||||
object: { |
||||
value: "publisher", |
||||
}, |
||||
}, |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: "The publisher of the creative work.", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}, |
||||
annotations: [ |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#label", |
||||
object: { |
||||
value: "SocialMediaPost", |
||||
}, |
||||
}, |
||||
{ |
||||
type: "Annotation", |
||||
predicate: "http://www.w3.org/2000/01/rdf-schema#comment", |
||||
object: { |
||||
value: |
||||
"A post to a social media platform, including blog posts, tweets, Facebook posts, etc.", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
], |
||||
}; |
@ -1,19 +0,0 @@ |
||||
import { ShapeType } from "@ldo/ldo"; |
||||
import { postSchema } from "./post.schema"; |
||||
import { postContext } from "./post.context"; |
||||
import { PostSh } from "./post.typings"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* LDO ShapeTypes post |
||||
* ============================================================================= |
||||
*/ |
||||
|
||||
/** |
||||
* PostSh ShapeType |
||||
*/ |
||||
export const PostShShapeType: ShapeType<PostSh> = { |
||||
schema: postSchema, |
||||
shape: "https://example.com/PostSh", |
||||
context: postContext, |
||||
}; |
@ -1,45 +0,0 @@ |
||||
import { ContextDefinition } from "jsonld"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* Typescript Typings for post |
||||
* ============================================================================= |
||||
*/ |
||||
|
||||
/** |
||||
* PostSh Type |
||||
*/ |
||||
export interface PostSh { |
||||
"@id"?: string; |
||||
"@context"?: ContextDefinition; |
||||
type: |
||||
| { |
||||
"@id": "SocialMediaPosting"; |
||||
} |
||||
| { |
||||
"@id": "CreativeWork"; |
||||
} |
||||
| { |
||||
"@id": "Thing"; |
||||
}; |
||||
/** |
||||
* The actual body of the article. |
||||
*/ |
||||
articleBody?: string; |
||||
/** |
||||
* Date when this media object was uploaded to this site. |
||||
*/ |
||||
uploadDate: string; |
||||
/** |
||||
* A media object that encodes this CreativeWork. This property is a synonym for encoding. |
||||
*/ |
||||
image?: { |
||||
"@id": string; |
||||
}; |
||||
/** |
||||
* The publisher of the creative work. |
||||
*/ |
||||
publisher: { |
||||
"@id": string; |
||||
}; |
||||
} |
@ -1,154 +0,0 @@ |
||||
import { ContextDefinition } from "jsonld"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* solidProfileContext: JSONLD Context for solidProfile |
||||
* ============================================================================= |
||||
*/ |
||||
export const solidProfileContext: ContextDefinition = { |
||||
type: { |
||||
"@id": "@type", |
||||
}, |
||||
Person: "http://schema.org/Person", |
||||
Person2: "http://xmlns.com/foaf/0.1/Person", |
||||
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", |
||||
"@container": "@set", |
||||
}, |
||||
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", |
||||
"@container": "@set", |
||||
}, |
||||
Dom: "http://www.w3.org/2006/vcard/ns#Dom", |
||||
Home: "http://www.w3.org/2006/vcard/ns#Home", |
||||
ISDN: "http://www.w3.org/2006/vcard/ns#ISDN", |
||||
Internet: "http://www.w3.org/2006/vcard/ns#Internet", |
||||
Intl: "http://www.w3.org/2006/vcard/ns#Intl", |
||||
Label: "http://www.w3.org/2006/vcard/ns#Label", |
||||
Parcel: "http://www.w3.org/2006/vcard/ns#Parcel", |
||||
Postal: "http://www.w3.org/2006/vcard/ns#Postal", |
||||
Pref: "http://www.w3.org/2006/vcard/ns#Pref", |
||||
Work: "http://www.w3.org/2006/vcard/ns#Work", |
||||
X400: "http://www.w3.org/2006/vcard/ns#X400", |
||||
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", |
||||
"@container": "@set", |
||||
}, |
||||
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", |
||||
"@container": "@set", |
||||
}, |
||||
mode: { |
||||
"@id": "http://www.w3.org/ns/auth/acl#mode", |
||||
"@container": "@set", |
||||
}, |
||||
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", |
||||
"@container": "@set", |
||||
}, |
||||
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", |
||||
"@container": "@set", |
||||
}, |
||||
account: { |
||||
"@id": "http://www.w3.org/ns/solid/terms#account", |
||||
"@type": "@id", |
||||
}, |
||||
privateTypeIndex: { |
||||
"@id": "http://www.w3.org/ns/solid/terms#privateTypeIndex", |
||||
"@type": "@id", |
||||
"@container": "@set", |
||||
}, |
||||
publicTypeIndex: { |
||||
"@id": "http://www.w3.org/ns/solid/terms#publicTypeIndex", |
||||
"@type": "@id", |
||||
"@container": "@set", |
||||
}, |
||||
knows: { |
||||
"@id": "http://xmlns.com/foaf/0.1/knows", |
||||
"@type": "@id", |
||||
"@container": "@set", |
||||
}, |
||||
}; |
@ -1,749 +0,0 @@ |
||||
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", |
||||
}, |
||||
}, |
||||
], |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
}, |
||||
], |
||||
}; |
@ -1,71 +0,0 @@ |
||||
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, |
||||
}; |
@ -1,293 +0,0 @@ |
||||
import { ContextDefinition } from "jsonld"; |
||||
|
||||
/** |
||||
* ============================================================================= |
||||
* Typescript Typings for solidProfile |
||||
* ============================================================================= |
||||
*/ |
||||
|
||||
/** |
||||
* SolidProfileShape Type |
||||
*/ |
||||
export interface SolidProfileShape { |
||||
"@id"?: string; |
||||
"@context"?: ContextDefinition; |
||||
/** |
||||
* Defines the node as a Person (from Schema.org) | Defines the node as a Person (from foaf) |
||||
*/ |
||||
type: ( |
||||
| { |
||||
"@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?: AddressShape[]; |
||||
/** |
||||
* The person's email. |
||||
*/ |
||||
hasEmail?: EmailShape[]; |
||||
/** |
||||
* A link to the person's photo |
||||
*/ |
||||
hasPhoto?: { |
||||
"@id": string; |
||||
}; |
||||
/** |
||||
* Photo link but in string form |
||||
*/ |
||||
img?: string; |
||||
/** |
||||
* Person's telephone number |
||||
*/ |
||||
hasTelephone?: 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?: TrustedAppShape[]; |
||||
/** |
||||
* A list of RSA public keys that are associated with private keys the user holds. |
||||
*/ |
||||
key?: 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?: { |
||||
"@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?: { |
||||
"@id": string; |
||||
}[]; |
||||
/** |
||||
* A registry of all types used on the user's Pod (for public access) |
||||
*/ |
||||
publicTypeIndex?: { |
||||
"@id": string; |
||||
}[]; |
||||
/** |
||||
* A list of WebIds for all the people this user knows. |
||||
*/ |
||||
knows?: SolidProfileShape[]; |
||||
} |
||||
|
||||
/** |
||||
* AddressShape Type |
||||
*/ |
||||
export interface AddressShape { |
||||
"@id"?: string; |
||||
"@context"?: ContextDefinition; |
||||
/** |
||||
* 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"?: ContextDefinition; |
||||
/** |
||||
* 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"?: ContextDefinition; |
||||
/** |
||||
* 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"?: ContextDefinition; |
||||
/** |
||||
* The level of access provided to this origin |
||||
*/ |
||||
mode: ( |
||||
| { |
||||
"@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"?: ContextDefinition; |
||||
/** |
||||
* RSA Modulus |
||||
*/ |
||||
modulus: string; |
||||
/** |
||||
* RSA Exponent |
||||
*/ |
||||
exponent: number; |
||||
} |
@ -1,23 +0,0 @@ |
||||
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> |
||||
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> |
||||
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> |
||||
PREFIX ex: <https://example.com/> |
||||
BASE <http://schema.org/> |
||||
|
||||
ex:PostSh { |
||||
a [<SocialMediaPosting> <CreativeWork> <Thing>] ; |
||||
<articleBody> xsd:string? |
||||
// rdfs:label '''articleBody''' |
||||
// rdfs:comment '''The actual body of the article. ''' ; |
||||
<uploadDate> xsd:date |
||||
// rdfs:label '''uploadDate''' |
||||
// rdfs:comment '''Date when this media object was uploaded to this site.''' ; |
||||
<image> IRI ? |
||||
// rdfs:label '''image''' |
||||
// rdfs:comment '''A media object that encodes this CreativeWork. This property is a synonym for encoding.''' ; |
||||
<publisher> IRI |
||||
// rdfs:label '''publisher''' |
||||
// rdfs:comment '''The publisher of the creative work.''' ; |
||||
} |
||||
// rdfs:label '''SocialMediaPost''' |
||||
// rdfs:comment '''A post to a social media platform, including blog posts, tweets, Facebook posts, etc.''' |
@ -1,121 +0,0 @@ |
||||
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" ; |
||||
} |
@ -1,13 +0,0 @@ |
||||
import type { FunctionComponent } from "react"; |
||||
import React from "react"; |
||||
import { Router } from "./Layout"; |
||||
import { BrowserSolidLdoProvider } from "@ldo/solid-react"; |
||||
|
||||
const ProfileApp: FunctionComponent = () => { |
||||
return ( |
||||
<BrowserSolidLdoProvider> |
||||
<Router /> |
||||
</BrowserSolidLdoProvider> |
||||
); |
||||
}; |
||||
export default ProfileApp; |
@ -1,65 +0,0 @@ |
||||
import type { FunctionComponent } from "react"; |
||||
import React, { useCallback } from "react"; |
||||
import { |
||||
BrowserSolidLdoProvider, |
||||
useResource, |
||||
useSolidAuth, |
||||
useSubject, |
||||
} from "@ldo/solid-react"; |
||||
import { SolidProfileShapeShapeType } from "./.ldo/solidProfile.shapeTypes"; |
||||
import { changeData, commitData } from "@ldo/solid"; |
||||
|
||||
// The base component for the app
|
||||
const App: FunctionComponent = () => { |
||||
return ( |
||||
/* The application should be surrounded with the BrowserSolidLdoProvider |
||||
this will set up all the underlying infrastructure for the application */ |
||||
<BrowserSolidLdoProvider> |
||||
<Login /> |
||||
</BrowserSolidLdoProvider> |
||||
); |
||||
}; |
||||
|
||||
// A component that handles login
|
||||
const Login: FunctionComponent = () => { |
||||
// Get login information using the "useSolidAuth" hook
|
||||
const { login, logout, session } = useSolidAuth(); |
||||
|
||||
const onLogin = useCallback(() => { |
||||
const issuer = prompt("What is your Solid IDP?"); |
||||
// Call the "login" function to initiate login
|
||||
if (issuer) login(issuer); |
||||
}, []); |
||||
|
||||
// You can use session.isLoggedIn to check if the user is logged in
|
||||
if (session.isLoggedIn) { |
||||
return ( |
||||
<div> |
||||
{/* Get the user's webId from session.webId */} |
||||
<p>Logged in as {session.webId}</p> |
||||
{/* Use the logout function to log out */} |
||||
<button onClick={logout}>Log Out</button> |
||||
<Profile /> |
||||
</div> |
||||
); |
||||
} |
||||
return <button onClick={onLogin}>Log In</button>; |
||||
}; |
||||
|
||||
const Profile: FunctionComponent = () => { |
||||
const { session } = useSolidAuth(); |
||||
const resource = useResource(session.webId); |
||||
const profile = useSubject(SolidProfileShapeShapeType, session.webId); |
||||
|
||||
const onNameChange = useCallback(async (e) => { |
||||
// Ensure that the
|
||||
if (!profile || !resource) return; |
||||
const cProfile = changeData(profile, resource); |
||||
cProfile.name = e.target.value; |
||||
await commitData(cProfile); |
||||
}, []); |
||||
|
||||
return <input type="text" value={profile?.name} onChange={onNameChange} />; |
||||
}; |
||||
|
||||
export default App; |
@ -1,54 +0,0 @@ |
||||
import { useState } from "react"; |
||||
import type { FunctionComponent } from "react"; |
||||
import React from "react"; |
||||
import { useResource, useSolidAuth, useSubject } from "@ldo/solid-react"; |
||||
import { SolidProfileShapeShapeType } from "./.ldo/solidProfile.shapeTypes"; |
||||
import { Link } from "react-router-dom"; |
||||
|
||||
const DEFAULT_ISSUER = "https://solidweb.me"; |
||||
|
||||
export const LoggedInHeader: FunctionComponent<{ webId: string }> = ({ |
||||
webId, |
||||
}) => { |
||||
const webIdResource = useResource(webId); |
||||
const profile = useSubject(SolidProfileShapeShapeType, webId); |
||||
const { logout } = useSolidAuth(); |
||||
return ( |
||||
<> |
||||
<span> |
||||
Logged in as {webId}. Welcome{" "} |
||||
{webIdResource.isReading() ? "LOADING NAME" : profile.fn} |
||||
</span> |
||||
<button onClick={logout}>Log Out</button> |
||||
</> |
||||
); |
||||
}; |
||||
|
||||
export const Header: FunctionComponent = () => { |
||||
const [issuer, setIssuer] = useState(DEFAULT_ISSUER); |
||||
const { login, signUp, session } = useSolidAuth(); |
||||
return ( |
||||
<header> |
||||
<div style={{ display: "flex" }}> |
||||
{session.isLoggedIn ? ( |
||||
<LoggedInHeader webId={session.webId!} /> |
||||
) : ( |
||||
<> |
||||
<input |
||||
type="text" |
||||
value={issuer} |
||||
onChange={(e) => setIssuer(e.target.value)} |
||||
/> |
||||
<button onClick={() => login(issuer)}>Log In</button> |
||||
<button onClick={() => signUp(issuer)}>Sign Up</button> |
||||
</> |
||||
)} |
||||
</div> |
||||
<p> |
||||
<Link to="/">Blog</Link> |
||||
{" "} |
||||
<Link to="/profile">Profile</Link> |
||||
</p> |
||||
</header> |
||||
); |
||||
}; |
@ -1,50 +0,0 @@ |
||||
import { useSolidAuth } from "@ldo/solid-react"; |
||||
import React, { Fragment } from "react"; |
||||
import type { FunctionComponent } from "react"; |
||||
import { createBrowserRouter, Outlet, RouterProvider } from "react-router-dom"; |
||||
import { Blog } from "./blog/Blog"; |
||||
import { PostPage } from "./post/PostPage"; |
||||
import { Header } from "./Header"; |
||||
import { MainContainerProvider } from "./MainContainerProvider"; |
||||
import { Profile } from "./profile/Profile"; |
||||
|
||||
export const Layout: FunctionComponent = () => { |
||||
const { session } = useSolidAuth(); |
||||
return ( |
||||
<div> |
||||
<Header /> |
||||
<hr /> |
||||
<MainContainerProvider> |
||||
{session.isLoggedIn ? <Outlet /> : <Fragment />} |
||||
</MainContainerProvider> |
||||
</div> |
||||
); |
||||
}; |
||||
|
||||
const router = createBrowserRouter([ |
||||
{ |
||||
element: <Layout />, |
||||
children: [ |
||||
{ |
||||
path: "/", |
||||
element: <Blog />, |
||||
}, |
||||
{ |
||||
path: "/media/:uri", |
||||
element: <PostPage />, |
||||
}, |
||||
{ |
||||
path: "/profile", |
||||
element: <Profile />, |
||||
}, |
||||
], |
||||
}, |
||||
]); |
||||
|
||||
export const Router: FunctionComponent = () => { |
||||
const { ranInitialAuthCheck } = useSolidAuth(); |
||||
if (!ranInitialAuthCheck) { |
||||
return <p>Loading</p>; |
||||
} |
||||
return <RouterProvider router={router} />; |
||||
}; |
@ -1,73 +0,0 @@ |
||||
import React, { useState, useEffect, createContext } from "react"; |
||||
import type { FunctionComponent, PropsWithChildren } from "react"; |
||||
import type { Container, LeafUri } from "@ldo/solid"; |
||||
import { useSolidAuth, useLdo, useResource } from "@ldo/solid-react"; |
||||
|
||||
export const MainContainerContext = createContext<Container | undefined>( |
||||
undefined, |
||||
); |
||||
|
||||
const MainContainerSubProvider: FunctionComponent< |
||||
PropsWithChildren<{ uri?: string }> |
||||
> = ({ uri, children }) => { |
||||
const mainContainer = useResource(uri); |
||||
return ( |
||||
<MainContainerContext.Provider value={mainContainer as Container}> |
||||
{children} |
||||
</MainContainerContext.Provider> |
||||
); |
||||
}; |
||||
|
||||
export const MainContainerProvider: FunctionComponent<PropsWithChildren> = ({ |
||||
children, |
||||
}) => { |
||||
const [mainContainer, setMainContainer] = useState<Container | undefined>(); |
||||
const { session } = useSolidAuth(); |
||||
const { getResource } = useLdo(); |
||||
|
||||
useEffect(() => { |
||||
if (session.webId) { |
||||
const webIdResource = getResource(session.webId as LeafUri); |
||||
webIdResource.getRootContainer().then(async (rootContainer) => { |
||||
if (rootContainer.isError) { |
||||
alert(rootContainer.message); |
||||
return; |
||||
} |
||||
const mainContainer = getResource(`${rootContainer.uri}demo-react/`); |
||||
setMainContainer(mainContainer); |
||||
const createResult = await mainContainer.createIfAbsent(); |
||||
// Only set the access rules if the create was a success.
|
||||
if (createResult.type === "createSuccess") { |
||||
await mainContainer.setWac({ |
||||
public: { |
||||
read: true, |
||||
write: false, |
||||
append: false, |
||||
control: false, |
||||
}, |
||||
authenticated: { |
||||
read: true, |
||||
write: false, |
||||
append: false, |
||||
control: false, |
||||
}, |
||||
agent: { |
||||
[session.webId!]: { |
||||
read: true, |
||||
write: true, |
||||
append: true, |
||||
control: true, |
||||
}, |
||||
}, |
||||
}); |
||||
} |
||||
}); |
||||
} |
||||
}, [session.webId]); |
||||
|
||||
return ( |
||||
<MainContainerSubProvider uri={mainContainer?.uri}> |
||||
{children} |
||||
</MainContainerSubProvider> |
||||
); |
||||
}; |
@ -1,30 +0,0 @@ |
||||
import React, { Fragment, useContext } from "react"; |
||||
import type { FunctionComponent } from "react"; |
||||
import { MainContainerContext } from "../MainContainerProvider"; |
||||
import { Post } from "../post/Post"; |
||||
import { MakePost } from "./MakePost"; |
||||
|
||||
export const Blog: FunctionComponent = () => { |
||||
const mainContainer = useContext(MainContainerContext); |
||||
if (mainContainer === undefined) { |
||||
return <p>Loading...</p>; |
||||
} |
||||
if (mainContainer.isDoingInitialFetch()) { |
||||
return <p>Loading Blob</p>; |
||||
} |
||||
|
||||
return ( |
||||
<div> |
||||
<div> |
||||
<MakePost mainContainer={mainContainer} /> |
||||
</div> |
||||
<hr /> |
||||
{mainContainer.children().map((child) => ( |
||||
<Fragment key={child.uri}> |
||||
<Post uri={child.uri} /> |
||||
<hr /> |
||||
</Fragment> |
||||
))} |
||||
</div> |
||||
); |
||||
}; |
@ -1,92 +0,0 @@ |
||||
import React, { useCallback, useState, useRef } from "react"; |
||||
import type { FunctionComponent, FormEvent } from "react"; |
||||
import type { Container, Leaf, LeafUri } from "@ldo/solid"; |
||||
import { v4 } from "uuid"; |
||||
import { useLdo, useSolidAuth } from "@ldo/solid-react"; |
||||
import { PostShShapeType } from "../.ldo/post.shapeTypes"; |
||||
|
||||
export const MakePost: FunctionComponent<{ mainContainer: Container }> = ({ |
||||
mainContainer, |
||||
}) => { |
||||
const [message, setMessage] = useState(""); |
||||
const [selectedFile, setSelectedFile] = useState<File | undefined>(); |
||||
const fileInputRef = useRef<HTMLInputElement | null>(null); |
||||
const { createData, commitData } = useLdo(); |
||||
const { session } = useSolidAuth(); |
||||
const onSubmit = useCallback( |
||||
async (e: FormEvent<HTMLFormElement>) => { |
||||
e.preventDefault(); |
||||
|
||||
// Create the container file
|
||||
const mediaContainerResult = await mainContainer.createChildAndOverwrite( |
||||
`${v4()}/`, |
||||
); |
||||
if (mediaContainerResult.isError) { |
||||
alert(mediaContainerResult.message); |
||||
return; |
||||
} |
||||
const mediaContainer = mediaContainerResult.resource; |
||||
|
||||
// Upload Image
|
||||
let uploadedImage: Leaf | undefined; |
||||
if (selectedFile) { |
||||
const result = await mediaContainer.uploadChildAndOverwrite( |
||||
selectedFile.name as LeafUri, |
||||
selectedFile, |
||||
selectedFile.type, |
||||
); |
||||
if (result.isError) { |
||||
alert(result.message); |
||||
await mediaContainer.delete(); |
||||
return; |
||||
} |
||||
uploadedImage = result.resource; |
||||
} |
||||
|
||||
// Create Post
|
||||
const indexResource = mediaContainer.child("index.ttl"); |
||||
const post = createData( |
||||
PostShShapeType, |
||||
indexResource.uri, |
||||
indexResource, |
||||
); |
||||
post.articleBody = message; |
||||
if (uploadedImage) { |
||||
post.image = { "@id": uploadedImage.uri }; |
||||
} |
||||
if (session.webId) { |
||||
post.publisher = { "@id": session.webId }; |
||||
} |
||||
post.type = { "@id": "SocialMediaPosting" }; |
||||
post.uploadDate = new Date().toISOString(); |
||||
const result = await commitData(post); |
||||
if (result.isError) { |
||||
alert(result.message); |
||||
} |
||||
|
||||
// Clear the UI after Upload
|
||||
setMessage(""); |
||||
setSelectedFile(undefined); |
||||
if (fileInputRef.current) fileInputRef.current.value = ""; |
||||
}, |
||||
[message, selectedFile, session.webId], |
||||
); |
||||
|
||||
return ( |
||||
<form onSubmit={onSubmit}> |
||||
<input |
||||
type="text" |
||||
placeholder="Make a Post" |
||||
value={message} |
||||
onChange={(e) => setMessage(e.target.value)} |
||||
/> |
||||
<input |
||||
type="file" |
||||
accept="image/*" |
||||
ref={fileInputRef} |
||||
onChange={(e) => setSelectedFile(e.target.files?.[0])} |
||||
/> |
||||
<input type="submit" value="Post" /> |
||||
</form> |
||||
); |
||||
}; |
@ -1,8 +0,0 @@ |
||||
import React from "react"; |
||||
import ReactDOM from "react-dom/client"; |
||||
import App from "./App"; |
||||
|
||||
const root = ReactDOM.createRoot( |
||||
document.getElementById("root") as HTMLElement, |
||||
); |
||||
root.render(<App />); |
@ -1,42 +0,0 @@ |
||||
import React, { useCallback } from "react"; |
||||
import type { FunctionComponent } from "react"; |
||||
import { useLdo, useResource, useSubject } from "@ldo/solid-react"; |
||||
import { PostShShapeType } from "../.ldo/post.shapeTypes"; |
||||
import { useNavigate } from "react-router-dom"; |
||||
import { PostedBy } from "./PostedBy"; |
||||
|
||||
export const Post: FunctionComponent<{ uri: string }> = ({ uri }) => { |
||||
const navigate = useNavigate(); |
||||
const mediaResource = useResource(`${uri}index.ttl`); |
||||
const post = useSubject(PostShShapeType, mediaResource.uri); |
||||
const { getResource } = useLdo(); |
||||
const deletePost = useCallback(async () => { |
||||
const postContainer = getResource(uri); |
||||
const result = await postContainer.delete(); |
||||
if (result.isError) { |
||||
alert(result.message); |
||||
} |
||||
}, [uri]); |
||||
|
||||
if (mediaResource.isReading()) { |
||||
return <p>Loading Post...</p>; |
||||
} else if (mediaResource.status.isError) { |
||||
return <p>Error: {mediaResource.status.message}</p>; |
||||
} else if (mediaResource.isAbsent()) { |
||||
return <p>Post does not exist.</p>; |
||||
} |
||||
|
||||
return ( |
||||
<div> |
||||
{post.publisher?.["@id"] && <PostedBy webId={post.publisher["@id"]} />} |
||||
<div |
||||
onClick={() => navigate(`/media/${encodeURIComponent(uri)}`)} |
||||
style={{ cursor: "pointer" }} |
||||
> |
||||
{post.articleBody && <p>{post.articleBody}</p>} |
||||
{post.image && <img src={post.image["@id"]} style={{ height: 300 }} />} |
||||
</div> |
||||
<button onClick={deletePost}>Delete Post</button> |
||||
</div> |
||||
); |
||||
}; |
@ -1,16 +0,0 @@ |
||||
import React from "react"; |
||||
import type { FunctionComponent } from "react"; |
||||
import { useNavigate, useParams } from "react-router-dom"; |
||||
import { Post } from "./Post"; |
||||
|
||||
export const PostPage: FunctionComponent = () => { |
||||
const navigate = useNavigate(); |
||||
const { uri } = useParams(); |
||||
|
||||
return ( |
||||
<div> |
||||
<button onClick={() => navigate("/")}>Back to Feed</button> |
||||
{uri ? <Post uri={uri} /> : <p>No URI Present</p>} |
||||
</div> |
||||
); |
||||
}; |
@ -1,16 +0,0 @@ |
||||
import type { FunctionComponent } from "react"; |
||||
import React from "react"; |
||||
import { useResource, useSubject } from "@ldo/solid-react"; |
||||
import { SolidProfileShapeShapeType } from "../.ldo/solidProfile.shapeTypes"; |
||||
|
||||
export const PostedBy: FunctionComponent<{ webId: string }> = ({ webId }) => { |
||||
const webIdResource = useResource(webId); |
||||
const profile = useSubject(SolidProfileShapeShapeType, webId); |
||||
|
||||
if (webIdResource.isReading()) { |
||||
return <p>Loading Profile...</p>; |
||||
} else if (webIdResource.status.isError) { |
||||
return <p>Error: {webIdResource.status.message}</p>; |
||||
} |
||||
return <p>Posted By: {profile.fn}</p>; |
||||
}; |
@ -1,34 +0,0 @@ |
||||
import { |
||||
useLdo, |
||||
useResource, |
||||
useSolidAuth, |
||||
useSubject, |
||||
} from "@ldo/solid-react"; |
||||
import type { ChangeEvent } from "react"; |
||||
import React, { useCallback, type FunctionComponent } from "react"; |
||||
import { SolidProfileShapeShapeType } from "../.ldo/solidProfile.shapeTypes"; |
||||
|
||||
export const Profile: FunctionComponent = () => { |
||||
const { session } = useSolidAuth(); |
||||
const profile = useSubject(SolidProfileShapeShapeType, session.webId); |
||||
const webIdResource = useResource(session.webId); |
||||
const { changeData, commitData } = useLdo(); |
||||
|
||||
const onNameChange = useCallback( |
||||
async (e: ChangeEvent<HTMLInputElement>) => { |
||||
if (profile && webIdResource) { |
||||
const cProfile = changeData(profile, webIdResource); |
||||
cProfile.fn = e.target.value; |
||||
await commitData(cProfile); |
||||
} |
||||
}, |
||||
[profile, webIdResource], |
||||
); |
||||
|
||||
return ( |
||||
<> |
||||
<label>Name</label> |
||||
<input type="text" value={profile?.fn || ""} onChange={onNameChange} /> |
||||
</> |
||||
); |
||||
}; |
@ -1,20 +0,0 @@ |
||||
{ |
||||
"extends": "../../tsconfig.json", |
||||
"compilerOptions": { |
||||
"outDir": "./dist", |
||||
"lib": ["dom", "dom.iterable", "esnext"], |
||||
"allowJs": true, |
||||
"skipLibCheck": true, |
||||
"allowSyntheticDefaultImports": true, |
||||
"forceConsistentCasingInFileNames": true, |
||||
"noFallthroughCasesInSwitch": true, |
||||
"moduleResolution": "node", |
||||
"resolveJsonModule": true, |
||||
"isolatedModules": true, |
||||
"noEmit": true, |
||||
"jsx": "react-jsx" |
||||
}, |
||||
"include": [ |
||||
"./src" |
||||
] |
||||
} |
Before Width: | Height: | Size: 269 KiB After Width: | Height: | Size: 229 KiB |
@ -1,20 +0,0 @@ |
||||
import type { Dataset } from "@rdfjs/types"; |
||||
import type { ObjectNode } from "@ldo/rdf-utils"; |
||||
import type { ArrayProxyTarget } from "./createArrayHandler"; |
||||
import type { |
||||
_getNodeAtIndex, |
||||
_getUnderlyingArrayTarget, |
||||
_getUnderlyingDataset, |
||||
_getUnderlyingMatch, |
||||
_proxyContext, |
||||
} from "../types"; |
||||
import { _getUnderlyingNode } from "../types"; |
||||
import type { ProxyContext } from "../ProxyContext"; |
||||
|
||||
export type ArrayProxy = Array<unknown> & { |
||||
readonly [_getUnderlyingDataset]: Dataset; |
||||
readonly [_getUnderlyingMatch]: ArrayProxyTarget[0]; |
||||
readonly [_getNodeAtIndex]: (index: number) => ObjectNode | undefined; |
||||
readonly [_getUnderlyingArrayTarget]: ArrayProxyTarget; |
||||
[_proxyContext]: ProxyContext; |
||||
}; |
@ -1,219 +0,0 @@ |
||||
import type { ArrayProxyTarget } from "./createArrayHandler"; |
||||
import type { ObjectJsonRepresentation } from "../util/nodeToJsonldRepresentation"; |
||||
import { nodeToJsonldRepresentation } from "../util/nodeToJsonldRepresentation"; |
||||
import { modifyArray } from "./modifyArray"; |
||||
import type { ProxyContext } from "../ProxyContext"; |
||||
|
||||
export type methodBuilder<Return> = ( |
||||
target: ArrayProxyTarget, |
||||
key: string, |
||||
proxyContext: ProxyContext, |
||||
) => Return; |
||||
|
||||
export interface ArrayMethodBuildersType { |
||||
copyWithin: methodBuilder<Array<ObjectJsonRepresentation>["copyWithin"]>; |
||||
fill: methodBuilder<Array<ObjectJsonRepresentation>["fill"]>; |
||||
pop: methodBuilder<Array<ObjectJsonRepresentation>["pop"]>; |
||||
push: methodBuilder<Array<ObjectJsonRepresentation>["push"]>; |
||||
reverse: methodBuilder<Array<ObjectJsonRepresentation>["reverse"]>; |
||||
shift: methodBuilder<Array<ObjectJsonRepresentation>["shift"]>; |
||||
sort: methodBuilder<Array<ObjectJsonRepresentation>["sort"]>; |
||||
splice: methodBuilder<Array<ObjectJsonRepresentation>["splice"]>; |
||||
unshift: methodBuilder<Array<ObjectJsonRepresentation>["unshift"]>; |
||||
} |
||||
|
||||
export const methodNames: Set<keyof ArrayMethodBuildersType> = new Set([ |
||||
"copyWithin", |
||||
"fill", |
||||
"pop", |
||||
"push", |
||||
"reverse", |
||||
"shift", |
||||
"sort", |
||||
"splice", |
||||
"unshift", |
||||
]); |
||||
|
||||
export const arrayMethodsBuilders: ArrayMethodBuildersType = { |
||||
copyWithin: (target, key, proxyContext) => { |
||||
return (targetIndex, start, end) => { |
||||
return modifyArray( |
||||
{ |
||||
target, |
||||
key, |
||||
quadsToDelete: (quads) => { |
||||
const oldQuads = [...quads]; |
||||
const newQuadSet = new Set( |
||||
quads.copyWithin(targetIndex, start, end), |
||||
); |
||||
return oldQuads.filter((oldQuad) => !newQuadSet.has(oldQuad)); |
||||
}, |
||||
modifyCoreArray: (coreArray) => { |
||||
coreArray.copyWithin(targetIndex, start, end); |
||||
return proxyContext.createArrayProxy( |
||||
target[0], |
||||
target[2], |
||||
) as ObjectJsonRepresentation[]; |
||||
}, |
||||
}, |
||||
proxyContext, |
||||
); |
||||
}; |
||||
}, |
||||
fill: (target, key, proxyContext) => { |
||||
return (value, start, end) => { |
||||
return modifyArray( |
||||
{ |
||||
target, |
||||
key, |
||||
toAdd: [value], |
||||
quadsToDelete: (quads) => { |
||||
return quads.slice(start, end); |
||||
}, |
||||
modifyCoreArray: (coreArray, addedValues) => { |
||||
coreArray.fill(addedValues[0], start, end); |
||||
return proxyContext.createArrayProxy( |
||||
target[0], |
||||
target[2], |
||||
) as ObjectJsonRepresentation[]; |
||||
}, |
||||
}, |
||||
proxyContext, |
||||
); |
||||
}; |
||||
}, |
||||
pop: (target, key, proxyContext) => { |
||||
return () => { |
||||
return modifyArray( |
||||
{ |
||||
target, |
||||
key, |
||||
quadsToDelete: (quads) => { |
||||
return quads[quads.length - 1] ? [quads[quads.length - 1]] : []; |
||||
}, |
||||
modifyCoreArray: (coreArray) => { |
||||
const popped = coreArray.pop(); |
||||
return popped |
||||
? nodeToJsonldRepresentation(popped, proxyContext) |
||||
: undefined; |
||||
}, |
||||
}, |
||||
proxyContext, |
||||
); |
||||
}; |
||||
}, |
||||
push: (target, key, proxyContext) => { |
||||
return (...args) => { |
||||
return modifyArray( |
||||
{ |
||||
target, |
||||
key, |
||||
toAdd: args, |
||||
modifyCoreArray: (coreArray, addedValues) => { |
||||
coreArray.push(...addedValues); |
||||
return proxyContext.createArrayProxy(target[0], target[2]).length; |
||||
}, |
||||
}, |
||||
proxyContext, |
||||
); |
||||
}; |
||||
}, |
||||
reverse: (target, _key, proxyContext) => { |
||||
return () => { |
||||
target[1].reverse(); |
||||
return proxyContext.createArrayProxy( |
||||
target[0], |
||||
target[2], |
||||
) as ObjectJsonRepresentation[]; |
||||
}; |
||||
}, |
||||
shift: (target, key, proxyContext) => { |
||||
return () => { |
||||
return modifyArray( |
||||
{ |
||||
target, |
||||
key, |
||||
quadsToDelete: (quads) => { |
||||
return quads[0] ? [quads[0]] : []; |
||||
}, |
||||
modifyCoreArray: (coreArray) => { |
||||
const shifted = coreArray.shift(); |
||||
return shifted |
||||
? nodeToJsonldRepresentation(shifted, proxyContext) |
||||
: undefined; |
||||
}, |
||||
}, |
||||
proxyContext, |
||||
); |
||||
}; |
||||
}, |
||||
sort: (target, _key, proxyContext) => { |
||||
return (compareFunction) => { |
||||
if (compareFunction) { |
||||
target[1].sort((a, b) => { |
||||
return compareFunction( |
||||
nodeToJsonldRepresentation(a, proxyContext), |
||||
nodeToJsonldRepresentation(b, proxyContext), |
||||
); |
||||
}); |
||||
} else if (target) { |
||||
target[1].sort((a, b) => { |
||||
const aReal = nodeToJsonldRepresentation(a, proxyContext); |
||||
const bReal = nodeToJsonldRepresentation(b, proxyContext); |
||||
if (aReal > bReal) { |
||||
return 1; |
||||
} else if (bReal > aReal) { |
||||
return -1; |
||||
} else { |
||||
return 0; |
||||
} |
||||
}); |
||||
} |
||||
return proxyContext.createArrayProxy( |
||||
target[0], |
||||
target[2], |
||||
) as ObjectJsonRepresentation[]; |
||||
}; |
||||
}, |
||||
splice: (target, key, proxyContext) => { |
||||
return (start, deleteCount, ...items: ObjectJsonRepresentation[]) => { |
||||
return modifyArray( |
||||
{ |
||||
target, |
||||
key, |
||||
toAdd: items, |
||||
quadsToDelete: (quads) => { |
||||
return quads.splice(start, deleteCount); |
||||
}, |
||||
modifyCoreArray: (coreArray, addedValues) => { |
||||
const spliced = coreArray.splice( |
||||
start, |
||||
deleteCount || 0, |
||||
...addedValues, |
||||
); |
||||
return spliced.map((node) => { |
||||
return nodeToJsonldRepresentation(node, proxyContext); |
||||
}); |
||||
}, |
||||
}, |
||||
proxyContext, |
||||
); |
||||
}; |
||||
}, |
||||
unshift: (target, key, proxyContext) => { |
||||
return (...args) => { |
||||
return modifyArray( |
||||
{ |
||||
target, |
||||
key, |
||||
toAdd: args, |
||||
modifyCoreArray: (coreArray, addedValues) => { |
||||
coreArray.unshift(...addedValues); |
||||
return proxyContext.createArrayProxy(target[0], target[2]).length; |
||||
}, |
||||
}, |
||||
proxyContext, |
||||
); |
||||
}; |
||||
}, |
||||
}; |
@ -1,177 +0,0 @@ |
||||
import { quad } from "@rdfjs/data-model"; |
||||
import type { NamedNode } from "@rdfjs/types"; |
||||
import type { ObjectNode, QuadMatch, SubjectNode } from "@ldo/rdf-utils"; |
||||
import type { ObjectJsonRepresentation } from "../util/nodeToJsonldRepresentation"; |
||||
import { nodeToJsonldRepresentation } from "../util/nodeToJsonldRepresentation"; |
||||
import type { ArrayMethodBuildersType } from "./arrayMethods"; |
||||
import { arrayMethodsBuilders, methodNames } from "./arrayMethods"; |
||||
import { |
||||
_getNodeAtIndex, |
||||
_getUnderlyingArrayTarget, |
||||
_getUnderlyingDataset, |
||||
_getUnderlyingMatch, |
||||
_isSubjectOriented, |
||||
_proxyContext, |
||||
} from "../types"; |
||||
import { modifyArray } from "./modifyArray"; |
||||
import type { ProxyContext } from "../ProxyContext"; |
||||
import { NodeSet } from "../util/NodeSet"; |
||||
import { filterQuadsByLanguageOrdering } from "../language/languageUtils"; |
||||
|
||||
export type ArrayProxyTarget = [ |
||||
quadMatch: QuadMatch, |
||||
curArray: ObjectNode[], |
||||
isSubjectOriented?: boolean, |
||||
isLangStringArray?: boolean, |
||||
]; |
||||
|
||||
function updateArrayOrder( |
||||
target: ArrayProxyTarget, |
||||
proxyContext: ProxyContext, |
||||
): void { |
||||
let quads = proxyContext.dataset.match(...target[0]); |
||||
if (target[3]) { |
||||
// Is lang string array
|
||||
quads = filterQuadsByLanguageOrdering(quads, proxyContext.languageOrdering); |
||||
} |
||||
const datasetObjects = new NodeSet(); |
||||
quads.toArray().forEach((quad) => { |
||||
// If this this a subject-oriented document
|
||||
if (target[2]) { |
||||
datasetObjects.add(quad.subject as SubjectNode); |
||||
} else { |
||||
datasetObjects.add(quad.object as ObjectNode); |
||||
} |
||||
}); |
||||
const processedObjects: ObjectNode[] = []; |
||||
target[1].forEach((arrItem) => { |
||||
if (datasetObjects.has(arrItem)) { |
||||
processedObjects.push(arrItem); |
||||
datasetObjects.delete(arrItem); |
||||
} |
||||
}); |
||||
datasetObjects.toArray().forEach((datasetObject) => { |
||||
processedObjects.push(datasetObject); |
||||
}); |
||||
target[1] = processedObjects; |
||||
} |
||||
|
||||
function getProcessedArray( |
||||
target: ArrayProxyTarget, |
||||
proxyContext: ProxyContext, |
||||
): ObjectJsonRepresentation[] { |
||||
return target[1].map((node) => { |
||||
return nodeToJsonldRepresentation(node, proxyContext); |
||||
}); |
||||
} |
||||
|
||||
export function createArrayHandler( |
||||
proxyContext: ProxyContext, |
||||
): ProxyHandler<ArrayProxyTarget> { |
||||
return { |
||||
get(target, key, ...rest) { |
||||
switch (key) { |
||||
case _getUnderlyingDataset: |
||||
return proxyContext.dataset; |
||||
case _getUnderlyingMatch: |
||||
return target[0]; |
||||
case _isSubjectOriented: |
||||
return target[2]; |
||||
case _getUnderlyingArrayTarget: |
||||
return target; |
||||
case _proxyContext: |
||||
return proxyContext; |
||||
case _getNodeAtIndex: |
||||
return (index: number): ObjectNode | undefined => { |
||||
updateArrayOrder(target, proxyContext); |
||||
return target[1][index]; |
||||
}; |
||||
} |
||||
|
||||
// TODO: Because of this, every get operation is O(n). Consider changing
|
||||
// this
|
||||
updateArrayOrder(target, proxyContext); |
||||
const processedArray = getProcessedArray(target, proxyContext); |
||||
if (methodNames.has(key as keyof ArrayMethodBuildersType)) { |
||||
return arrayMethodsBuilders[key as keyof ArrayMethodBuildersType]( |
||||
target, |
||||
key as string, |
||||
proxyContext, |
||||
); |
||||
} |
||||
return Reflect.get(processedArray, key, ...rest); |
||||
}, |
||||
getOwnPropertyDescriptor(target, key, ...rest) { |
||||
updateArrayOrder(target, proxyContext); |
||||
const processedArray = getProcessedArray(target, proxyContext); |
||||
return Reflect.getOwnPropertyDescriptor(processedArray, key, ...rest); |
||||
}, |
||||
ownKeys(target, ...rest) { |
||||
updateArrayOrder(target, proxyContext); |
||||
const processedArray = getProcessedArray(target, proxyContext); |
||||
return Reflect.ownKeys(processedArray, ...rest); |
||||
}, |
||||
getPrototypeOf(target, ...rest) { |
||||
updateArrayOrder(target, proxyContext); |
||||
const processedObjects = getProcessedArray(target, proxyContext); |
||||
return Reflect.getPrototypeOf(processedObjects, ...rest); |
||||
}, |
||||
has(target, ...rest) { |
||||
updateArrayOrder(target, proxyContext); |
||||
const processedObjects = getProcessedArray(target, proxyContext); |
||||
return Reflect.has(processedObjects, ...rest); |
||||
}, |
||||
set(target, key, value, ...rest) { |
||||
if (key === _proxyContext) { |
||||
proxyContext = value; |
||||
return true; |
||||
} |
||||
updateArrayOrder(target, proxyContext); |
||||
if (typeof key !== "symbol" && !isNaN(parseInt(key as string))) { |
||||
const index = parseInt(key); |
||||
return modifyArray( |
||||
{ |
||||
target, |
||||
key, |
||||
toAdd: [value], |
||||
quadsToDelete(allQuads) { |
||||
return allQuads[index] ? [allQuads[index]] : []; |
||||
}, |
||||
modifyCoreArray(coreArray, addedValues) { |
||||
coreArray[index] = addedValues[0]; |
||||
return true; |
||||
}, |
||||
}, |
||||
proxyContext, |
||||
); |
||||
} |
||||
return Reflect.set(target[1], key, ...rest); |
||||
}, |
||||
deleteProperty(target, key) { |
||||
const { dataset } = proxyContext; |
||||
if (typeof key !== "symbol" && !isNaN(parseInt(key as string))) { |
||||
const objectQuad = dataset.match(...target[0]).toArray()[parseInt(key)]; |
||||
if (!objectQuad) { |
||||
return true; |
||||
} |
||||
const term = target[2] ? objectQuad.subject : objectQuad.object; |
||||
if (term.termType === "Literal") { |
||||
const subject = target[0][0] as NamedNode; |
||||
const predicate = target[0][1] as NamedNode; |
||||
if (subject && predicate) { |
||||
dataset.delete(quad(subject, predicate, term)); |
||||
} |
||||
return true; |
||||
} else if ( |
||||
term.termType === "NamedNode" || |
||||
term.termType === "BlankNode" |
||||
) { |
||||
dataset.deleteMatches(term, undefined, undefined); |
||||
dataset.deleteMatches(undefined, undefined, term); |
||||
return true; |
||||
} |
||||
} |
||||
return true; |
||||
}, |
||||
}; |
||||
} |
@ -1,23 +0,0 @@ |
||||
import { |
||||
_getNodeAtIndex, |
||||
_getUnderlyingArrayTarget, |
||||
_getUnderlyingDataset, |
||||
_getUnderlyingMatch, |
||||
_getUnderlyingNode, |
||||
_proxyContext, |
||||
_writeGraphs, |
||||
} from "../types"; |
||||
import type { ArrayProxy } from "./ArrayProxy"; |
||||
|
||||
export function isArrayProxy(someObject?: unknown): someObject is ArrayProxy { |
||||
if (!someObject) return false; |
||||
if (typeof someObject !== "object") return false; |
||||
const potentialArrayProxy = someObject as ArrayProxy; |
||||
|
||||
return !( |
||||
typeof potentialArrayProxy[_getUnderlyingDataset] !== "object" || |
||||
typeof potentialArrayProxy[_getUnderlyingMatch] !== "object" || |
||||
typeof potentialArrayProxy[_getNodeAtIndex] !== "function" || |
||||
typeof potentialArrayProxy[_getUnderlyingArrayTarget] !== "object" |
||||
); |
||||
} |
@ -1,141 +0,0 @@ |
||||
import { defaultGraph } from "@rdfjs/data-model"; |
||||
import type { Quad } from "@rdfjs/types"; |
||||
import type { ObjectNode } from "@ldo/rdf-utils"; |
||||
import { |
||||
TransactionDataset, |
||||
createTransactionDatasetFactory, |
||||
} from "@ldo/subscribable-dataset"; |
||||
import { createDatasetFactory } from "@ldo/dataset"; |
||||
import type { ProxyContext } from "../ProxyContext"; |
||||
import { addObjectToDataset } from "../util/addObjectToDataset"; |
||||
import { |
||||
getNodeFromRawObject, |
||||
getNodeFromRawValue, |
||||
} from "../util/getNodeFromRaw"; |
||||
import { nodeToString } from "../util/NodeSet"; |
||||
import type { ObjectJsonRepresentation } from "../util/nodeToJsonldRepresentation"; |
||||
import type { RawObject, RawValue } from "../util/RawObject"; |
||||
import type { ArrayProxyTarget } from "./createArrayHandler"; |
||||
|
||||
export function checkArrayModification( |
||||
target: ArrayProxyTarget, |
||||
objectsToAdd: RawValue[], |
||||
proxyContext: ProxyContext, |
||||
) { |
||||
if (target[2]) { |
||||
for (const objectToAdd of objectsToAdd) { |
||||
// Undefined is fine no matter what
|
||||
if (objectToAdd === undefined) { |
||||
return; |
||||
} |
||||
if (typeof objectToAdd !== "object") { |
||||
throw new Error( |
||||
`Cannot add a literal "${objectToAdd}"(${typeof objectToAdd}) to a subject-oriented collection.`, |
||||
); |
||||
} |
||||
// Create a test dataset to see if the inputted data is valid
|
||||
const testDataset = new TransactionDataset( |
||||
proxyContext.dataset, |
||||
createDatasetFactory(), |
||||
createTransactionDatasetFactory(), |
||||
); |
||||
addObjectToDataset( |
||||
objectToAdd as RawObject, |
||||
false, |
||||
proxyContext.duplicate({ |
||||
writeGraphs: [defaultGraph()], |
||||
}), |
||||
); |
||||
const isValidAddition = |
||||
testDataset.match( |
||||
getNodeFromRawObject(objectToAdd, proxyContext.contextUtil), |
||||
target[0][1], |
||||
target[0][2], |
||||
).size !== 0; |
||||
if (!isValidAddition) { |
||||
throw new Error( |
||||
`Cannot add value to collection. This must contain a quad that matches (${nodeToString( |
||||
target[0][0], |
||||
)}, ${nodeToString(target[0][1])}, ${nodeToString( |
||||
target[0][2], |
||||
)}, ${nodeToString(target[0][3])})`,
|
||||
); |
||||
} |
||||
} |
||||
} else if (!target[0][0] || !target[0][1]) { |
||||
throw new Error( |
||||
"A collection that does not specify a match for both a subject or predicate cannot be modified directly.", |
||||
); |
||||
} |
||||
} |
||||
|
||||
export function modifyArray<ReturnType>( |
||||
config: { |
||||
target: ArrayProxyTarget; |
||||
key: string; |
||||
toAdd?: RawValue[]; |
||||
quadsToDelete?: (quads: Quad[]) => Quad[]; |
||||
modifyCoreArray: ( |
||||
coreArray: ArrayProxyTarget[1], |
||||
addedValues: ArrayProxyTarget[1], |
||||
) => ReturnType; |
||||
}, |
||||
proxyContext: ProxyContext, |
||||
): ReturnType { |
||||
const { target, toAdd, quadsToDelete, modifyCoreArray, key } = config; |
||||
const { dataset, contextUtil } = proxyContext; |
||||
checkArrayModification(target, toAdd || [], proxyContext); |
||||
|
||||
// Remove appropriate Quads
|
||||
if (quadsToDelete) { |
||||
const quadArr = dataset.match(...target[0]).toArray(); |
||||
const deleteQuadArr = quadsToDelete(quadArr); |
||||
// Filter out overlapping items
|
||||
deleteQuadArr.forEach((delQuad) => { |
||||
if (target[2]) { |
||||
dataset.deleteMatches(delQuad.subject, undefined, undefined); |
||||
} else { |
||||
dataset.delete(delQuad); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
// Add new items to the dataset
|
||||
const added = toAdd |
||||
?.map((item) => { |
||||
return typeof item === "object" |
||||
? addObjectToDataset(item, false, proxyContext) |
||||
: item; |
||||
}) |
||||
.filter( |
||||
(val) => val != undefined, |
||||
) as NonNullable<ObjectJsonRepresentation>[]; |
||||
if (!target[2] && target[0][0] && target[0][1] && added) { |
||||
addObjectToDataset( |
||||
{ |
||||
"@id": target[0][0], |
||||
[contextUtil.iriToKey( |
||||
target[0][1].value, |
||||
proxyContext.getRdfType(target[0][0]), |
||||
)]: added, |
||||
} as RawObject, |
||||
false, |
||||
proxyContext, |
||||
); |
||||
} |
||||
const addedNodes = added |
||||
? (added |
||||
.map((addedValue) => { |
||||
return getNodeFromRawValue( |
||||
key, |
||||
addedValue, |
||||
target[0][0] ? proxyContext.getRdfType(target[0][0]) : [], |
||||
proxyContext, |
||||
); |
||||
}) |
||||
.filter((val) => val != undefined) as ObjectNode[]) |
||||
: []; |
||||
|
||||
// Allow the base array to be modified
|
||||
return modifyCoreArray(target[1], addedNodes); |
||||
} |
@ -0,0 +1,66 @@ |
||||
import type { GraphNode, PredicateNode, SubjectNode } from "@ldo/rdf-utils"; |
||||
import type { RawObject, RawValue } from "../util/RawObject"; |
||||
import { WildcardObjectSetProxy } from "./WildcardObjectSetProxy"; |
||||
import { addObjectToDataset } from "../util/addObjectToDataset"; |
||||
import type { ProxyContext } from "../ProxyContext"; |
||||
|
||||
export type ObjectSetProxyQuadMatch = [ |
||||
SubjectNode, |
||||
PredicateNode, |
||||
undefined | null, |
||||
GraphNode | undefined | null, |
||||
]; |
||||
|
||||
export class ObjectSetProxy< |
||||
T extends NonNullable<RawValue>, |
||||
> extends WildcardObjectSetProxy<T> { |
||||
protected quadMatch: ObjectSetProxyQuadMatch; |
||||
|
||||
constructor( |
||||
context: ProxyContext, |
||||
quadMatch: ObjectSetProxyQuadMatch, |
||||
isLangSet?: boolean, |
||||
) { |
||||
super(context, quadMatch, isLangSet); |
||||
this.quadMatch = quadMatch; |
||||
} |
||||
|
||||
/** |
||||
* Appends a new element with a specified value to the end of the Set. |
||||
*/ |
||||
add(value: T): this { |
||||
addObjectToDataset( |
||||
{ |
||||
"@id": this.quadMatch[0], |
||||
[this.context.contextUtil.iriToKey( |
||||
this.quadMatch[1].value, |
||||
this.context.getRdfType(this.quadMatch[0]), |
||||
)]: value, |
||||
} as RawObject, |
||||
false, |
||||
this.context, |
||||
); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Clears the set of all values |
||||
*/ |
||||
clear(): void { |
||||
for (const value of this) { |
||||
this.delete(value); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Deletes an item for the set |
||||
* @param value the item to delete |
||||
* @returns true if the item was present before deletion |
||||
*/ |
||||
delete(value: T): boolean { |
||||
const { dataset } = this.context; |
||||
const quads = this.getQuads(value); |
||||
quads.forEach((quad) => dataset.delete(quad)); |
||||
return quads.size > 0; |
||||
} |
||||
} |
@ -0,0 +1,141 @@ |
||||
/** |
||||
* This file handles the underlying functionality of a set, including hidden |
||||
* helper methods |
||||
*/ |
||||
import type { Dataset, Quad } from "@rdfjs/types"; |
||||
import type { |
||||
GraphNode, |
||||
ObjectNode, |
||||
QuadMatch, |
||||
SubjectNode, |
||||
} from "@ldo/rdf-utils"; |
||||
import { |
||||
_isSubjectOriented, |
||||
_getUnderlyingDataset, |
||||
_proxyContext, |
||||
_isLangString, |
||||
_getUnderlyingMatch, |
||||
_getUnderlyingNode, |
||||
_writeGraphs, |
||||
} from "../types"; |
||||
import type { ProxyContext } from "../ProxyContext"; |
||||
import type { RawValue } from "../util/RawObject"; |
||||
import { nodeToJsonldRepresentation } from "../util/nodeToJsonldRepresentation"; |
||||
import { BasicLdSet } from "./ldSet/BasicLdSet"; |
||||
|
||||
/** |
||||
* A Set Proxy represents a set of items in a dataset and is a proxy for |
||||
* accessing those items in the dataset. |
||||
*/ |
||||
export abstract class SetProxy< |
||||
T extends NonNullable<RawValue> = NonNullable<RawValue>, |
||||
> extends BasicLdSet<T> { |
||||
protected quadMatch: QuadMatch; |
||||
protected context: ProxyContext; |
||||
|
||||
constructor(context: ProxyContext, quadMatch: QuadMatch) { |
||||
super(); |
||||
this.context = context; |
||||
this.quadMatch = quadMatch; |
||||
} |
||||
|
||||
/** |
||||
* Gets the subject, predicate and object for this set |
||||
*/ |
||||
protected abstract getQuads(value?: T): Dataset<Quad, Quad>; |
||||
|
||||
protected abstract getNodeOfFocus(quad: Quad): SubjectNode | ObjectNode; |
||||
|
||||
/** |
||||
* The add method on a wildcard set does nothing. |
||||
* @deprecated You cannot add data to a wildcard set as it is simply a proxy to an underlying dataset |
||||
*/ |
||||
add(_value: T) { |
||||
console.warn( |
||||
'You\'ve attempted to call "add" on a wildcard set. You cannot add data to a wildcard set as it is simply a proxy to an underlying dataset', |
||||
); |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* The clear method on an abstract set does nothing. |
||||
* @deprecated You cannot clear data from an abstract set as it is simply a proxy to an underlying dataset |
||||
*/ |
||||
clear(): void { |
||||
console.warn( |
||||
'You\'ve attempted to call "clear" on an abstract set. You cannot clear data from an abstract set as it is simply a proxy to an underlying dataset', |
||||
); |
||||
return; |
||||
} |
||||
|
||||
/** |
||||
* The delete method on an abstract set does nothing. |
||||
* @deprecated You cannot delete data from an abstract set as it is simply a proxy to an underlying dataset |
||||
*/ |
||||
delete(_value: T): boolean { |
||||
console.warn( |
||||
'You\'ve attempted to call "clear" on an abstract set. You cannot delete data from an abstract set as it is simply a proxy to an underlying dataset', |
||||
); |
||||
return false; |
||||
} |
||||
|
||||
has(value: T): boolean { |
||||
return this.getQuads(value).size > 0; |
||||
} |
||||
|
||||
get size() { |
||||
return this.getQuads().size; |
||||
} |
||||
|
||||
entries(): IterableIterator<[T, T]> { |
||||
const iteratorSet = new Set<[T, T]>(); |
||||
for (const value of this) { |
||||
iteratorSet.add([value, value]); |
||||
} |
||||
return iteratorSet[Symbol.iterator](); |
||||
} |
||||
|
||||
keys(): IterableIterator<T> { |
||||
return this.values(); |
||||
} |
||||
|
||||
values(): IterableIterator<T> { |
||||
return this[Symbol.iterator](); |
||||
} |
||||
|
||||
[Symbol.iterator](): IterableIterator<T> { |
||||
const quads = this.getQuads(); |
||||
const collection: T[] = quads.toArray().map((quad) => { |
||||
const quadSubject = this.getNodeOfFocus(quad); |
||||
return nodeToJsonldRepresentation(quadSubject, this.context) as T; |
||||
}); |
||||
return new Set(collection)[Symbol.iterator](); |
||||
} |
||||
|
||||
get [Symbol.toStringTag]() { |
||||
// TODO: Change this to be human readable.
|
||||
return "LdSet"; |
||||
} |
||||
|
||||
get [_getUnderlyingDataset](): Dataset { |
||||
return this.context.dataset; |
||||
} |
||||
|
||||
get [_getUnderlyingMatch](): QuadMatch { |
||||
return this.quadMatch; |
||||
} |
||||
|
||||
get [_proxyContext](): ProxyContext { |
||||
return this.context; |
||||
} |
||||
|
||||
set [_proxyContext](newContext: ProxyContext) { |
||||
this.context = newContext; |
||||
} |
||||
|
||||
get [_writeGraphs](): GraphNode[] { |
||||
return this.context.writeGraphs; |
||||
} |
||||
|
||||
abstract get [_isSubjectOriented](): boolean; |
||||
} |
@ -0,0 +1,85 @@ |
||||
import { |
||||
type GraphNode, |
||||
type ObjectNode, |
||||
type PredicateNode, |
||||
} from "@ldo/rdf-utils"; |
||||
import type { RawObject } from "../util/RawObject"; |
||||
import { addObjectToDataset } from "../util/addObjectToDataset"; |
||||
import type { ProxyContext } from "../ProxyContext"; |
||||
import { WildcardSubjectSetProxy } from "./WildcardSubjectSetProxy"; |
||||
import { _getUnderlyingNode } from "../types"; |
||||
import { defaultGraph, quad } from "@rdfjs/data-model"; |
||||
import { |
||||
createTransactionDatasetFactory, |
||||
TransactionDataset, |
||||
} from "@ldo/subscribable-dataset"; |
||||
import { createDatasetFactory } from "@ldo/dataset"; |
||||
import { getNodeFromRawObject } from "../util/getNodeFromRaw"; |
||||
import { nodeToString } from "../util/NodeSet"; |
||||
|
||||
export type SubjectSetProxyQuadMatch = [ |
||||
undefined | null, |
||||
PredicateNode, |
||||
ObjectNode, |
||||
GraphNode | undefined | null, |
||||
]; |
||||
|
||||
export class SubjectSetProxy< |
||||
T extends RawObject, |
||||
> extends WildcardSubjectSetProxy<T> { |
||||
protected quadMatch: SubjectSetProxyQuadMatch; |
||||
|
||||
constructor(context: ProxyContext, quadMatch: SubjectSetProxyQuadMatch) { |
||||
super(context, quadMatch); |
||||
this.quadMatch = quadMatch; |
||||
} |
||||
|
||||
/** |
||||
* Appends a new element with a specified value to the end of the Set. |
||||
*/ |
||||
add(value: T): this { |
||||
if (typeof value !== "object") { |
||||
throw new Error( |
||||
`Cannot add a literal "${value}"(${typeof value}) to a subject-oriented collection.`, |
||||
); |
||||
} |
||||
// Create a test dataset to see if the inputted data is valid
|
||||
const testDataset = new TransactionDataset( |
||||
this.context.dataset, |
||||
createDatasetFactory(), |
||||
createTransactionDatasetFactory(), |
||||
); |
||||
addObjectToDataset( |
||||
value, |
||||
false, |
||||
this.context.duplicate({ |
||||
writeGraphs: [defaultGraph()], |
||||
}), |
||||
); |
||||
const isValidAddition = |
||||
testDataset.match( |
||||
getNodeFromRawObject(value, this.context.contextUtil), |
||||
this.quadMatch[1], |
||||
this.quadMatch[2], |
||||
).size !== 0; |
||||
if (!isValidAddition) { |
||||
throw new Error( |
||||
`Cannot add value to collection. This must contain a quad that matches (${nodeToString( |
||||
this.quadMatch[0], |
||||
)}, ${nodeToString(this.quadMatch[1])}, ${nodeToString( |
||||
this.quadMatch[2], |
||||
)}, ${nodeToString(this.quadMatch[3])})`,
|
||||
); |
||||
} |
||||
|
||||
// Add the object if everything's okay
|
||||
const added = addObjectToDataset(value as RawObject, false, this.context); |
||||
const addedNode = added[_getUnderlyingNode]; |
||||
this.context.writeGraphs.forEach((graph) => { |
||||
this.context.dataset.add( |
||||
quad(addedNode, this.quadMatch[1], this.quadMatch[2], graph), |
||||
); |
||||
}); |
||||
return this; |
||||
} |
||||
} |
@ -0,0 +1,89 @@ |
||||
import type { |
||||
SubjectNode, |
||||
PredicateNode, |
||||
ObjectNode, |
||||
GraphNode, |
||||
} from "@ldo/rdf-utils"; |
||||
import type { Dataset, Quad } from "@rdfjs/types"; |
||||
import type { RawValue } from "../util/RawObject"; |
||||
import { SetProxy } from "./SetProxy"; |
||||
import type { ProxyContext } from "../ProxyContext"; |
||||
import { getNodeFromRawValue } from "../util/getNodeFromRaw"; |
||||
import { _isSubjectOriented } from "../types"; |
||||
import { filterQuadsByLanguageOrdering } from "../language/languageUtils"; |
||||
|
||||
export type WildcardObjectSetProxyQuadMatch = [ |
||||
SubjectNode | undefined | null, |
||||
PredicateNode | undefined | null, |
||||
undefined | null, |
||||
GraphNode | undefined | null, |
||||
]; |
||||
|
||||
/** |
||||
* A WildcardObjectProxy represents a set of nodes in a dataset that are all the |
||||
* object of a given subject and predicate. Because this is a wildcard, the |
||||
* subject and predicate don't necissarily need to be defined. |
||||
*/ |
||||
export class WildcardObjectSetProxy< |
||||
T extends NonNullable<RawValue>, |
||||
> extends SetProxy<T> { |
||||
protected quadMatch: WildcardObjectSetProxyQuadMatch; |
||||
protected isLangStringSet: boolean; |
||||
|
||||
constructor( |
||||
context: ProxyContext, |
||||
quadMatch: WildcardObjectSetProxyQuadMatch, |
||||
isLangStringSet?: boolean, |
||||
) { |
||||
super(context, quadMatch); |
||||
this.quadMatch = quadMatch; |
||||
this.isLangStringSet = isLangStringSet ?? false; |
||||
} |
||||
|
||||
protected getQuads(value?: T | undefined): Dataset<Quad, Quad> { |
||||
const { dataset } = this.context; |
||||
let quads: Dataset<Quad, Quad>; |
||||
// Get the RDF Node that represents the value, skip if no value
|
||||
const subject = this.quadMatch[0] ?? undefined; |
||||
const predicate = this.quadMatch[1] ?? undefined; |
||||
const graph = this.quadMatch[3] ?? undefined; |
||||
if (value) { |
||||
// Get datatype if applicable
|
||||
let datatype: string | undefined = undefined; |
||||
if (this.quadMatch[0] && predicate) { |
||||
const rdfType = this.context.getRdfType(this.quadMatch[0]); |
||||
const key = this.context.contextUtil.iriToKey(predicate.value, rdfType); |
||||
datatype = this.context.contextUtil.getDataType(key, rdfType); |
||||
} |
||||
const valueNode = getNodeFromRawValue(value, this.context, datatype); |
||||
quads = dataset.match(subject, predicate, valueNode, graph); |
||||
// If there is no valueNode, we must filter by value manually as we
|
||||
// weren't able to deduce the datatype.
|
||||
if (!valueNode) { |
||||
quads = quads.filter( |
||||
(quad) => |
||||
quad.object.termType === "Literal" && quad.object.value === value, |
||||
); |
||||
} |
||||
} else { |
||||
// SPO for no value
|
||||
quads = dataset.match(subject, predicate, undefined, graph); |
||||
} |
||||
// If this is a langStringSet, filter by language preferences
|
||||
if (this.isLangStringSet) { |
||||
return filterQuadsByLanguageOrdering( |
||||
quads, |
||||
this.context.languageOrdering, |
||||
); |
||||
} |
||||
return quads; |
||||
} |
||||
|
||||
protected getNodeOfFocus(quad: Quad): ObjectNode { |
||||
return quad.object as ObjectNode; |
||||
} |
||||
|
||||
get [_isSubjectOriented](): false { |
||||
return false; |
||||
} |
||||
} |
@ -0,0 +1,58 @@ |
||||
import type { |
||||
SubjectNode, |
||||
PredicateNode, |
||||
ObjectNode, |
||||
GraphNode, |
||||
} from "@ldo/rdf-utils"; |
||||
import type { Dataset, Quad } from "@rdfjs/types"; |
||||
import type { RawObject } from "../util/RawObject"; |
||||
import { SetProxy } from "./SetProxy"; |
||||
import type { ProxyContext } from "../ProxyContext"; |
||||
import { getNodeFromRawObject } from "../util/getNodeFromRaw"; |
||||
import { _isSubjectOriented } from "../types"; |
||||
|
||||
export type WildcardSubjectSetProxyQuadMatch = [ |
||||
undefined | null, |
||||
PredicateNode | undefined | null, |
||||
ObjectNode | undefined | null, |
||||
GraphNode | undefined | null, |
||||
]; |
||||
|
||||
/** |
||||
* A WildcardObjectProxy represents a set of nodes in a dataset that are all the |
||||
* object of a given subject and predicate. Because this is a wildcard, the |
||||
* subject and predicate don't necissarily need to be defined. |
||||
*/ |
||||
export class WildcardSubjectSetProxy<T extends RawObject> extends SetProxy<T> { |
||||
protected quadMatch: WildcardSubjectSetProxyQuadMatch; |
||||
|
||||
constructor( |
||||
context: ProxyContext, |
||||
quadMatch: WildcardSubjectSetProxyQuadMatch, |
||||
) { |
||||
super(context, quadMatch); |
||||
this.quadMatch = quadMatch; |
||||
} |
||||
|
||||
protected getQuads(value?: T | undefined): Dataset<Quad, Quad> { |
||||
const { dataset } = this.context; |
||||
// Get the RDF Node that represents the value, skip is no value
|
||||
const predicate = this.quadMatch[1]; |
||||
const object = this.quadMatch[2]; |
||||
const graph = this.quadMatch[3]; |
||||
if (value) { |
||||
const valueNode = getNodeFromRawObject(value, this.context.contextUtil); |
||||
return dataset.match(valueNode, predicate, object, graph); |
||||
} |
||||
// SPO for no value
|
||||
return dataset.match(undefined, predicate, object, graph); |
||||
} |
||||
|
||||
protected getNodeOfFocus(quad: Quad): SubjectNode { |
||||
return quad.subject as SubjectNode; |
||||
} |
||||
|
||||
get [_isSubjectOriented](): true { |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,47 @@ |
||||
import type { QuadMatch } from "@ldo/rdf-utils"; |
||||
import type { ProxyContext } from "../ProxyContext"; |
||||
import type { RawObject, RawValue } from "../util/RawObject"; |
||||
import type { ObjectSetProxyQuadMatch } from "./ObjectSetProxy"; |
||||
import { ObjectSetProxy } from "./ObjectSetProxy"; |
||||
import type { SubjectSetProxyQuadMatch } from "./SubjectSetProxy"; |
||||
import { SubjectSetProxy } from "./SubjectSetProxy"; |
||||
import type { WildcardObjectSetProxyQuadMatch } from "./WildcardObjectSetProxy"; |
||||
import { WildcardObjectSetProxy } from "./WildcardObjectSetProxy"; |
||||
import type { WildcardSubjectSetProxyQuadMatch } from "./WildcardSubjectSetProxy"; |
||||
import { WildcardSubjectSetProxy } from "./WildcardSubjectSetProxy"; |
||||
import type { SetProxy } from "./SetProxy"; |
||||
|
||||
export function createNewSetProxy<T extends NonNullable<RawValue>>( |
||||
quadMatch: QuadMatch, |
||||
isSubjectOriented: boolean, |
||||
proxyContext: ProxyContext, |
||||
isLangSet?: boolean, |
||||
): SetProxy<T> { |
||||
if (!isSubjectOriented) { |
||||
if (quadMatch[0] && quadMatch[1]) { |
||||
return new ObjectSetProxy<T>( |
||||
proxyContext, |
||||
quadMatch as ObjectSetProxyQuadMatch, |
||||
isLangSet, |
||||
); |
||||
} else { |
||||
return new WildcardObjectSetProxy<T>( |
||||
proxyContext, |
||||
quadMatch as WildcardObjectSetProxyQuadMatch, |
||||
isLangSet, |
||||
); |
||||
} |
||||
} else { |
||||
if (quadMatch[1] && quadMatch[2]) { |
||||
return new SubjectSetProxy<T & RawObject>( |
||||
proxyContext, |
||||
quadMatch as SubjectSetProxyQuadMatch, |
||||
); |
||||
} else { |
||||
return new WildcardSubjectSetProxy<T & RawObject>( |
||||
proxyContext, |
||||
quadMatch as WildcardSubjectSetProxyQuadMatch, |
||||
); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,7 @@ |
||||
import { SetProxy } from "./SetProxy"; |
||||
|
||||
export function isSetProxy(someObject?: unknown): someObject is SetProxy { |
||||
if (!someObject) return false; |
||||
if (typeof someObject !== "object") return false; |
||||
return someObject instanceof SetProxy; |
||||
} |
@ -0,0 +1,266 @@ |
||||
import type { BlankNode, NamedNode } from "@rdfjs/types"; |
||||
import { _getUnderlyingNode } from "../../types"; |
||||
import type { RawValue } from "../../util/RawObject"; |
||||
import type { LdSet } from "./LdSet"; |
||||
import { blankNode } from "@rdfjs/data-model"; |
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */ |
||||
export class BasicLdSet<T extends NonNullable<RawValue> = NonNullable<RawValue>> |
||||
implements LdSet<T> |
||||
{ |
||||
private hashMap: Map<string, T>; |
||||
|
||||
constructor(values?: Iterable<T> | null) { |
||||
this.hashMap = new Map(); |
||||
if (values) { |
||||
for (const value of values) { |
||||
this.add(value); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private hashFn(value: T): string { |
||||
if (typeof value !== "object") return value.toString(); |
||||
if (value[_getUnderlyingNode]) { |
||||
return (value[_getUnderlyingNode] as NamedNode | BlankNode).value; |
||||
} else if (!value["@id"]) { |
||||
return blankNode().value; |
||||
} else if (typeof value["@id"] === "string") { |
||||
return value["@id"]; |
||||
} else { |
||||
return value["@id"].value; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* =========================================================================== |
||||
* Base Set Functions |
||||
* =========================================================================== |
||||
*/ |
||||
|
||||
add(value: T): this { |
||||
const key = this.hashFn(value); |
||||
if (!this.hashMap.has(key)) { |
||||
this.hashMap.set(key, value); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
clear(): void { |
||||
this.hashMap.clear(); |
||||
} |
||||
|
||||
delete(value: T): boolean { |
||||
const key = this.hashFn(value); |
||||
return this.hashMap.delete(key); |
||||
} |
||||
|
||||
has(value: T): boolean { |
||||
const key = this.hashFn(value); |
||||
return this.hashMap.has(key); |
||||
} |
||||
|
||||
get size(): number { |
||||
return this.hashMap.size; |
||||
} |
||||
|
||||
*entries(): IterableIterator<[T, T]> { |
||||
for (const [, value] of this.hashMap.entries()) { |
||||
yield [value, value]; |
||||
} |
||||
} |
||||
|
||||
keys(): IterableIterator<T> { |
||||
return this.hashMap.values(); |
||||
} |
||||
|
||||
values(): IterableIterator<T> { |
||||
return this.hashMap.values(); |
||||
} |
||||
[Symbol.iterator](): IterableIterator<T> { |
||||
return this.hashMap.values(); |
||||
} |
||||
|
||||
get [Symbol.toStringTag]() { |
||||
// TODO: Change this to be human readable.
|
||||
return "BasicLdSet"; |
||||
} |
||||
|
||||
/** |
||||
* =========================================================================== |
||||
* Array Functions |
||||
* =========================================================================== |
||||
*/ |
||||
|
||||
every<S extends T>( |
||||
predicate: (value: T, set: LdSet<T>) => value is S, |
||||
thisArg?: any, |
||||
): this is LdSet<S>; |
||||
every( |
||||
predicate: (value: T, set: LdSet<T>) => unknown, |
||||
thisArg?: any, |
||||
): boolean; |
||||
every(predicate: (value: T, set: LdSet<T>) => any, thisArg?: any): boolean { |
||||
for (const value of this) { |
||||
if (!predicate.call(thisArg, value, this)) return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
some( |
||||
predicate: (value: T, set: LdSet<T>) => unknown, |
||||
thisArg?: any, |
||||
): boolean { |
||||
for (const value of this) { |
||||
if (predicate.call(thisArg, value, this)) return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
forEach( |
||||
callbackfn: (value: T, value2: T, set: LdSet<T>) => void, |
||||
thisArg?: any, |
||||
): void { |
||||
for (const value of this) { |
||||
callbackfn.call(thisArg, value, value, this); |
||||
} |
||||
} |
||||
|
||||
map<U>(callbackfn: (value: T, set: LdSet<T>) => U, thisArg?: any): U[] { |
||||
const returnValues: U[] = []; |
||||
for (const value of this) { |
||||
returnValues.push(callbackfn.call(thisArg, value, this)); |
||||
} |
||||
return returnValues; |
||||
} |
||||
|
||||
filter<S extends T>( |
||||
predicate: (value: T, set: LdSet<T>) => value is S, |
||||
thisArg?: any, |
||||
): LdSet<S>; |
||||
filter( |
||||
predicate: (value: T, set: LdSet<T>) => unknown, |
||||
thisArg?: any, |
||||
): LdSet<T>; |
||||
filter( |
||||
predicate: (value: T, set: LdSet<T>) => any, |
||||
thisArg?: unknown, |
||||
): LdSet<T> { |
||||
const newSet = new BasicLdSet<T>(); |
||||
for (const value of this) { |
||||
if (predicate.call(thisArg, value, this)) newSet.add(value); |
||||
} |
||||
return newSet; |
||||
} |
||||
|
||||
reduce( |
||||
callbackfn: (previousValue: T, currentValue: T, set: LdSet<T>) => T, |
||||
): T; |
||||
reduce( |
||||
callbackfn: (previousValue: T, currentValue: T, set: LdSet<T>) => T, |
||||
initialValue: T, |
||||
): T; |
||||
reduce<U>( |
||||
callbackfn: (previousValue: U, currentValue: T, set: LdSet<T>) => U, |
||||
initialValue: U, |
||||
): U; |
||||
reduce(callbackfn: any, initialValue?: any): any { |
||||
const iterator = this[Symbol.iterator](); |
||||
let accumulator; |
||||
|
||||
if (initialValue === undefined) { |
||||
const first = iterator.next(); |
||||
if (first.done) { |
||||
throw new TypeError("Reduce of empty collection with no initial value"); |
||||
} |
||||
accumulator = first.value; |
||||
} else { |
||||
accumulator = initialValue; |
||||
} |
||||
|
||||
let result = iterator.next(); |
||||
while (!result.done) { |
||||
accumulator = callbackfn(accumulator, result.value, this); |
||||
result = iterator.next(); |
||||
} |
||||
|
||||
return accumulator; |
||||
} |
||||
|
||||
toArray(): T[] { |
||||
const arr: T[] = []; |
||||
this.forEach((value) => arr.push(value)); |
||||
return arr; |
||||
} |
||||
|
||||
toJSON(): T[] { |
||||
return this.toArray(); |
||||
} |
||||
|
||||
/** |
||||
* =========================================================================== |
||||
* Set Methods |
||||
* =========================================================================== |
||||
*/ |
||||
|
||||
difference(other: Set<T>): LdSet<T> { |
||||
return this.filter((value) => !other.has(value)); |
||||
} |
||||
|
||||
intersection(other: Set<T>): LdSet<T> { |
||||
const newSet = new BasicLdSet<T>(); |
||||
const iteratingSet = this.size < other.size ? this : other; |
||||
const comparingSet = this.size < other.size ? other : this; |
||||
for (const value of iteratingSet) { |
||||
if (comparingSet.has(value)) { |
||||
newSet.add(value); |
||||
} |
||||
} |
||||
return newSet; |
||||
} |
||||
|
||||
isDisjointFrom(other: Set<T>): boolean { |
||||
const iteratingSet = this.size < other.size ? this : other; |
||||
const comparingSet = this.size < other.size ? other : this; |
||||
for (const value of iteratingSet) { |
||||
if (comparingSet.has(value)) return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
isSubsetOf(other: Set<T>): boolean { |
||||
if (this.size > other.size) return false; |
||||
for (const value of this) { |
||||
if (!other.has(value)) return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
isSupersetOf(other: Set<T>): boolean { |
||||
if (this.size < other.size) return false; |
||||
for (const value of other) { |
||||
if (!this.has(value)) return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
symmetricDifference(other: Set<T>): LdSet<T> { |
||||
const newSet = new BasicLdSet<T>(); |
||||
this.forEach((value) => newSet.add(value)); |
||||
other.forEach((value) => { |
||||
if (newSet.has(value)) { |
||||
newSet.delete(value); |
||||
} else { |
||||
newSet.add(value); |
||||
} |
||||
}); |
||||
return newSet; |
||||
} |
||||
|
||||
union(other: Set<T>): LdSet<T> { |
||||
const newSet = new BasicLdSet<T>(); |
||||
this.forEach((value) => newSet.add(value)); |
||||
other.forEach((value) => newSet.add(value)); |
||||
return newSet; |
||||
} |
||||
} |
@ -0,0 +1,189 @@ |
||||
/* eslint-disable @typescript-eslint/no-explicit-any */ |
||||
|
||||
/** |
||||
* An abract representation for a set of Linked Data Objects |
||||
*/ |
||||
export interface LdSet<T> extends Set<T> { |
||||
/** |
||||
* =========================================================================== |
||||
* BASE METHODS |
||||
* =========================================================================== |
||||
*/ |
||||
/** |
||||
* Appends a new element with a specified value to the end of the Set. |
||||
*/ |
||||
add(value: T): this; |
||||
/** |
||||
* Clears this set of all values, but keeps the values in the datastore |
||||
*/ |
||||
clear(): void; |
||||
/** |
||||
* Removes a specified value from the Set. |
||||
* @returns Returns true if an element in the Set existed and has been removed, or false if the element does not exist. |
||||
*/ |
||||
delete(value: T): boolean; |
||||
/** |
||||
* @returns a boolean indicating whether an element with the specified value exists in the Set or not. |
||||
*/ |
||||
has(value: T): boolean; |
||||
/** |
||||
* @returns the number of (unique) elements in Set. |
||||
*/ |
||||
readonly size: number; |
||||
/** Iterates over values in the set. */ |
||||
[Symbol.iterator](): IterableIterator<T>; |
||||
/** |
||||
* Returns an iterable of [v,v] pairs for every value `v` in the set. |
||||
*/ |
||||
entries(): IterableIterator<[T, T]>; |
||||
/** |
||||
* Despite its name, returns an iterable of the values in the set. |
||||
*/ |
||||
keys(): IterableIterator<T>; |
||||
/** |
||||
* Returns an iterable of values in the set. |
||||
*/ |
||||
values(): IterableIterator<T>; |
||||
/** |
||||
* =========================================================================== |
||||
* ITERATOR METHODS |
||||
* These methods mimic array methods |
||||
* =========================================================================== |
||||
*/ |
||||
/** |
||||
* Determines whether all the members of an set satisfy the specified test. |
||||
* @param predicate A function that accepts up to two arguments. The every method calls |
||||
* the predicate function for each element in the set until the predicate returns a value |
||||
* which is coercible to the Boolean value false, or until the end of the set. |
||||
* @param thisArg An object to which the this keyword can refer in the predicate function. |
||||
* If thisArg is omitted, undefined is used as the this value. |
||||
*/ |
||||
every<S extends T>( |
||||
predicate: (value: T, set: LdSet<T>) => value is S, |
||||
thisArg?: any, |
||||
): this is LdSet<S>; |
||||
/** |
||||
* Determines whether all the members of an set satisfy the specified test. |
||||
* @param predicate A function that accepts up to two arguments. The every method calls |
||||
* the predicate function for each element in the set until the predicate returns a value |
||||
* which is coercible to the Boolean value false, or until the end of the set. |
||||
* @param thisArg An object to which the this keyword can refer in the predicate function. |
||||
* If thisArg is omitted, undefined is used as the this value. |
||||
*/ |
||||
every( |
||||
predicate: (value: T, set: LdSet<T>) => unknown, |
||||
thisArg?: any, |
||||
): boolean; |
||||
/** |
||||
* Determines whether the specified callback function returns true for any element of a set. |
||||
* @param predicate A function that accepts up to two arguments. The some method calls |
||||
* the predicate function for each element in the set until the predicate returns a value |
||||
* which is coercible to the Boolean value true, or until the end of the set. |
||||
* @param thisArg An object to which the this keyword can refer in the predicate function. |
||||
* If thisArg is omitted, undefined is used as the this value. |
||||
*/ |
||||
some(predicate: (value: T, set: LdSet<T>) => unknown, thisArg?: any): boolean; |
||||
/** |
||||
* Performs the specified action for each element in an set. |
||||
* @param callbackfn A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the set. A "value2" is provided for parity with the base set. |
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value. |
||||
*/ |
||||
forEach( |
||||
callbackfn: (value: T, value2: T, set: LdSet<T>) => void, |
||||
thisArg?: any, |
||||
): void; |
||||
/** |
||||
* Calls a defined callback function on each element of an set, and returns a set that contains the results. |
||||
* @param callbackfn A function that accepts up to two arguments. The map method calls the callbackfn function one time for each element in the set. |
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value. |
||||
*/ |
||||
map<U>(callbackfn: (value: T, set: LdSet<T>) => U, thisArg?: any): U[]; |
||||
/** |
||||
* Returns the elements of a set that meet the condition specified in a callback function. |
||||
* @param predicate A function that accepts up to two arguments. The filter method calls the predicate function one time for each element in the set. |
||||
* @param thisArg An object to which the this keyword can refer in the predicate function. If thisArg is omitted, undefined is used as the this value. |
||||
*/ |
||||
filter<S extends T>( |
||||
predicate: (value: T, set: LdSet<T>) => value is S, |
||||
thisArg?: any, |
||||
): LdSet<S>; |
||||
/** |
||||
* Returns the elements of a set that meet the condition specified in a callback function. |
||||
* @param predicate A function that accepts up to two arguments. The filter method calls the predicate function one time for each element in the set. |
||||
* @param thisArg An object to which the this keyword can refer in the predicate function. If thisArg is omitted, undefined is used as the this value. |
||||
*/ |
||||
filter( |
||||
predicate: (value: T, set: LdSet<T>) => unknown, |
||||
thisArg?: any, |
||||
): LdSet<T>; |
||||
/** |
||||
* Calls the specified callback function for all the elements in a set. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
||||
* @param callbackfn A function that accepts up to three arguments. The reduce method calls the callbackfn function one time for each element in the set. |
||||
* @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. |
||||
*/ |
||||
reduce( |
||||
callbackfn: (previousValue: T, currentValue: T, set: LdSet<T>) => T, |
||||
): T; |
||||
/** |
||||
* Calls the specified callback function for all the elements in a set. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
||||
* @param callbackfn A function that accepts up to three arguments. The reduce method calls the callbackfn function one time for each element in the set. |
||||
* @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. |
||||
*/ |
||||
reduce( |
||||
callbackfn: (previousValue: T, currentValue: T, set: LdSet<T>) => T, |
||||
initialValue: T, |
||||
): T; |
||||
/** |
||||
* Calls the specified callback function for all the elements in a set. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. |
||||
* @param callbackfn A function that accepts up to three arguments. The reduce method calls the callbackfn function one time for each element in the set. |
||||
* @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. |
||||
*/ |
||||
reduce<U>( |
||||
callbackfn: (previousValue: U, currentValue: T, array: LdSet<T>) => U, |
||||
initialValue: U, |
||||
): U; |
||||
|
||||
/** |
||||
* Converts the current LdSet to an array. |
||||
*/ |
||||
toArray(): T[]; |
||||
|
||||
/** |
||||
* Converts to JSON |
||||
*/ |
||||
toJSON(): T[]; |
||||
|
||||
/** |
||||
* =========================================================================== |
||||
* EXTENDED SET METHODS |
||||
* =========================================================================== |
||||
*/ |
||||
/** |
||||
* Returns a new set containing elements in this set but not in the given set. |
||||
*/ |
||||
difference(other: Set<T>): LdSet<T>; |
||||
/** |
||||
* returns a new set containing elements in both this set and the given set. |
||||
*/ |
||||
intersection(other: Set<T>): LdSet<T>; |
||||
/** |
||||
* Returns a boolean indicating if this set has no elements in common with the given set. |
||||
*/ |
||||
isDisjointFrom(other: Set<T>): boolean; |
||||
/** |
||||
* Returns a boolean indicating if all elements of this set are in the given set. |
||||
*/ |
||||
isSubsetOf(other: Set<T>): boolean; |
||||
/** |
||||
* Returns a boolean indicating if all elements of the given set are in this set. |
||||
*/ |
||||
isSupersetOf(other: Set<T>): boolean; |
||||
/** |
||||
* Returns a new set containing elements which are in either this set or the given set, but not in both. |
||||
*/ |
||||
symmetricDifference(other: Set<T>): LdSet<T>; |
||||
/** |
||||
* Returns a new set containing elements which are in either or both of this set and the given set. |
||||
*/ |
||||
union(other: Set<T>): LdSet<T>; |
||||
} |
@ -0,0 +1,14 @@ |
||||
import type { RawValue } from "../util/RawObject"; |
||||
import { BasicLdSet } from "./ldSet/BasicLdSet"; |
||||
import type { LdSet } from "./ldSet/LdSet"; |
||||
|
||||
/** |
||||
* Creates an LdSet used by LDO as a list of items. |
||||
* @param values The list of items in the set |
||||
* @returns An LdSet |
||||
*/ |
||||
export function set<T>(...values: T[]): LdSet<T> { |
||||
return new BasicLdSet( |
||||
values as Iterable<NonNullable<RawValue>>, |
||||
) as unknown as LdSet<T>; |
||||
} |
@ -1,11 +1,11 @@ |
||||
export const _getUnderlyingNode = Symbol("_getUnderlyingNode"); |
||||
export const _getUnderlyingMatch = Symbol("_getUnderlyingMatch"); |
||||
export const _isSubjectOriented = Symbol("_isSubjectOriented"); |
||||
export const _getNodeAtIndex = Symbol("_getNodeAtIndex"); |
||||
export const _isLangString = Symbol("_isLangString"); |
||||
export const _getUnderlyingDataset = Symbol("_getUnderlyingDataset"); |
||||
export const _getUnderlyingArrayTarget = Symbol("_getUnderlyingArrayTarget"); |
||||
export const _proxyContext = Symbol("_proxyContext"); |
||||
export const _writeGraphs = Symbol("_writeGraphs"); |
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type ObjectLike = Record<string | number | symbol, any>; |
||||
export type LiteralLike = string | number | boolean; |
||||
|
@ -1,13 +1,21 @@ |
||||
import type { BlankNode, NamedNode } from "@rdfjs/types"; |
||||
import { _getUnderlyingNode } from "../types"; |
||||
import type { LdSet } from "../setProxy/ldSet/LdSet"; |
||||
import type { SubjectProxy } from "../subjectProxy/SubjectProxy"; |
||||
|
||||
export type RawObject = |
||||
| ({ |
||||
"@id"?: string | NamedNode | BlankNode; |
||||
} & { |
||||
[key: string | symbol | number]: RawValue | RawValue[]; |
||||
[key: string | symbol | number]: RawValue | LdSet<RawValue>; |
||||
}) |
||||
| SubjectProxy; |
||||
|
||||
export type RawValue = string | boolean | number | RawObject | undefined; |
||||
export type RawValue = |
||||
| string |
||||
| boolean |
||||
| number |
||||
| RawObject |
||||
| NamedNode |
||||
| BlankNode |
||||
| undefined; |
||||
|
@ -0,0 +1,325 @@ |
||||
import { namedNode } from "@rdfjs/data-model"; |
||||
import jsonldDatasetProxy, { BasicLdSet, _getUnderlyingNode } from "../src"; |
||||
import { createDataset } from "@ldo/dataset"; |
||||
|
||||
describe("BasicLdSet", () => { |
||||
describe("constructor and add", () => { |
||||
test("should add primitive values correctly", () => { |
||||
const set = new BasicLdSet<number>(); |
||||
expect(set.size).toBe(0); |
||||
set.add(1); |
||||
expect(set.size).toBe(1); |
||||
expect(set.has(1)).toBe(true); |
||||
// Duplicate primitives should not increase size.
|
||||
set.add(1); |
||||
expect(set.size).toBe(1); |
||||
}); |
||||
|
||||
test('should add objects with "@id" as string correctly', () => { |
||||
const obj1 = { "@id": "testId" }; |
||||
const set = new BasicLdSet(); |
||||
set.add(obj1); |
||||
expect(set.has(obj1)).toBe(true); |
||||
expect(set.size).toBe(1); |
||||
// A different object with the same "@id" should be considered a duplicate.
|
||||
const obj2 = { "@id": "testId" }; |
||||
set.add(obj2); |
||||
expect(set.size).toBe(1); |
||||
}); |
||||
|
||||
test('should add objects with "@id" as an object correctly', () => { |
||||
// In this case the object’s "@id" is a string already.
|
||||
const obj1 = { "@id": "testIdObj" }; |
||||
const set = new BasicLdSet(); |
||||
set.add(obj1); |
||||
expect(set.has(obj1)).toBe(true); |
||||
expect(set.size).toBe(1); |
||||
// A different object with an equivalent "@id" should not increase the size.
|
||||
const obj2 = { "@id": "testIdObj" }; |
||||
set.add(obj2); |
||||
expect(set.size).toBe(1); |
||||
}); |
||||
|
||||
test("should add LinkedDataObject", () => { |
||||
// In this case the object’s "@id" is a string already.
|
||||
const obj1 = jsonldDatasetProxy(createDataset(), {}).fromSubject( |
||||
namedNode("testIdObj"), |
||||
); |
||||
const set = new BasicLdSet(); |
||||
set.add(obj1); |
||||
expect(set.has(obj1)).toBe(true); |
||||
expect(set.size).toBe(1); |
||||
// A different object with an equivalent "@id" should not increase the size.
|
||||
const obj2 = { "@id": "testIdObj" }; |
||||
set.add(obj2); |
||||
expect(set.size).toBe(1); |
||||
}); |
||||
|
||||
test("should add objects with underlying nodes correctly", () => { |
||||
// Here we simulate a case where the object has a NamedNode stored as its "@id"
|
||||
// which in turn yields its .value.
|
||||
const obj1 = { "@id": namedNode("testIdObj") }; |
||||
const set = new BasicLdSet(); |
||||
set.add(obj1); |
||||
expect(set.has(obj1)).toBe(true); |
||||
expect(set.size).toBe(1); |
||||
// A different object with an equivalent "@id".value should not increase the size.
|
||||
const obj2 = { "@id": "testIdObj" }; |
||||
set.add(obj2); |
||||
expect(set.size).toBe(1); |
||||
}); |
||||
|
||||
test('should treat objects with no "@id" as unique even if same reference', () => { |
||||
// When an object does not have "@id" (or _getUnderlyingNode),
|
||||
// the hashFn falls back to generating a new blank node each time.
|
||||
const obj = {}; |
||||
const set = new BasicLdSet(); |
||||
set.add(obj); |
||||
// Adding the same object twice produces two different hash keys.
|
||||
set.add(obj); |
||||
expect(set.size).toBe(2); |
||||
}); |
||||
|
||||
test("should initialize with iterable values", () => { |
||||
const set = new BasicLdSet<number>([1, 2, 3, 3]); |
||||
expect(set.size).toBe(3); |
||||
expect([...set]).toEqual([1, 2, 3]); |
||||
}); |
||||
}); |
||||
|
||||
describe("clear", () => { |
||||
test("should clear all elements", () => { |
||||
const set = new BasicLdSet<number>([1, 2, 3]); |
||||
expect(set.size).toBe(3); |
||||
set.clear(); |
||||
expect(set.size).toBe(0); |
||||
expect([...set]).toEqual([]); |
||||
}); |
||||
}); |
||||
|
||||
describe("delete", () => { |
||||
test("should delete an existing element and return true", () => { |
||||
const set = new BasicLdSet<number>([1, 2, 3]); |
||||
expect(set.delete(2)).toBe(true); |
||||
expect(set.has(2)).toBe(false); |
||||
expect(set.size).toBe(2); |
||||
}); |
||||
|
||||
test("should return false when deleting a non-existent element", () => { |
||||
const set = new BasicLdSet<number>([1, 2, 3]); |
||||
expect(set.delete(4)).toBe(false); |
||||
expect(set.size).toBe(3); |
||||
}); |
||||
}); |
||||
|
||||
describe("has", () => { |
||||
test("should correctly identify the presence of elements", () => { |
||||
const set = new BasicLdSet<number>([1, 2, 3]); |
||||
expect(set.has(1)).toBe(true); |
||||
expect(set.has(4)).toBe(false); |
||||
}); |
||||
}); |
||||
|
||||
describe("iteration functions", () => { |
||||
test("every should return true if all elements satisfy the predicate", () => { |
||||
const set = new BasicLdSet<number>([2, 4, 6]); |
||||
const result = set.every((num) => num % 2 === 0); |
||||
expect(result).toBe(true); |
||||
}); |
||||
|
||||
test("every should return false if any element fails the predicate", () => { |
||||
const set = new BasicLdSet<number>([2, 3, 6]); |
||||
const result = set.every((num) => num % 2 === 0); |
||||
expect(result).toBe(false); |
||||
}); |
||||
|
||||
test("some should return true if any element satisfies the predicate", () => { |
||||
const set = new BasicLdSet<number>([1, 3, 4]); |
||||
const result = set.some((num) => num % 2 === 0); |
||||
expect(result).toBe(true); |
||||
}); |
||||
|
||||
test("some should return false if no element satisfies the predicate", () => { |
||||
const set = new BasicLdSet<number>([1, 3, 5]); |
||||
const result = set.some((num) => num % 2 === 0); |
||||
expect(result).toBe(false); |
||||
}); |
||||
|
||||
test("forEach should call the callback for each element", () => { |
||||
const set = new BasicLdSet<number>([1, 2, 3]); |
||||
const mockFn = jest.fn(); |
||||
set.forEach((value, value2, collection) => { |
||||
expect(collection).toBe(set); |
||||
expect(value).toBe(value2); |
||||
mockFn(value); |
||||
}); |
||||
expect(mockFn).toHaveBeenCalledTimes(3); |
||||
expect(mockFn).toHaveBeenCalledWith(1); |
||||
expect(mockFn).toHaveBeenCalledWith(2); |
||||
expect(mockFn).toHaveBeenCalledWith(3); |
||||
}); |
||||
|
||||
test("map should return an array with mapped values", () => { |
||||
const set = new BasicLdSet<number>([1, 2, 3]); |
||||
const result = set.map((num) => num * 2); |
||||
expect(result).toEqual([2, 4, 6]); |
||||
}); |
||||
|
||||
test("filter should return a new set with filtered elements", () => { |
||||
const set = new BasicLdSet<number>([1, 2, 3, 4]); |
||||
const filtered = set.filter((num) => num % 2 === 0); |
||||
expect(filtered.size).toBe(2); |
||||
expect(filtered.has(2)).toBe(true); |
||||
expect(filtered.has(4)).toBe(true); |
||||
}); |
||||
|
||||
test("reduce should work without an initial value", () => { |
||||
const set = new BasicLdSet<number>([1, 2, 3, 4]); |
||||
const result = set.reduce((acc, curr) => acc + curr); |
||||
expect(result).toBe(10); |
||||
}); |
||||
|
||||
test("reduce should work with an initial value", () => { |
||||
const set = new BasicLdSet<number>([1, 2, 3, 4]); |
||||
const result = set.reduce((acc, curr) => acc + curr, 10); |
||||
expect(result).toBe(20); |
||||
}); |
||||
|
||||
test("reduce should throw an error for an empty set without an initial value", () => { |
||||
const set = new BasicLdSet<number>(); |
||||
expect(() => { |
||||
set.reduce((acc, curr) => acc + curr); |
||||
}).toThrow("Reduce of empty collection with no initial value"); |
||||
}); |
||||
|
||||
test("toArray and toJSON should return an array of elements", () => { |
||||
const elements = [1, 2, 3]; |
||||
const set = new BasicLdSet<number>(elements); |
||||
expect(set.toArray()).toEqual(elements); |
||||
expect(set.toJSON()).toEqual(elements); |
||||
}); |
||||
}); |
||||
|
||||
describe("set operations", () => { |
||||
test("difference should return elements in the first set not present in the second", () => { |
||||
const set1 = new BasicLdSet<number>([1, 2, 3, 4]); |
||||
const set2 = new Set<number>([3, 4, 5]); |
||||
const diff = set1.difference(set2); |
||||
expect(diff.size).toBe(2); |
||||
expect(diff.has(1)).toBe(true); |
||||
expect(diff.has(2)).toBe(true); |
||||
}); |
||||
|
||||
test("intersection should return only the common elements", () => { |
||||
const set1 = new BasicLdSet<number>([1, 2, 3, 4]); |
||||
const set2 = new BasicLdSet<number>([3, 4, 5]); |
||||
const inter = set1.intersection(set2); |
||||
expect(inter.size).toBe(2); |
||||
expect(inter.has(3)).toBe(true); |
||||
expect(inter.has(4)).toBe(true); |
||||
const inter2 = set2.intersection(set1); |
||||
expect(inter2.size).toBe(2); |
||||
expect(inter2.has(3)).toBe(true); |
||||
expect(inter2.has(4)).toBe(true); |
||||
}); |
||||
|
||||
test("isDisjointFrom should return true if the sets have no common elements", () => { |
||||
const set1 = new BasicLdSet<number>([1, 2]); |
||||
const set2 = new BasicLdSet<number>([3, 4, 5]); |
||||
expect(set1.isDisjointFrom(set2)).toBe(true); |
||||
expect(set2.isDisjointFrom(set1)).toBe(true); |
||||
}); |
||||
|
||||
test("isDisjointFrom should return false if the sets share elements", () => { |
||||
const set1 = new BasicLdSet<number>([1, 2]); |
||||
const set2 = new Set<number>([2, 3]); |
||||
expect(set1.isDisjointFrom(set2)).toBe(false); |
||||
}); |
||||
|
||||
test("isSubsetOf should return true when the set is a subset of another", () => { |
||||
const set1 = new BasicLdSet<number>([1, 2]); |
||||
const set2 = new BasicLdSet<number>([1, 2, 3]); |
||||
expect(set1.isSubsetOf(set2)).toBe(true); |
||||
expect(set2.isSubsetOf(set1)).toBe(false); |
||||
}); |
||||
|
||||
test("isSubsetOf should return false when the set is not a subset of another", () => { |
||||
const set1 = new BasicLdSet<number>([1, 2, 4]); |
||||
const set2 = new Set<number>([1, 2, 3]); |
||||
expect(set1.isSubsetOf(set2)).toBe(false); |
||||
}); |
||||
|
||||
test("isSupersetOf should return true when the set is a superset of another", () => { |
||||
const set1 = new BasicLdSet<number>([1, 2, 3]); |
||||
const set2 = new Set<number>([1, 2]); |
||||
expect(set1.isSupersetOf(set2)).toBe(true); |
||||
}); |
||||
|
||||
test("isSupersetOf should return false when the set is larger", () => { |
||||
const set1 = new BasicLdSet<number>([1, 2]); |
||||
const set2 = new BasicLdSet<number>([1, 2, 3]); |
||||
expect(set1.isSupersetOf(set2)).toBe(false); |
||||
}); |
||||
|
||||
test("isSupersetOf should return false when the set is not a superset of another", () => { |
||||
const set1 = new BasicLdSet<number>([1, 2, 5]); |
||||
const set2 = new BasicLdSet<number>([1, 2, 3]); |
||||
expect(set1.isSupersetOf(set2)).toBe(false); |
||||
}); |
||||
|
||||
test("symmetricDifference should return the symmetric difference of two sets", () => { |
||||
const set1 = new BasicLdSet<number>([1, 2, 3]); |
||||
const set2 = new Set<number>([2, 3, 4]); |
||||
const symDiff = set1.symmetricDifference(set2); |
||||
expect(symDiff.size).toBe(2); |
||||
expect(symDiff.has(1)).toBe(true); |
||||
expect(symDiff.has(4)).toBe(true); |
||||
}); |
||||
|
||||
test("union should return the union of two sets", () => { |
||||
const set1 = new BasicLdSet<number>([1, 2]); |
||||
const set2 = new Set<number>([2, 3]); |
||||
const union = set1.union(set2); |
||||
expect(union.size).toBe(3); |
||||
expect(union.has(1)).toBe(true); |
||||
expect(union.has(2)).toBe(true); |
||||
expect(union.has(3)).toBe(true); |
||||
}); |
||||
}); |
||||
|
||||
describe("iterator methods", () => { |
||||
test("entries returns pairs [value, value]", () => { |
||||
const set = new BasicLdSet<number>([1, 2, 3]); |
||||
const entries = Array.from(set.entries()); |
||||
expect(entries).toEqual([ |
||||
[1, 1], |
||||
[2, 2], |
||||
[3, 3], |
||||
]); |
||||
}); |
||||
|
||||
test("keys returns all values", () => { |
||||
const set = new BasicLdSet<number>([1, 2, 3]); |
||||
const keys = Array.from(set.keys()); |
||||
expect(keys).toEqual([1, 2, 3]); |
||||
}); |
||||
|
||||
test("values returns all values", () => { |
||||
const set = new BasicLdSet<number>([1, 2, 3]); |
||||
const values = Array.from(set.values()); |
||||
expect(values).toEqual([1, 2, 3]); |
||||
}); |
||||
|
||||
test("iterator returns all values", () => { |
||||
const set = new BasicLdSet<number>([1, 2, 3]); |
||||
const iterated = [...set]; |
||||
expect(iterated).toEqual([1, 2, 3]); |
||||
}); |
||||
|
||||
test("toStringTag returns 'BasicLdSet'", () => { |
||||
const set = new BasicLdSet<number>(); |
||||
expect(Object.prototype.toString.call(set)).toBe("[object BasicLdSet]"); |
||||
expect(set[Symbol.toStringTag]).toBe("BasicLdSet"); |
||||
}); |
||||
}); |
||||
}); |
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@ |
||||
{ |
||||
"extends": "../../tsconfig.base.json", |
||||
"compilerOptions": { |
||||
"outDir": "./dist" |
||||
"outDir": "./dist", |
||||
}, |
||||
"include": ["./src"] |
||||
} |
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue