-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #950 from IntersectMBO/feat/942-create-govtool-met…
…adata-submission-service feat(942): create govtool metadata submission service
- Loading branch information
Showing
21 changed files
with
4,256 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
coverage | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# Metadata Service Package | ||
|
||
🔍 This package provides a set of tools for managing metadata. It includes a `MetadataService` for handling metadata operations and a `MetadataProvider` for providing metadata context to React components. | ||
|
||
![Statements](https://img.shields.io/badge/statements-96.33%25-brightgreen.svg?style=flat) | ||
![Branches](https://img.shields.io/badge/branches-80%25-yellow.svg?style=flat) | ||
![Functions](https://img.shields.io/badge/functions-90.9%25-brightgreen.svg?style=flat) | ||
![Lines](https://img.shields.io/badge/lines-96.33%25-brightgreen.svg?style=flat) | ||
|
||
## Getting started | ||
|
||
First, install the package in your project: | ||
|
||
```bash | ||
yarn add metadata-service | ||
``` | ||
|
||
### MetadataProvider | ||
|
||
Wrap your application in the `MetadataProvider`: | ||
|
||
```jsx | ||
import { MetadataProvider } from "metadata-service"; | ||
|
||
function App() { | ||
return ( | ||
<MetadataProvider> | ||
<YourComponent /> | ||
</MetadataProvider> | ||
); | ||
} | ||
``` | ||
|
||
Now you can use the `useMetadata` hook to access metadata context in your components: | ||
|
||
```jsx | ||
import { useMetadata } from "metadata-service"; | ||
|
||
function YourComponent() { | ||
const metadata = useMetadata(); | ||
|
||
// Use the metadata here... | ||
|
||
return <div>{/* Your component's JSX... */}</div>; | ||
} | ||
``` | ||
|
||
### MetadataService | ||
|
||
You can also use the `MetadataService` directly to perform metadata operations: | ||
|
||
```jsx | ||
import { MetadataService } from "metadata-service"; | ||
|
||
const metadataService = new MetadataService({ | ||
cip: CIP_Reference["0108"], | ||
hashAlgorithm: "blake2b-256", | ||
body: { | ||
title: "My title", | ||
abstract: "My abstract", | ||
motivation: "My motivation", | ||
rationale: "My rationale", | ||
references: [{ label: "some url", uri: "http://some.url" }], | ||
}, | ||
}); | ||
|
||
metadataService.initialize().then((service) => { | ||
// ...use the service here | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module.exports = { | ||
presets: [ | ||
"@babel/preset-env", // Include any other presets you may need | ||
"@babel/preset-react", // Add @babel/preset-react | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./src"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/** | ||
* For a detailed explanation regarding each configuration property, visit: | ||
* https://jestjs.io/docs/configuration | ||
*/ | ||
|
||
/** @type {import('jest').Config} */ | ||
const config = { | ||
clearMocks: true, | ||
collectCoverage: true, | ||
coverageDirectory: "coverage", | ||
coverageProvider: "v8", | ||
coverageReporters: ["json-summary"], | ||
testEnvironment: "jsdom", | ||
preset: "ts-jest", | ||
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"], | ||
moduleNameMapper: { | ||
"^@/(.*)$": "<rootDir>/src/$1", | ||
}, | ||
}; | ||
|
||
module.exports = config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
require("@testing-library/jest-dom"); | ||
|
||
const { TextDecoder, TextEncoder } = require("text-encoding"); | ||
global.TextDecoder = TextDecoder; | ||
global.TextEncoder = TextEncoder; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"name": "govtool-submission-tool", | ||
"version": "0.0.1", | ||
"scripts": { | ||
"test": "jest" | ||
}, | ||
"dependencies": { | ||
"blakejs": "^1.2.1", | ||
"jsonld": "^8.3.2", | ||
"react": "^18.3.1", | ||
"react-dom": "^18.3.1", | ||
"zod": "^3.23.6" | ||
}, | ||
"devDependencies": { | ||
"@babel/preset-env": "^7.24.5", | ||
"@babel/preset-react": "^7.24.1", | ||
"@testing-library/dom": "^10.1.0", | ||
"@testing-library/jest-dom": "^6.4.5", | ||
"@testing-library/react": "^15.0.7", | ||
"@types/jest": "^29.5.12", | ||
"@types/jsonld": "^1.5.13", | ||
"@types/react": "^18.3.1", | ||
"@types/text-encoding": "^0.0.39", | ||
"jest": "^29.7.0", | ||
"jest-environment-jsdom": "^29.7.0", | ||
"text-encoding": "^0.7.0", | ||
"ts-jest": "^29.1.2", | ||
"typescript": "^5.4.5" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
export const CIP_0108_CONTEXT = { | ||
"@language": "en-us", | ||
CIP100: | ||
"https://github.com/cardano-foundation/CIPs/blob/master/CIP-0100/README.md#", | ||
CIP108: | ||
"https://github.com/cardano-foundation/CIPs/blob/master/CIP-0108/README.md#", | ||
hashAlgorithm: "CIP100:hashAlgorithm", | ||
body: { | ||
"@id": "CIP108:body", | ||
"@context": { | ||
references: { | ||
"@id": "CIP108:references", | ||
"@container": "@set" as const, | ||
"@context": { | ||
GovernanceMetadata: "CIP100:GovernanceMetadataReference", | ||
Other: "CIP100:OtherReference", | ||
label: "CIP100:reference-label", | ||
uri: "CIP100:reference-uri", | ||
referenceHash: { | ||
"@id": "CIP108:referenceHash", | ||
"@context": { | ||
hashDigest: "CIP108:hashDigest", | ||
hashAlgorithm: "CIP100:hashAlgorithm", | ||
}, | ||
}, | ||
}, | ||
}, | ||
title: "CIP108:title", | ||
abstract: "CIP108:abstract", | ||
motivation: "CIP108:motivation", | ||
rationale: "CIP108:rationale", | ||
}, | ||
}, | ||
authors: { | ||
"@id": "CIP100:authors", | ||
"@container": "@set" as const, | ||
"@context": { | ||
name: "http://xmlns.com/foaf/0.1/name", | ||
witness: { | ||
"@id": "CIP100:witness", | ||
"@context": { | ||
witnessAlgorithm: "CIP100:witnessAlgorithm", | ||
publicKey: "CIP100:publicKey", | ||
signature: "CIP100:signature", | ||
}, | ||
}, | ||
}, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./context"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export * from "./consts"; | ||
export * from "./schemas"; | ||
export * from "./services"; | ||
export * from "./types"; |
42 changes: 42 additions & 0 deletions
42
govtool/packages/submission-tool/src/providers/MetadataProvider.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { render, screen } from "@testing-library/react"; | ||
import { MetadataProvider, useMetadata } from "@/providers/MetadataProvider"; | ||
|
||
describe("MetadataProvider", () => { | ||
it("renders its children", () => { | ||
render( | ||
<MetadataProvider> | ||
<div>Child Component</div> | ||
</MetadataProvider> | ||
); | ||
|
||
const childComponent = screen.getByText("Child Component"); | ||
expect(childComponent).toBeDefined(); | ||
}); | ||
|
||
it("provides the validate and build functions in the context", () => { | ||
const TestComponent = () => { | ||
const { validate, build } = useMetadata(); | ||
expect(typeof validate).toBe("function"); | ||
expect(typeof build).toBe("function"); | ||
|
||
return null; | ||
}; | ||
|
||
render( | ||
<MetadataProvider> | ||
<TestComponent /> | ||
</MetadataProvider> | ||
); | ||
}); | ||
|
||
it("throws an error when useMetadata is used outside of MetadataProvider", () => { | ||
const TestComponent = () => { | ||
useMetadata(); | ||
return null; | ||
}; | ||
|
||
expect(() => render(<TestComponent />)).toThrow( | ||
"useMetadata must be used within a MetadataProvider" | ||
); | ||
}); | ||
}); |
65 changes: 65 additions & 0 deletions
65
govtool/packages/submission-tool/src/providers/MetadataProvider.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import { | ||
createContext, | ||
useContext, | ||
useMemo, | ||
useCallback, | ||
PropsWithChildren, | ||
} from "react"; | ||
|
||
import { MetadataService } from "@/services"; | ||
import { MetadataConfig } from "@/types"; | ||
|
||
type MetadataContextValues = { | ||
validate: (data: MetadataConfig) => void; | ||
build: (config: MetadataConfig) => Promise<MetadataService>; | ||
}; | ||
|
||
const MetadataContext = createContext<MetadataContextValues | null>(null); | ||
|
||
/** | ||
* Provides metadata validation and building functionality to its children components. | ||
* @param children - The child components to be wrapped by the MetadataProvider. | ||
*/ | ||
export const MetadataProvider = ({ children }: PropsWithChildren) => { | ||
/** | ||
* Validates the metadata configuration. | ||
* | ||
* @param data - The metadata configuration to validate. | ||
* @returns A promise that resolves to the validation result. | ||
*/ | ||
const validate = useCallback( | ||
(data: MetadataConfig) => new MetadataService(data).validateMetadata(), | ||
[] | ||
); | ||
|
||
/** | ||
* Builds the metadata using the provided configuration. | ||
* @param config The configuration for building the metadata. | ||
* @returns A promise that resolves to the built metadata. | ||
*/ | ||
const build = useCallback( | ||
(config: MetadataConfig) => new MetadataService(config).build(), | ||
[] | ||
); | ||
|
||
const value = useMemo(() => ({ validate, build }), [validate, build]); | ||
|
||
return ( | ||
<MetadataContext.Provider value={value}> | ||
{children} | ||
</MetadataContext.Provider> | ||
); | ||
}; | ||
|
||
/** | ||
* Custom hook that provides access to the metadata context. | ||
* @returns The metadata context. | ||
* @throws {Error} If used outside of a MetadataProvider. | ||
*/ | ||
export const useMetadata = () => { | ||
const context = useContext(MetadataContext); | ||
if (!context) { | ||
throw new Error("useMetadata must be used within a MetadataProvider"); | ||
} | ||
return context; | ||
}; |
14 changes: 14 additions & 0 deletions
14
govtool/packages/submission-tool/src/schemas/cipSchemas.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { z } from "zod"; | ||
|
||
export const CIP0108ValidationSchema = z.object({ | ||
title: z.string().max(80), | ||
abstract: z.string().max(2500), | ||
motivation: z.string(), | ||
rationale: z.string(), | ||
references: z.array( | ||
z.object({ | ||
label: z.string(), | ||
uri: z.string().url(), | ||
}) | ||
), | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from "./cipSchemas"; |
53 changes: 53 additions & 0 deletions
53
govtool/packages/submission-tool/src/services/MetadataService.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { CIP_Reference } from ".."; | ||
import { MetadataService } from "./MetadataService"; | ||
|
||
describe("MetadataService", () => { | ||
it("should initialize jsonld and hash", async () => { | ||
// Arrange | ||
const metadataService = new MetadataService({ | ||
cip: CIP_Reference["0108"], | ||
hashAlgorithm: "blake2b-256", | ||
body: { | ||
title: "123", | ||
abstract: "My abstract", | ||
motivation: "My motivation", | ||
rationale: "My rationale", | ||
references: [{ label: "some url", uri: "http://some.url" }], | ||
}, | ||
}); | ||
|
||
// Act | ||
await metadataService.initialize(); | ||
const jsonld = metadataService.jsonld; | ||
const hash = metadataService.hash; | ||
|
||
// Assert | ||
expect(jsonld).toBeDefined(); | ||
expect(jsonld).not.toBeNull(); | ||
// TODO: Add structure assertions to the jsonld | ||
|
||
expect(hash).toBeDefined(); | ||
expect(hash).not.toBeNull(); | ||
}); | ||
|
||
it("should fail on body validation", async () => { | ||
try { | ||
new MetadataService({ | ||
cip: CIP_Reference["0108"], | ||
hashAlgorithm: "blake2b-256", | ||
body: { | ||
// For the testing purposes | ||
// @ts-expect-error | ||
title: 123, | ||
abstract: "My abstract", | ||
motivation: "My motivation", | ||
rationale: "My rationale", | ||
references: [{ label: "some url", uri: "http://some.url" }], | ||
}, | ||
}); | ||
} catch (error) { | ||
expect(error).toBeDefined(); | ||
expect((error as any).message).toBe("Invalid metadata body"); | ||
} | ||
}); | ||
}); |
Oops, something went wrong.