Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Schema.regen.network browser & RDFS Ontology POC #54

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions rdfs/regen.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is mostly a dummy file with some basic data to see what setting up a website that renders based on RDFS ontologies would look like.

After further research, I do think that it might be best for us to lean into OWL ontologies instead, but curious to hear others' feedback on that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you share more on that @clevinson?
BTW reading the articles you've shared is on my TODO list https://archive.topquadrant.com/owl-blog/ vs https://triply.cc/blog/2021-08-why-we-use-owl/

@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix regen: <http://schema.regen.network#> .
@prefix schema: <http://schema.org/> .

regen:CreditClass a rdfs:Class ;
rdfs:comment "A class of credits that can be issued for a project. Each credit class has specific methodologies and rules for issuing credits." ;
rdfs:label "Credit Class" ;
.

regen:offsetGenerationMethod a rdf:Property ;
rdfs:label "Offset Generation Method" ;
rdfs:domain regen:CreditClass ;
rdfs:range xsd:string ;
rdfs:comment "In the case where a credit represents an offset, offset generation method represents the mechanicsm by which the credit is to be counted as an offset (e.g. Avoided Emissions, Carbon Sequestration)" ;
.

regen:coBenefits a rdf:Property ;
rdfs:label "Co-Benefits" ;
rdfs:domain regen:CreditClass ;
rdfs:range schema:ItemList;
rdfs:comment "A list of co-benefits expected to be available for projects under a given Credit Class."
.

regen:approvedMethodologies a rdf:Property ;
rdfs:label "Approved Methodologies" ;
rdfs:domain regen:CreditClass ;
rdfs:range schema:ItemList;
rdfs:comment "A list of versioned methodologies that are approved for a given Credit Class, or a specific project. List Items are all of the type 'Methodology Version'";
.

regen:Project a rdfs:Class ;
rdfs:comment "" ;
rdfs:label "Project" ;
.

regen:additionalCertification a rdf:Property ;
rdfs:label "Additional Certification" ;
rdfs:domain regen:Project ;
rdfs:range regen:CertificationProtocol;
rdfs:comment "An optional additional certification for a given project.";
.

schema:name a rdf:Property ;
rdfs:label "Name" ;
rdfs:domain regen:Project ;
rdfs:range xsd:string;
rdfs:comment "The name of a resource";
.

regen:landManagementPractices a rdf:Property ;
rdfs:label "Land Management Practices" ;
rdfs:domain regen:Project ;
rdfs:range schema:ItemList;
rdfs:comment "Land management practices used by the project (ex. no-till, cover cropping, etc...)";
.

regen:CertificationProtocol a rdfs:Class ;
rdfs:comment "A certification protocol used for tracking project co-benefits" ;
rdfs:label "Certification Protocol" ;
.

regen:Methodology rdfs:subClassOf regen:CertificationProtocol;
.

regen:documentId a rdf:Property ;
rdfs:label "Document ID" ;
rdfs:domain regen:CertificationProtocol ;
rdfs:range xsd:string ;
rdfs:comment "The identifier of the document." .

schema:url a rdf:Property ;
rdfs:label "URL" ;
rdfs:domain regen:CertificationProtocol;
rdfs:range schema:URL ;
rdfs:comment "The URL of the resource." .

schema:version a rdf:Property ;
rdfs:label "Version" ;
rdfs:domain regen:CertificationProtocol ;
rdfs:range xsd:string ;
rdfs:comment "The version of the resource."
.
3 changes: 3 additions & 0 deletions schema-www/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
35 changes: 35 additions & 0 deletions schema-www/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
30 changes: 30 additions & 0 deletions schema-www/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:

```bash
yarn dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
8 changes: 8 additions & 0 deletions schema-www/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** @type {import('next').NextConfig} */
module.exports = {
experimental: { appDir: true },
webpack(config) {
config.experiments = { ...config.experiments, topLevelAwait: true };
return config;
},
};
31 changes: 31 additions & 0 deletions schema-www/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "regen-schema-js",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@types/node": "20.1.2",
"@types/react": "18.2.8",
"@types/react-dom": "18.2.4",
"@zeit/next-css": "^1.0.1",
"autoprefixer": "10.4.14",
"encoding": "^0.1.13",
"eslint": "8.40.0",
"eslint-config-next": "13.4.1",
"fs-extra": "^11.1.1",
"next": "13.4.1",
"postcss": "8.4.23",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-preset-env": "^8.4.1",
"rdflib": "^2.2.32",
"react": "18.2.0",
"react-dom": "18.2.0",
"tailwindcss": "npm:@tailwindcss/postcss7-compat",
"typescript": "5.1.3"
}
}
6 changes: 6 additions & 0 deletions schema-www/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
113 changes: 113 additions & 0 deletions schema-www/src/app/[item]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import fs from "fs/promises";
import path from "path";
import * as rdf from "rdflib";

import ClassView from "../../components/ClassView";
import PropertyView from "../../components/PropertyView";
import { Property, Class } from "../../types";

import { BASE_URI, REGEN, RDF, RDFS } from "../../utils/namespaces";

export const generateStaticParams = async () => {
const filePath = path.join(process.cwd(), "../rdfs", `regen.ttl`);
const fileContents = await fs.readFile(filePath, "utf8");

// Parse the RDF data
const store = rdf.graph();
rdf.parse(fileContents, store, BASE_URI, "text/turtle");

const classStatements = store
.statementsMatching(undefined, RDF("type"), RDFS("Class"))
.filter((statement) => statement.subject.value.startsWith(BASE_URI));

const propertyStatements = store
.statementsMatching(undefined, RDF("type"), RDF("Property"))
.filter((statement) => statement.subject.value.startsWith(BASE_URI));

const params = classStatements
.concat(propertyStatements)
.map((statement) => ({
item: statement.subject.value.split("#").pop(),
}));

return params;
};

const getItem = async (itemSlug: string) => {
const filePath = path.join(process.cwd(), "../rdfs", `regen.ttl`);
const fileContents = await fs.readFile(filePath, "utf8");

// Parse the RDF data
const store = rdf.graph();
rdf.parse(fileContents, store, BASE_URI, "text/turtle");
const item = REGEN(`${itemSlug}`);

const itemType = store.any(item, RDF("type"));
if (!itemType) throw new Error(`No type found for ${item}`);

if (itemType.value == RDF("Property").value) {
// Fetch property data
const label = store.any(item, RDFS("label"))?.value;
const comment = store.any(item, RDFS("comment"))?.value;
const ranges = store
.statementsMatching(item, RDFS("range"), undefined)
.map((statement) => statement.object.value);
const domains = store
.statementsMatching(item, RDFS("domain"), undefined)
.map((statement) => statement.object.value);

return {
type: "property",
iri: item.value,
label,
description: comment,
ranges,
domains,
};
} else if (itemType.value == RDFS("Class").value) {
// Fetch class data
const label = store.any(item, RDFS("label"))?.value;
const comment = store.any(item, RDFS("comment"))?.value;
const properties = store
.statementsMatching(undefined, RDFS("domain"), item)
.map((statement) => {
const label = statement.subject.value;
const ranges = store
.statementsMatching(statement.subject, RDFS("range"), undefined)
.map((propRange) => {
return propRange.object.value;
});
const description = store.any(
statement.subject,
RDFS("comment")
)?.value;
return { type: "property", label, ranges, description };
});

return {
type: "class",
iri: item.value,
label,
description: comment,
properties,
};
} else {
throw new Error(`Unhandled type for ${item}`);
}
};

const ItemPage = async ({ params }: { params: { item: string } }) => {
const itemSlug = params.item;

const item = await getItem(itemSlug);
const componentType = item.type;
const isClass = componentType === "class";
const isProperty = componentType === "property";

return <>
{isClass && <ClassView {...(item as Class)} />}
{isProperty && <PropertyView {...(item as Property)} />}
</>
};

export default ItemPage;
17 changes: 17 additions & 0 deletions schema-www/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Link from "next/link";
import "../styles/globals.css";

function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body className="h-screen">
<header className="p-4 bg-green-500 text-gray-700 font-bold">
<Link href="/">schema.regen.network</Link>
</header>
{children}
</body>
</html>
);
}

export default RootLayout;
Loading