diff --git a/packages/graph-framework-identity/package.json b/packages/graph-framework-identity/package.json new file mode 100644 index 00000000..6869f68d --- /dev/null +++ b/packages/graph-framework-identity/package.json @@ -0,0 +1,28 @@ +{ + "name": "graph-framework-identity", + "version": "0.0.1", + "description": "", + "type": "module", + "scripts": { + "test": "vitest run --typecheck", + "ts:check": "tsc --noEmit", + "lint": "echo 'No linting configured'" + }, + "exports": { + ".": { + "default": "./src/index.js" + } + }, + "peerDependencies": { + "@effect/schema": "^0.74" + }, + "devDependencies": { + "@effect/schema": "^0.74.1", + "vite": "^5.4.8", + "vitest": "^2.1.1" + }, + "dependencies": { + "uuid": "^10.0.0", + "graph-framework-utils": "workspace:*" + } +} diff --git a/packages/graph-framework-identity/src/create-identity.test.ts b/packages/graph-framework-identity/src/create-identity.test.ts new file mode 100644 index 00000000..11d1fbe9 --- /dev/null +++ b/packages/graph-framework-identity/src/create-identity.test.ts @@ -0,0 +1,6 @@ +import { expect, it } from "vitest"; +import { createIdentity } from "./create-identity.js"; + +it.skip("should generate an identity", () => { + expect(createIdentity()).toEqual({}); +}); diff --git a/packages/graph-framework/src/identity/create-identity.ts b/packages/graph-framework-identity/src/create-identity.ts similarity index 100% rename from packages/graph-framework/src/identity/create-identity.ts rename to packages/graph-framework-identity/src/create-identity.ts diff --git a/packages/graph-framework-identity/src/index.tsx b/packages/graph-framework-identity/src/index.tsx new file mode 100644 index 00000000..b26e0952 --- /dev/null +++ b/packages/graph-framework-identity/src/index.tsx @@ -0,0 +1,2 @@ +export * from "./create-identity.js"; +export * from "./restore-identity.js"; diff --git a/packages/graph-framework/src/identity/restore-identity.ts b/packages/graph-framework-identity/src/restore-identity.ts similarity index 100% rename from packages/graph-framework/src/identity/restore-identity.ts rename to packages/graph-framework-identity/src/restore-identity.ts diff --git a/packages/graph-framework-identity/tsconfig.json b/packages/graph-framework-identity/tsconfig.json new file mode 100644 index 00000000..062fb3da --- /dev/null +++ b/packages/graph-framework-identity/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "strict": true, + "noUncheckedIndexedAccess": true, + "esModuleInterop": true, + "sourceMap": true, + "declarationMap": true, + "declaration": true, + "strictNullChecks": true, + "incremental": true, + "composite": true, + "allowJs": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "noErrorTruncation": true, + "isolatedModules": true, + "target": "ESNext", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "./dist", + "rootDir": "./src", + "jsx": "react-jsx" + }, + "include": ["./src"] +} diff --git a/packages/graph-framework-identity/vite.config.js b/packages/graph-framework-identity/vite.config.js new file mode 100644 index 00000000..290663c3 --- /dev/null +++ b/packages/graph-framework-identity/vite.config.js @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; + +// https://vitejs.dev/config/ +export default defineConfig({}); diff --git a/packages/graph-framework-schema/package.json b/packages/graph-framework-schema/package.json new file mode 100644 index 00000000..814b2484 --- /dev/null +++ b/packages/graph-framework-schema/package.json @@ -0,0 +1,41 @@ +{ + "name": "graph-framework-schema", + "version": "0.0.1", + "description": "", + "type": "module", + "scripts": { + "test": "vitest run --typecheck", + "ts:check": "tsc --noEmit", + "lint": "echo 'No linting configured'" + }, + "exports": { + ".": { + "default": "./src/index.js" + } + }, + "peerDependencies": { + "@automerge/automerge": "^2", + "@automerge/automerge-repo": "^1", + "@automerge/automerge-repo-react-hooks": "^1", + "@effect/schema": "^0.74", + "react": "^18" + }, + "devDependencies": { + "@automerge/automerge": "^2.2.8", + "@automerge/automerge-repo": "^1.2.1", + "@automerge/automerge-repo-react-hooks": "^1.2.1", + "@effect/schema": "^0.74.1", + "@testing-library/jest-dom": "^6.5.0", + "@testing-library/react": "^16.0.1", + "@types/react": "^18.3.7", + "@types/uuid": "^10.0.0", + "@vitejs/plugin-react": "^4.3.2", + "jsdom": "^25.0.1", + "vite": "^5.4.8", + "vitest": "^2.1.1" + }, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "graph-framework-utils": "workspace:*" + } +} diff --git a/packages/graph-framework/src/context.tsx b/packages/graph-framework-schema/src/context.tsx similarity index 100% rename from packages/graph-framework/src/context.tsx rename to packages/graph-framework-schema/src/context.tsx diff --git a/packages/graph-framework-schema/src/index.test.tsx b/packages/graph-framework-schema/src/index.test.tsx new file mode 100644 index 00000000..8cd52cc9 --- /dev/null +++ b/packages/graph-framework-schema/src/index.test.tsx @@ -0,0 +1,290 @@ +import "@testing-library/jest-dom/vitest"; +import { act, cleanup, renderHook } from "@testing-library/react"; +import React from "react"; +import { + afterEach, + beforeEach, + describe, + expect, + expectTypeOf, + it, +} from "vitest"; +import { createFunctions, repo, type } from "./context.js"; + +afterEach(() => { + cleanup(); +}); + +describe("Library Tests", () => { + const schema = { + types: { + Person: { + name: type.Text, + age: type.Number, + badges: type.Relation({ + types: ["Badge"] as const, + cardinality: "many", + }), + }, + User: { + name: type.Text, + email: type.Text, + }, + Badge: { + name: type.Text, + }, + Event: { + name: type.Text, + participants: type.Relation({ + types: ["Person"] as const, + cardinality: "many", + }), + author: type.Relation({ + types: ["User", "Person"] as const, + cardinality: "one", + }), + }, + }, + }; + + // Create functions from the schema + const { + useCreateEntity, + useDeleteEntity, + useQuery, + SpaceProvider, + createDocumentId, + } = createFunctions(schema); + + let repoResult = repo.create(); + let wrapper = ({ children }: { children: React.ReactNode }) => ( + {children} + ); + + beforeEach(() => { + repoResult = repo.create(); + wrapper = ({ children }: { children: React.ReactNode }) => ( + {children} + ); + }); + + it("should create one entity successfully", () => { + expect([1]).toHaveLength(1); + + const { result: createResult } = renderHook(() => useCreateEntity(), { + wrapper, + }); + + const { result: queryResult } = renderHook( + () => useQuery({ types: ["Event"] }), + { wrapper } + ); + + act(() => { + createResult.current(["Event"], { + name: "Conference", + participants: [ + { + name: "Alice", + age: 30, + badges: [{ name: "Speaker" }], + }, + { + name: "Bob", + age: 25, + badges: [{ name: "Attendee" }], + }, + ], + author: { + name: "Charlie", + email: "charlie@example.com", + age: 35, + badges: [{ name: "VIP" }], + }, + }); + }); + + const events = queryResult.current; + expect(events).toHaveLength(1); + }); + + it("should create and query entities with relations", () => { + const { result: createResult } = renderHook(() => useCreateEntity(), { + wrapper, + }); + + const { result: queryResult } = renderHook( + () => useQuery({ types: ["Event"] }), + { wrapper } + ); + + act(() => { + createResult.current(["Event"], { + name: "Conference", + participants: [ + { + name: "Alice", + age: 30, + badges: [{ name: "Speaker" }], + }, + { + name: "Bob", + age: 25, + badges: [{ name: "Attendee" }], + }, + ], + author: { + name: "Charlie", + email: "charlie@example.com", + age: 35, + badges: [{ name: "VIP" }], + }, + }); + }); + + // Wait for the hook to update + const events = queryResult.current; + expect(events).toHaveLength(1); + + const event = events[0]; + if (!event) { + throw new Error("Event not found"); + } + expect(event.id).toBeTypeOf("string"); + expect(event.types).toStrictEqual(["Event"]); + expect(event.name).toBe("Conference"); + + // Check participants + expect(event.participants).toHaveLength(2); + if ( + !event.participants[0] || + !event.participants[1] || + !event.participants[0].badges[0] || + !event.participants[1].badges[0] + ) { + throw new Error("Participants not found"); + } + + expect(event.participants[0].id).toBeTypeOf("string"); + expect(event.participants[0].types).toStrictEqual(["Person"]); + expect(event.participants[0].name).toBe("Alice"); + expect(event.participants[0].age).toBe(30); + expect(event.participants[0].badges).toHaveLength(1); + expect(event.participants[0].badges[0].name).toBe("Speaker"); + + expect(event.participants[1].id).toBeTypeOf("string"); + expect(event.participants[1].types).toStrictEqual(["Person"]); + expect(event.participants[1].name).toBe("Bob"); + expect(event.participants[1].age).toBe(25); + expect(event.participants[1].badges).toHaveLength(1); + expect(event.participants[1].badges[0].name).toBe("Attendee"); + + // Check author + expect(event.author.id).toBeTypeOf("string"); + expect(event.author.types).toStrictEqual(["User", "Person"]); + expect(event.author.name).toBe("Charlie"); + expect(event.author.email).toBe("charlie@example.com"); + + expectTypeOf(event).toMatchTypeOf<{ + id: string; + types: string[]; + name: string; + participants: { + id: string; + types: string[]; + name: string; + age: number; + badges: { + id: string; + types: string[]; + name: string; + }[]; + }[]; + author: { + id: string; + types: string[]; + name: string; + age: number; + email: string; + badges: { + id: string; + types: string[]; + name: string; + }[]; + }; + }>(); + }); + + it("should create entities with nested relations and query them", () => { + const { result: createResult } = renderHook(() => useCreateEntity(), { + wrapper, + }); + + const { result: queryResult } = renderHook( + () => useQuery({ types: ["Person"] }), + { wrapper } + ); + + act(() => { + createResult.current(["Person"], { + name: "Dave", + age: 40, + badges: [{ name: "VIP" }, { name: "Contributor" }], + }); + }); + + // Wait for the hook to update + const people = queryResult.current; + expect(people).toHaveLength(1); + + const person = people[0]; + if (!person) { + throw new Error("Person not found"); + } + expect(person.name).toBe("Dave"); + expect(person.age).toBe(40); + expect(person.badges).toHaveLength(2); + if (!person.badges[0] || !person.badges[1]) { + throw new Error("Badges not found"); + } + expect(person.badges[0].name).toBe("VIP"); + expect(person.badges[1].name).toBe("Contributor"); + }); + + it("should delete an entity", () => { + const { result: createResult } = renderHook(() => useCreateEntity(), { + wrapper, + }); + + const { result: deleteResult } = renderHook(() => useDeleteEntity(), { + wrapper, + }); + + const { result: queryResult } = renderHook( + () => useQuery({ types: ["Badge"] }), + { wrapper } + ); + + let badgeId: string | undefined; + + act(() => { + createResult.current(["Badge"], { name: "Exclusive" }); + }); + + act(() => { + const badges = queryResult.current; + expect(badges).toHaveLength(1); + badgeId = badges[0]?.id; + }); + + act(() => { + const success = deleteResult.current(badgeId!); + expect(success).toBe(true); + }); + + act(() => { + const badgesAfterDelete = queryResult.current; + expect(badgesAfterDelete).toHaveLength(0); + }); + }); +}); diff --git a/packages/graph-framework-schema/src/index.tsx b/packages/graph-framework-schema/src/index.tsx new file mode 100644 index 00000000..45f75471 --- /dev/null +++ b/packages/graph-framework-schema/src/index.tsx @@ -0,0 +1 @@ +export * from "./context.js"; diff --git a/packages/graph-framework-schema/tsconfig.json b/packages/graph-framework-schema/tsconfig.json new file mode 100644 index 00000000..062fb3da --- /dev/null +++ b/packages/graph-framework-schema/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "strict": true, + "noUncheckedIndexedAccess": true, + "esModuleInterop": true, + "sourceMap": true, + "declarationMap": true, + "declaration": true, + "strictNullChecks": true, + "incremental": true, + "composite": true, + "allowJs": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "noErrorTruncation": true, + "isolatedModules": true, + "target": "ESNext", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "./dist", + "rootDir": "./src", + "jsx": "react-jsx" + }, + "include": ["./src"] +} diff --git a/packages/graph-framework-schema/vite.config.js b/packages/graph-framework-schema/vite.config.js new file mode 100644 index 00000000..b4f8c666 --- /dev/null +++ b/packages/graph-framework-schema/vite.config.js @@ -0,0 +1,10 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], + test: { + environment: "jsdom", + }, +}); diff --git a/packages/graph-framework-space-events/package.json b/packages/graph-framework-space-events/package.json new file mode 100644 index 00000000..81eaefe8 --- /dev/null +++ b/packages/graph-framework-space-events/package.json @@ -0,0 +1,28 @@ +{ + "name": "graph-framework-space-events", + "version": "0.0.1", + "description": "", + "type": "module", + "scripts": { + "test": "vitest run --typecheck", + "ts:check": "tsc --noEmit", + "lint": "echo 'No linting configured'" + }, + "exports": { + ".": { + "default": "./src/index.js" + } + }, + "peerDependencies": { + "@effect/schema": "^0.74" + }, + "devDependencies": { + "@effect/schema": "^0.74.1", + "vite": "^5.4.8", + "vitest": "^2.1.1" + }, + "dependencies": { + "uuid": "^10.0.0", + "graph-framework-utils": "workspace:*" + } +} diff --git a/packages/graph-framework/src/space-events/apply-event.ts b/packages/graph-framework-space-events/src/apply-event.ts similarity index 100% rename from packages/graph-framework/src/space-events/apply-event.ts rename to packages/graph-framework-space-events/src/apply-event.ts diff --git a/packages/graph-framework/src/space-events/create-invitation.test.ts b/packages/graph-framework-space-events/src/create-invitation.test.ts similarity index 100% rename from packages/graph-framework/src/space-events/create-invitation.test.ts rename to packages/graph-framework-space-events/src/create-invitation.test.ts diff --git a/packages/graph-framework/src/space-events/create-invitation.ts b/packages/graph-framework-space-events/src/create-invitation.ts similarity index 100% rename from packages/graph-framework/src/space-events/create-invitation.ts rename to packages/graph-framework-space-events/src/create-invitation.ts diff --git a/packages/graph-framework/src/space-events/create-space.test.ts b/packages/graph-framework-space-events/src/create-space.test.ts similarity index 100% rename from packages/graph-framework/src/space-events/create-space.test.ts rename to packages/graph-framework-space-events/src/create-space.test.ts diff --git a/packages/graph-framework/src/space-events/create-space.ts b/packages/graph-framework-space-events/src/create-space.ts similarity index 91% rename from packages/graph-framework/src/space-events/create-space.ts rename to packages/graph-framework-space-events/src/create-space.ts index f3ed5039..318fa5f1 100644 --- a/packages/graph-framework/src/space-events/create-space.ts +++ b/packages/graph-framework-space-events/src/create-space.ts @@ -1,4 +1,4 @@ -import { generateId } from "../generateId.js"; +import { generateId } from "graph-framework-utils"; import { Author, SpaceEvent } from "./types.js"; type Params = { diff --git a/packages/graph-framework/src/space-events/delete-space.test.ts b/packages/graph-framework-space-events/src/delete-space.test.ts similarity index 100% rename from packages/graph-framework/src/space-events/delete-space.test.ts rename to packages/graph-framework-space-events/src/delete-space.test.ts diff --git a/packages/graph-framework/src/space-events/delete-space.ts b/packages/graph-framework-space-events/src/delete-space.ts similarity index 100% rename from packages/graph-framework/src/space-events/delete-space.ts rename to packages/graph-framework-space-events/src/delete-space.ts diff --git a/packages/graph-framework-space-events/src/index.ts b/packages/graph-framework-space-events/src/index.ts new file mode 100644 index 00000000..7ccc70b9 --- /dev/null +++ b/packages/graph-framework-space-events/src/index.ts @@ -0,0 +1,5 @@ +export * from "./apply-event.js"; +export * from "./create-invitation.js"; +export * from "./create-space.js"; +export * from "./delete-space.js"; +export * from "./types.js"; diff --git a/packages/graph-framework/src/space-events/types.ts b/packages/graph-framework-space-events/src/types.ts similarity index 100% rename from packages/graph-framework/src/space-events/types.ts rename to packages/graph-framework-space-events/src/types.ts diff --git a/packages/graph-framework-space-events/tsconfig.json b/packages/graph-framework-space-events/tsconfig.json new file mode 100644 index 00000000..062fb3da --- /dev/null +++ b/packages/graph-framework-space-events/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "strict": true, + "noUncheckedIndexedAccess": true, + "esModuleInterop": true, + "sourceMap": true, + "declarationMap": true, + "declaration": true, + "strictNullChecks": true, + "incremental": true, + "composite": true, + "allowJs": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "noErrorTruncation": true, + "isolatedModules": true, + "target": "ESNext", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "./dist", + "rootDir": "./src", + "jsx": "react-jsx" + }, + "include": ["./src"] +} diff --git a/packages/graph-framework-space-events/vite.config.js b/packages/graph-framework-space-events/vite.config.js new file mode 100644 index 00000000..290663c3 --- /dev/null +++ b/packages/graph-framework-space-events/vite.config.js @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; + +// https://vitejs.dev/config/ +export default defineConfig({}); diff --git a/packages/graph-framework-utils/package.json b/packages/graph-framework-utils/package.json new file mode 100644 index 00000000..79f80967 --- /dev/null +++ b/packages/graph-framework-utils/package.json @@ -0,0 +1,25 @@ +{ + "name": "graph-framework-utils", + "version": "0.0.1", + "description": "", + "type": "module", + "scripts": { + "test": "vitest run --typecheck", + "ts:check": "tsc --noEmit", + "lint": "echo 'No linting configured'" + }, + "exports": { + ".": { + "default": "./src/index.js" + } + }, + "devDependencies": { + "@types/react": "^18.3.7", + "@types/uuid": "^10.0.0", + "vite": "^5.4.8", + "vitest": "^2.1.1" + }, + "dependencies": { + "uuid": "^10.0.0" + } +} diff --git a/packages/graph-framework-utils/src/generateId.test.ts b/packages/graph-framework-utils/src/generateId.test.ts new file mode 100644 index 00000000..9f464cff --- /dev/null +++ b/packages/graph-framework-utils/src/generateId.test.ts @@ -0,0 +1,10 @@ +import { expect, it } from "vitest"; +import { generateId } from "./generateId.js"; + +it("should generate an id", () => { + expect(generateId()).toBeTypeOf("string"); +}); + +it.skip("should have a length of 22 characters", () => { + expect(generateId()).toHaveLength(22); +}); diff --git a/packages/graph-framework/src/generateId.ts b/packages/graph-framework-utils/src/generateId.ts similarity index 100% rename from packages/graph-framework/src/generateId.ts rename to packages/graph-framework-utils/src/generateId.ts diff --git a/packages/graph-framework-utils/src/index.tsx b/packages/graph-framework-utils/src/index.tsx new file mode 100644 index 00000000..841ce577 --- /dev/null +++ b/packages/graph-framework-utils/src/index.tsx @@ -0,0 +1 @@ +export * from "./generateId.js"; diff --git a/packages/graph-framework-utils/tsconfig.json b/packages/graph-framework-utils/tsconfig.json new file mode 100644 index 00000000..062fb3da --- /dev/null +++ b/packages/graph-framework-utils/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "strict": true, + "noUncheckedIndexedAccess": true, + "esModuleInterop": true, + "sourceMap": true, + "declarationMap": true, + "declaration": true, + "strictNullChecks": true, + "incremental": true, + "composite": true, + "allowJs": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "noErrorTruncation": true, + "isolatedModules": true, + "target": "ESNext", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "./dist", + "rootDir": "./src", + "jsx": "react-jsx" + }, + "include": ["./src"] +} diff --git a/packages/graph-framework-utils/vite.config.js b/packages/graph-framework-utils/vite.config.js new file mode 100644 index 00000000..290663c3 --- /dev/null +++ b/packages/graph-framework-utils/vite.config.js @@ -0,0 +1,4 @@ +import { defineConfig } from "vite"; + +// https://vitejs.dev/config/ +export default defineConfig({}); diff --git a/packages/graph-framework/package.json b/packages/graph-framework/package.json index f98a34f1..51a48fce 100644 --- a/packages/graph-framework/package.json +++ b/packages/graph-framework/package.json @@ -32,11 +32,12 @@ "@vitejs/plugin-react": "^4.3.2", "jsdom": "^25.0.1", "vite": "^5.4.8", - "vitest": "^2.1.1", - "zod": "^3.23.8" + "vitest": "^2.1.1" }, "dependencies": { - "fast-deep-equal": "^3.1.3", - "uuid": "^10.0.0" + "graph-framework-utils": "workspace:*", + "graph-framework-space-events": "workspace:*", + "graph-framework-identity": "workspace:*", + "graph-framework-schema": "workspace:*" } } diff --git a/packages/graph-framework/src/index.test.tsx b/packages/graph-framework/src/index.test.tsx index 8cd52cc9..9a5838a7 100644 --- a/packages/graph-framework/src/index.test.tsx +++ b/packages/graph-framework/src/index.test.tsx @@ -1,290 +1,5 @@ -import "@testing-library/jest-dom/vitest"; -import { act, cleanup, renderHook } from "@testing-library/react"; -import React from "react"; -import { - afterEach, - beforeEach, - describe, - expect, - expectTypeOf, - it, -} from "vitest"; -import { createFunctions, repo, type } from "./context.js"; +import { expect, it } from "vitest"; -afterEach(() => { - cleanup(); -}); - -describe("Library Tests", () => { - const schema = { - types: { - Person: { - name: type.Text, - age: type.Number, - badges: type.Relation({ - types: ["Badge"] as const, - cardinality: "many", - }), - }, - User: { - name: type.Text, - email: type.Text, - }, - Badge: { - name: type.Text, - }, - Event: { - name: type.Text, - participants: type.Relation({ - types: ["Person"] as const, - cardinality: "many", - }), - author: type.Relation({ - types: ["User", "Person"] as const, - cardinality: "one", - }), - }, - }, - }; - - // Create functions from the schema - const { - useCreateEntity, - useDeleteEntity, - useQuery, - SpaceProvider, - createDocumentId, - } = createFunctions(schema); - - let repoResult = repo.create(); - let wrapper = ({ children }: { children: React.ReactNode }) => ( - {children} - ); - - beforeEach(() => { - repoResult = repo.create(); - wrapper = ({ children }: { children: React.ReactNode }) => ( - {children} - ); - }); - - it("should create one entity successfully", () => { - expect([1]).toHaveLength(1); - - const { result: createResult } = renderHook(() => useCreateEntity(), { - wrapper, - }); - - const { result: queryResult } = renderHook( - () => useQuery({ types: ["Event"] }), - { wrapper } - ); - - act(() => { - createResult.current(["Event"], { - name: "Conference", - participants: [ - { - name: "Alice", - age: 30, - badges: [{ name: "Speaker" }], - }, - { - name: "Bob", - age: 25, - badges: [{ name: "Attendee" }], - }, - ], - author: { - name: "Charlie", - email: "charlie@example.com", - age: 35, - badges: [{ name: "VIP" }], - }, - }); - }); - - const events = queryResult.current; - expect(events).toHaveLength(1); - }); - - it("should create and query entities with relations", () => { - const { result: createResult } = renderHook(() => useCreateEntity(), { - wrapper, - }); - - const { result: queryResult } = renderHook( - () => useQuery({ types: ["Event"] }), - { wrapper } - ); - - act(() => { - createResult.current(["Event"], { - name: "Conference", - participants: [ - { - name: "Alice", - age: 30, - badges: [{ name: "Speaker" }], - }, - { - name: "Bob", - age: 25, - badges: [{ name: "Attendee" }], - }, - ], - author: { - name: "Charlie", - email: "charlie@example.com", - age: 35, - badges: [{ name: "VIP" }], - }, - }); - }); - - // Wait for the hook to update - const events = queryResult.current; - expect(events).toHaveLength(1); - - const event = events[0]; - if (!event) { - throw new Error("Event not found"); - } - expect(event.id).toBeTypeOf("string"); - expect(event.types).toStrictEqual(["Event"]); - expect(event.name).toBe("Conference"); - - // Check participants - expect(event.participants).toHaveLength(2); - if ( - !event.participants[0] || - !event.participants[1] || - !event.participants[0].badges[0] || - !event.participants[1].badges[0] - ) { - throw new Error("Participants not found"); - } - - expect(event.participants[0].id).toBeTypeOf("string"); - expect(event.participants[0].types).toStrictEqual(["Person"]); - expect(event.participants[0].name).toBe("Alice"); - expect(event.participants[0].age).toBe(30); - expect(event.participants[0].badges).toHaveLength(1); - expect(event.participants[0].badges[0].name).toBe("Speaker"); - - expect(event.participants[1].id).toBeTypeOf("string"); - expect(event.participants[1].types).toStrictEqual(["Person"]); - expect(event.participants[1].name).toBe("Bob"); - expect(event.participants[1].age).toBe(25); - expect(event.participants[1].badges).toHaveLength(1); - expect(event.participants[1].badges[0].name).toBe("Attendee"); - - // Check author - expect(event.author.id).toBeTypeOf("string"); - expect(event.author.types).toStrictEqual(["User", "Person"]); - expect(event.author.name).toBe("Charlie"); - expect(event.author.email).toBe("charlie@example.com"); - - expectTypeOf(event).toMatchTypeOf<{ - id: string; - types: string[]; - name: string; - participants: { - id: string; - types: string[]; - name: string; - age: number; - badges: { - id: string; - types: string[]; - name: string; - }[]; - }[]; - author: { - id: string; - types: string[]; - name: string; - age: number; - email: string; - badges: { - id: string; - types: string[]; - name: string; - }[]; - }; - }>(); - }); - - it("should create entities with nested relations and query them", () => { - const { result: createResult } = renderHook(() => useCreateEntity(), { - wrapper, - }); - - const { result: queryResult } = renderHook( - () => useQuery({ types: ["Person"] }), - { wrapper } - ); - - act(() => { - createResult.current(["Person"], { - name: "Dave", - age: 40, - badges: [{ name: "VIP" }, { name: "Contributor" }], - }); - }); - - // Wait for the hook to update - const people = queryResult.current; - expect(people).toHaveLength(1); - - const person = people[0]; - if (!person) { - throw new Error("Person not found"); - } - expect(person.name).toBe("Dave"); - expect(person.age).toBe(40); - expect(person.badges).toHaveLength(2); - if (!person.badges[0] || !person.badges[1]) { - throw new Error("Badges not found"); - } - expect(person.badges[0].name).toBe("VIP"); - expect(person.badges[1].name).toBe("Contributor"); - }); - - it("should delete an entity", () => { - const { result: createResult } = renderHook(() => useCreateEntity(), { - wrapper, - }); - - const { result: deleteResult } = renderHook(() => useDeleteEntity(), { - wrapper, - }); - - const { result: queryResult } = renderHook( - () => useQuery({ types: ["Badge"] }), - { wrapper } - ); - - let badgeId: string | undefined; - - act(() => { - createResult.current(["Badge"], { name: "Exclusive" }); - }); - - act(() => { - const badges = queryResult.current; - expect(badges).toHaveLength(1); - badgeId = badges[0]?.id; - }); - - act(() => { - const success = deleteResult.current(badgeId!); - expect(success).toBe(true); - }); - - act(() => { - const badgesAfterDelete = queryResult.current; - expect(badgesAfterDelete).toHaveLength(0); - }); - }); +it.skip("TODO test full integration", () => { + expect(true).toBe(false); }); diff --git a/packages/graph-framework/src/index.tsx b/packages/graph-framework/src/index.tsx index 45f75471..14dd81c5 100644 --- a/packages/graph-framework/src/index.tsx +++ b/packages/graph-framework/src/index.tsx @@ -1 +1,4 @@ -export * from "./context.js"; +export * from "graph-framework-identity"; +export * from "graph-framework-schema"; +export * from "graph-framework-space-events"; +export * from "graph-framework-utils"; diff --git a/packages/graph-framework/vite.config.js b/packages/graph-framework/vite.config.js index e5bf5565..b4f8c666 100644 --- a/packages/graph-framework/vite.config.js +++ b/packages/graph-framework/vite.config.js @@ -5,7 +5,6 @@ import react from "@vitejs/plugin-react"; export default defineConfig({ plugins: [react()], test: { - // 👋 add the line below to add jsdom to vite environment: "jsdom", }, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 44cbef3e..2d0227f6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -238,15 +238,21 @@ importers: packages/graph-framework: dependencies: - fast-deep-equal: - specifier: ^3.1.3 - version: 3.1.3 + graph-framework-identity: + specifier: workspace:* + version: link:../graph-framework-identity + graph-framework-schema: + specifier: workspace:* + version: link:../graph-framework-schema + graph-framework-space-events: + specifier: workspace:* + version: link:../graph-framework-space-events + graph-framework-utils: + specifier: workspace:* + version: link:../graph-framework-utils react: specifier: ^18 version: 18.3.1 - uuid: - specifier: ^10.0.0 - version: 10.0.0 devDependencies: '@automerge/automerge': specifier: ^2.2.8 @@ -284,9 +290,112 @@ importers: vitest: specifier: ^2.1.1 version: 2.1.1(@types/node@22.7.4)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)) - zod: - specifier: ^3.23.8 - version: 3.23.8 + + packages/graph-framework-identity: + dependencies: + graph-framework-utils: + specifier: workspace:* + version: link:../graph-framework-utils + uuid: + specifier: ^10.0.0 + version: 10.0.0 + devDependencies: + '@effect/schema': + specifier: ^0.74.1 + version: 0.74.2(effect@3.8.4) + vite: + specifier: ^5.4.8 + version: 5.4.8(@types/node@22.7.4) + vitest: + specifier: ^2.1.1 + version: 2.1.2(@types/node@22.7.4)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + + packages/graph-framework-schema: + dependencies: + fast-deep-equal: + specifier: ^3.1.3 + version: 3.1.3 + graph-framework-utils: + specifier: workspace:* + version: link:../graph-framework-utils + react: + specifier: ^18 + version: 18.3.1 + devDependencies: + '@automerge/automerge': + specifier: ^2.2.8 + version: 2.2.8 + '@automerge/automerge-repo': + specifier: ^1.2.1 + version: 1.2.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.7.4)(typescript@5.6.2) + '@automerge/automerge-repo-react-hooks': + specifier: ^1.2.1 + version: 1.2.1(@swc/core@1.7.26(@swc/helpers@0.5.13))(@types/node@22.7.4)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.6.2) + '@effect/schema': + specifier: ^0.74.1 + version: 0.74.2(effect@3.8.4) + '@testing-library/jest-dom': + specifier: ^6.5.0 + version: 6.5.0 + '@testing-library/react': + specifier: ^16.0.1 + version: 16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@types/react': + specifier: ^18.3.7 + version: 18.3.11 + '@types/uuid': + specifier: ^10.0.0 + version: 10.0.0 + '@vitejs/plugin-react': + specifier: ^4.3.2 + version: 4.3.2(vite@5.4.8(@types/node@22.7.4)) + jsdom: + specifier: ^25.0.1 + version: 25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10) + vite: + specifier: ^5.4.8 + version: 5.4.8(@types/node@22.7.4) + vitest: + specifier: ^2.1.1 + version: 2.1.2(@types/node@22.7.4)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + + packages/graph-framework-space-events: + dependencies: + graph-framework-utils: + specifier: workspace:* + version: link:../graph-framework-utils + uuid: + specifier: ^10.0.0 + version: 10.0.0 + devDependencies: + '@effect/schema': + specifier: ^0.74.1 + version: 0.74.2(effect@3.8.4) + vite: + specifier: ^5.4.8 + version: 5.4.8(@types/node@22.7.4) + vitest: + specifier: ^2.1.1 + version: 2.1.2(@types/node@22.7.4)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + + packages/graph-framework-utils: + dependencies: + uuid: + specifier: ^10.0.0 + version: 10.0.0 + devDependencies: + '@types/react': + specifier: ^18.3.7 + version: 18.3.11 + '@types/uuid': + specifier: ^10.0.0 + version: 10.0.0 + vite: + specifier: ^5.4.8 + version: 5.4.8(@types/node@22.7.4) + vitest: + specifier: ^2.1.1 + version: 2.1.2(@types/node@22.7.4)(jsdom@25.0.1(bufferutil@4.0.8)(utf-8-validate@5.0.10)) packages: @@ -7016,6 +7125,16 @@ snapshots: lodash: 4.17.21 redent: 3.0.0 + '@testing-library/react@16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.25.7 + '@testing-library/dom': 10.4.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.11 + '@types/react-dom': 18.3.0 + '@testing-library/react@16.0.1(@testing-library/dom@10.4.0)(@types/react-dom@18.3.0)(@types/react@18.3.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.25.7