Skip to content

Commit 834c5af

Browse files
authored
fix(#374 | template deps): use workspace for create-hypergraph template deps. replace on build (#380)
1 parent a94bea7 commit 834c5af

File tree

14 files changed

+355
-296
lines changed

14 files changed

+355
-296
lines changed

apps/connect/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"@tanstack/react-router-devtools": "^1.122.0",
2525
"@xstate/store": "^3.5.1",
2626
"clsx": "^2.1.1",
27-
"effect": "^3.17.0",
27+
"effect": "^3.17.1",
2828
"framer-motion": "^12.10.1",
2929
"graphql-request": "^7.2.0",
3030
"lucide-react": "^0.508.0",

apps/create-hypergraph/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# create-hypergraph
22

3+
## 0.2.0
4+
### Minor Changes
5+
6+
- 3204607: Use workspace deps for create-hypergraph templates and replace with current version on copy into dist directory
7+
38
## 0.1.0
49
### Patch Changes
510

apps/create-hypergraph/package.json

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "create-hypergraph",
3-
"version": "0.1.3",
3+
"version": "0.2.0",
44
"description": "CLI toolchain to scaffold a Hypergraph-enabled application with a given template.",
55
"type": "module",
66
"bin": {
@@ -26,12 +26,13 @@
2626
"scripts": {
2727
"test": "vitest run",
2828
"dev": "NODE_ENV=development pnpx tsx ./src/bin.ts",
29-
"build": "tsdown && tsx scripts/copy-package-json.ts && pnpm run copy-all",
30-
"copy-templates": "cp -r template-* dist/",
29+
"build": "tsdown && pnpm run copy-all",
30+
"copy-packagejson": "tsx scripts/copy-package-json.ts",
31+
"copy-templates": "tsx scripts/copy-template-dir.ts",
3132
"copy-readme": "cp README.md dist/README.md",
3233
"copy-changelog": "cp CHANGELOG.md dist/CHANGELOG.md",
3334
"copy-llms": "cp llms.txt dist/llms.txt",
34-
"copy-all": "pnpm run copy-templates && pnpm run copy-readme && pnpm run copy-changelog && pnpm run copy-llms",
35+
"copy-all": "pnpm run copy-packagejson && pnpm run copy-templates && pnpm run copy-readme && pnpm run copy-changelog && pnpm run copy-llms",
3536
"check": "tsc --noEmit",
3637
"start": "node ./dist/bin.js",
3738
"lint": "biome check",
@@ -53,14 +54,14 @@
5354
},
5455
"homepage": "https://github.com/graphprotocol/hypergraph/tree/main/apps/create-hypergraph-app#readme",
5556
"devDependencies": {
56-
"@effect/cli": "^0.68.0",
57-
"@effect/language-service": "^0.28.0",
58-
"@effect/platform": "^0.89.0",
59-
"@effect/platform-node": "^0.92.0",
57+
"@effect/cli": "^0.69.0",
58+
"@effect/language-service": "^0.28.3",
59+
"@effect/platform": "^0.90.0",
60+
"@effect/platform-node": "^0.94.0",
6061
"@effect/printer-ansi": "^0.45.0",
6162
"@effect/vitest": "^0.25.0",
6263
"@types/node": "^24.1.0",
63-
"effect": "^3.17.0",
64+
"effect": "^3.17.1",
6465
"execa": "^9.6.0",
6566
"tsdown": "^0.13.0",
6667
"tsx": "^4.20.3"
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import { readdirSync } from 'node:fs';
2+
import type { PlatformError } from '@effect/platform/Error';
3+
import * as FileSystem from '@effect/platform/FileSystem';
4+
import * as Path from '@effect/platform/Path';
5+
import * as NodeFileSystem from '@effect/platform-node/NodeFileSystem';
6+
import * as NodePath from '@effect/platform-node/NodePath';
7+
import { Cause, Chunk, Console, Data, Effect, pipe, Stream } from 'effect';
8+
9+
const workspaceDepsToReplace = {
10+
'@graphprotocol/hypergraph': {
11+
packageJson: 'packages/hypergraph/package.json',
12+
},
13+
'@graphprotocol/hypergraph-react': {
14+
packageJson: 'packages/hypergraph-react/package.json',
15+
},
16+
'@graphprotocol/typesync': {
17+
packageJson: 'packages/typesync/package.json',
18+
},
19+
} as const satisfies Record<
20+
'@graphprotocol/hypergraph' | '@graphprotocol/hypergraph-react' | '@graphprotocol/typesync',
21+
{ packageJson: `packages/${string}/package.json` }
22+
>;
23+
const ignore = new Set(['.git', 'node_modules', '.tanstack', 'dist', 'publish', 'build', '.next']);
24+
25+
class CopyTemplateDirService extends Effect.Service<CopyTemplateDirService>()(
26+
'/Hypergraph/create-hypergraph/services/CopyTemplateDirService',
27+
{
28+
dependencies: [NodeFileSystem.layer, NodePath.layer],
29+
effect: Effect.gen(function* () {
30+
const fs = yield* FileSystem.FileSystem;
31+
const path = yield* Path.Path;
32+
33+
const cwd = process.cwd();
34+
35+
const getTemplateDirectories = () =>
36+
Effect.gen(function* () {
37+
return yield* Stream.fromIterable(readdirSync(cwd, { withFileTypes: true })).pipe(
38+
Stream.filter((entry) => entry.name.startsWith('template-') && entry.isDirectory()),
39+
Stream.map((entry) => entry.name),
40+
Stream.runCollect,
41+
);
42+
});
43+
44+
function fetchWorkspaceDepCurrentVersion(packagejson: `packages/${string}/package.json`) {
45+
return pipe(
46+
fs.readFileString(path.resolve(cwd, '..', '..', packagejson)),
47+
Effect.tapError((err) => Console.error('Failure reading remplate package.json', { cause: err, packagejson })),
48+
Effect.map((_) => JSON.parse(_)),
49+
Effect.map((json) => String(json.version)),
50+
);
51+
}
52+
function fetchAllWorkspaceDepsCurrentVersion() {
53+
return Stream.fromIterable(Object.entries(workspaceDepsToReplace)).pipe(
54+
Stream.mapEffect(([dep, { packageJson }]) =>
55+
Effect.gen(function* () {
56+
const version = yield* fetchWorkspaceDepCurrentVersion(packageJson);
57+
58+
return [dep, version] as const;
59+
}),
60+
),
61+
Stream.runCollect,
62+
);
63+
}
64+
65+
const updatePackageJsonWorkspaceDeps = (
66+
packageJsonPath: string,
67+
destPackageJsonPath: string,
68+
replaced: Record<string, string>,
69+
) =>
70+
Effect.gen(function* () {
71+
// read the package.json
72+
// update the hypergraph workspace deps with the current version
73+
const packageJson = yield* fs.readFileString(packageJsonPath).pipe(Effect.map(JSON.parse));
74+
75+
packageJson.dependencies = {
76+
...packageJson.dependencies,
77+
...replaced,
78+
};
79+
80+
yield* fs.writeFileString(destPackageJsonPath, JSON.stringify(packageJson, null, 2));
81+
});
82+
83+
const copy = (src: string, dest: string, replaced: Record<string, string>): Effect.Effect<void, PlatformError> =>
84+
Effect.gen(function* () {
85+
yield* fs.makeDirectory(dest, { recursive: true });
86+
const entries = readdirSync(src, { withFileTypes: true });
87+
88+
for (const entry of entries) {
89+
if (entry.isDirectory() && ignore.has(entry.name)) continue;
90+
91+
const srcPath = path.join(src, entry.name);
92+
const destPath = path.join(dest, entry.name);
93+
94+
if (entry.isDirectory()) {
95+
yield* copy(srcPath, destPath, replaced);
96+
} else {
97+
// update the package.json
98+
if (entry.name === 'package.json') {
99+
yield* updatePackageJsonWorkspaceDeps(srcPath, destPath, replaced);
100+
continue;
101+
}
102+
yield* fs.copyFile(srcPath, destPath);
103+
}
104+
}
105+
});
106+
107+
return {
108+
copyTemplates() {
109+
return Effect.gen(function* () {
110+
const workspaceDeps = yield* fetchAllWorkspaceDepsCurrentVersion();
111+
const workspaceDepsMap = Chunk.reduce(
112+
workspaceDeps,
113+
{} as Record<string, string>,
114+
(map, [currDep, currVersion]) => {
115+
map[currDep] = currVersion;
116+
117+
return map;
118+
},
119+
);
120+
121+
// iterate through all templates, copy all files, update package.json deps
122+
yield* Stream.fromIterableEffect(getTemplateDirectories())
123+
.pipe(
124+
Stream.runForEach((template) =>
125+
Effect.gen(function* () {
126+
yield* Console.info('Copying template:', template, 'into dist');
127+
128+
const templateDir = path.resolve(process.cwd(), template);
129+
const templateDirExists = yield* fs.exists(templateDir);
130+
if (!templateDirExists) {
131+
throw new TemplateDirDoesNotExistError({ template: templateDir });
132+
}
133+
134+
const templateDestDir = path.resolve(process.cwd(), 'dist', template);
135+
136+
yield* copy(templateDir, templateDestDir, workspaceDepsMap);
137+
}),
138+
),
139+
)
140+
.pipe(
141+
Effect.tapErrorCause((cause) =>
142+
Console.error('Failure copying template to dist', { cause: Cause.pretty(cause) }),
143+
),
144+
Effect.andThen(() => Console.info('Completed copying template directories to dist with updated deps')),
145+
);
146+
});
147+
},
148+
} as const;
149+
}),
150+
},
151+
) {}
152+
153+
class TemplateDirDoesNotExistError extends Data.TaggedError(
154+
'Hypergraph/create-hypergraph/errors/TemplateDirDoesNotExistError',
155+
)<{
156+
readonly template: string;
157+
}> {}
158+
159+
const program = pipe(
160+
Console.log('Copying templates to dist dir'),
161+
() =>
162+
Effect.gen(function* () {
163+
const copy = yield* CopyTemplateDirService;
164+
165+
yield* copy.copyTemplates();
166+
}),
167+
Effect.provide(CopyTemplateDirService.Default),
168+
);
169+
170+
Effect.runPromise(program);

apps/create-hypergraph/src/Cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ const createHypergraphApp = Command.make('create-hypergraph-app', {
7575

7676
export const run = Command.run(createHypergraphApp, {
7777
name: 'create-hypergraph-app',
78-
version: '0.1.3',
78+
version: '0.2.0',
7979
});
8080

8181
// ========================

apps/create-hypergraph/template-vite-react/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
},
1313
"dependencies": {
1414
"@graphprotocol/grc-20": "^0.21.6",
15-
"@graphprotocol/hypergraph": "0.1.0",
16-
"@graphprotocol/hypergraph-react": "0.1.0",
17-
"@graphprotocol/typesync": "^0.1.0",
15+
"@graphprotocol/hypergraph": "workspace:*",
16+
"@graphprotocol/hypergraph-react": "workspace:*",
17+
"@graphprotocol/typesync": "workspace:*",
1818
"@radix-ui/react-navigation-menu": "^1.2.13",
1919
"@radix-ui/react-slot": "^1.2.3",
2020
"@radix-ui/react-tooltip": "^1.2.7",
@@ -23,7 +23,7 @@
2323
"@tanstack/react-router": "^1.129.2",
2424
"class-variance-authority": "^0.7.1",
2525
"clsx": "^2.1.1",
26-
"effect": "^3.17.0",
26+
"effect": "^3.17.1",
2727
"lucide-react": "^0.525.0",
2828
"react": "^19.1.0",
2929
"react-dom": "^19.1.0",

apps/create-hypergraph/test/Cli.test.ts

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -234,38 +234,4 @@ describe('create-hypergraph CLI', () => {
234234
}
235235
}),
236236
);
237-
238-
it.effect(
239-
'test dependency installation when not skipped',
240-
() =>
241-
Effect.gen(function* () {
242-
yield* cleanupTestDirs();
243-
const tempDir = yield* createTempDir();
244-
245-
try {
246-
// Run CLI without skipping dependency installation
247-
const output = yield* run(
248-
[
249-
'--template',
250-
'vite-react',
251-
'--package-manager',
252-
'pnpm',
253-
'--skip-initialize-git',
254-
// Note: not skipping install deps
255-
'test-deps-app',
256-
],
257-
tempDir,
258-
);
259-
260-
expect(output).toContain('Successfully scaffolded your hypergraph enabled app');
261-
262-
// Verify node_modules directory was created
263-
const projectPath = join(tempDir, 'test-deps-app');
264-
expect(existsSync(join(projectPath, 'node_modules'))).toBe(true);
265-
} finally {
266-
yield* cleanupTempDir(tempDir);
267-
}
268-
}),
269-
{ timeout: 60000 }, // 60 second timeout for dependency installation
270-
);
271237
});

apps/events/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"@xstate/store": "^3.5.1",
2323
"class-variance-authority": "^0.7.1",
2424
"clsx": "^2.1.1",
25-
"effect": "^3.17.0",
25+
"effect": "^3.17.1",
2626
"framer-motion": "^12.10.1",
2727
"graphql-request": "^7.1.2",
2828
"isomorphic-ws": "^5.0.0",

apps/server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"@privy-io/server-auth": "^1.26.0",
2020
"body-parser": "^2.2.0",
2121
"cors": "^2.8.5",
22-
"effect": "^3.17.0",
22+
"effect": "^3.17.1",
2323
"express": "^5.1.0",
2424
"prisma": "^6.7.0",
2525
"siwe": "^3.0.0",

apps/typesync/package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@
4141
"hypergraph": "pnpx tsx ./src/bin.ts typesync"
4242
},
4343
"devDependencies": {
44-
"@effect/cli": "^0.68.0",
45-
"@effect/experimental": "^0.53.0",
46-
"@effect/language-service": "^0.28.0",
47-
"@effect/platform": "^0.89.0",
48-
"@effect/platform-node": "^0.92.0",
44+
"@effect/cli": "^0.69.0",
45+
"@effect/experimental": "^0.54.0",
46+
"@effect/language-service": "^0.28.3",
47+
"@effect/platform": "^0.90.0",
48+
"@effect/platform-node": "^0.94.0",
4949
"@effect/printer": "^0.45.0",
50-
"@effect/sql": "^0.43.0",
51-
"@effect/sql-sqlite-node": "^0.44.0",
50+
"@effect/sql": "^0.44.0",
51+
"@effect/sql-sqlite-node": "^0.45.0",
5252
"@effect/vitest": "^0.25.0",
5353
"@graphql-codegen/cli": "^5.0.7",
5454
"@graphql-codegen/client-preset": "^4.8.3",
@@ -81,7 +81,7 @@
8181
"@tanstack/react-router-devtools": "^1.129.5",
8282
"better-sqlite3": "^12.2.0",
8383
"date-fns": "^4.1.0",
84-
"effect": "^3.17.0",
84+
"effect": "^3.17.1",
8585
"graphql": "^16.11.0",
8686
"graphql-request": "^7.2.0",
8787
"jotai": "^2.12.5",

0 commit comments

Comments
 (0)