authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-06-03 22:34:23-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-06-04 05:34:23+00:00
log37bf0f0d1d3ca53ca0b8f349ac7eaf086afaf975
tree67a498e84663108dcc7a7a5e47dc506f609639fd
parent6a1c4da528a3ab433dc19de2d728a66a1ee92a79
signature Signed by PGP key B5690EEEBB952194

[codex] remove duplicated pnpm root config (#2939)

Co-authored-by: Julius Marminge <julius@mac.lan>

11 files changed, 268 insertions(+), 94 deletions(-)

apps/server/scripts/cli.ts+8-6
...@@ -17,8 +17,8 @@ import {...@@ -17,8 +17,8 @@ import {
17} from "../../../scripts/lib/brand-assets.ts";17} from "../../../scripts/lib/brand-assets.ts";
18import { resolveCatalogDependencies } from "../../../scripts/lib/resolve-catalog.ts";18import { resolveCatalogDependencies } from "../../../scripts/lib/resolve-catalog.ts";
19import { fromJsonStringPretty } from "@t3tools/shared/schemaJson";19import { fromJsonStringPretty } from "@t3tools/shared/schemaJson";
20import { fromYaml } from "@t3tools/shared/schemaYaml";
20import serverPackageJson from "../package.json" with { type: "json" };21import serverPackageJson from "../package.json" with { type: "json" };
21import { parse as parseYaml } from "yaml";
2222
23interface PackageJson {23interface PackageJson {
24 name: string;24 name: string;
...@@ -39,10 +39,12 @@ interface PackageJson {...@@ -39,10 +39,12 @@ interface PackageJson {
39const PackageJsonPrettyJson = fromJsonStringPretty(Schema.Unknown);39const PackageJsonPrettyJson = fromJsonStringPretty(Schema.Unknown);
40const encodePackageJson = Schema.encodeEffect(PackageJsonPrettyJson);40const encodePackageJson = Schema.encodeEffect(PackageJsonPrettyJson);
4141
42interface WorkspaceConfig {42const WorkspaceConfig = Schema.Struct({
43 readonly catalog?: Record<string, string>;43 catalog: Schema.optional(Schema.Record(Schema.String, Schema.String)),
44 readonly overrides?: Record<string, string>;44 overrides: Schema.optional(Schema.Record(Schema.String, Schema.String)),
45}45});
46type WorkspaceConfig = typeof WorkspaceConfig.Type;
47const decodeWorkspaceConfig = Schema.decodeEffect(fromYaml(WorkspaceConfig));
4648
47class CliError extends Data.TaggedError("CliError")<{49class CliError extends Data.TaggedError("CliError")<{
48 readonly message: string;50 readonly message: string;
...@@ -58,7 +60,7 @@ const readWorkspaceConfig = Effect.fn("readWorkspaceConfig")(function* () {...@@ -58,7 +60,7 @@ const readWorkspaceConfig = Effect.fn("readWorkspaceConfig")(function* () {
58 const fs = yield* FileSystem.FileSystem;60 const fs = yield* FileSystem.FileSystem;
59 const repoRoot = yield* RepoRoot;61 const repoRoot = yield* RepoRoot;
60 const workspaceYaml = yield* fs.readFileString(path.join(repoRoot, "pnpm-workspace.yaml"));62 const workspaceYaml = yield* fs.readFileString(path.join(repoRoot, "pnpm-workspace.yaml"));
61 return parseYaml(workspaceYaml) as WorkspaceConfig;63 return yield* decodeWorkspaceConfig(workspaceYaml);
62});64});
6365
64const runCommand = Effect.fn("runCommand")(function* (command: ChildProcess.Command) {66const runCommand = Effect.fn("runCommand")(function* (command: ChildProcess.Command) {
package.json-48
...@@ -1,35 +1,6 @@...@@ -1,35 +1,6 @@
1{1{
2 "name": "@t3tools/monorepo",2 "name": "@t3tools/monorepo",
3 "private": true,3 "private": true,
4 "workspaces": {
5 "packages": [
6 "apps/*",
7 "oxlint-plugin-t3code",
8 "packages/*",
9 "scripts"
10 ],
11 "catalog": {
12 "effect": "4.0.0-beta.73",
13 "@effect/atom-react": "4.0.0-beta.73",
14 "@effect/openapi-generator": "4.0.0-beta.73",
15 "@effect/platform-bun": "4.0.0-beta.73",
16 "@effect/platform-node": "4.0.0-beta.73",
17 "@effect/platform-node-shared": "4.0.0-beta.73",
18 "@effect/sql-sqlite-bun": "4.0.0-beta.73",
19 "@effect/vitest": "4.0.0-beta.73",
20 "@effect/tsgo": "0.11.4",
21 "@pierre/diffs": "1.1.20",
22 "@vitest/runner": "^4.1.8",
23 "@types/bun": "^1.3.11",
24 "@types/node": "24.12.4",
25 "@typescript/native-preview": "7.0.0-dev.20260527.2",
26 "typescript": "~6.0.3",
27 "vitest": "npm:@voidzero-dev/vite-plus-test@latest",
28 "vite": "npm:@voidzero-dev/vite-plus-core@latest",
29 "vite-plus": "latest",
30 "yaml": "^2.9.0"
31 }
32 },
33 "type": "module",4 "type": "module",
34 "scripts": {5 "scripts": {
35 "prepare": "vp config && effect-tsgo patch",6 "prepare": "vp config && effect-tsgo patch",
...@@ -75,19 +46,6 @@...@@ -75,19 +46,6 @@
75 "@vitest/runner": "catalog:",46 "@vitest/runner": "catalog:",
76 "vite": "catalog:",47 "vite": "catalog:",
77 "vite-plus": "catalog:",48 "vite-plus": "catalog:",
78 "vitest": "catalog:",
79 "yaml": "catalog:"
80 },
81 "overrides": {
82 "@effect/atom-react": "catalog:",
83 "@effect/platform-bun": "catalog:",
84 "@effect/platform-node": "catalog:",
85 "@effect/platform-node-shared": "catalog:",
86 "@effect/sql-sqlite-bun": "catalog:",
87 "@effect/vitest": "catalog:",
88 "@types/node": "catalog:",
89 "effect": "catalog:",
90 "vite": "catalog:",
91 "vitest": "catalog:"49 "vitest": "catalog:"
92 },50 },
93 "engines": {51 "engines": {
...@@ -98,11 +56,5 @@...@@ -98,11 +56,5 @@
98 "workerDirectory": [56 "workerDirectory": [
99 "apps/web/public"57 "apps/web/public"
100 ]58 ]
101 },
102 "patchedDependencies": {
103 "@expo/metro-config@56.0.13": "patches/@expo%2Fmetro-config@56.0.13.patch",
104 "@pierre/diffs@1.1.20@1.1.20": "patches/@pierre%2Fdiffs@1.1.20.patch",
105 "effect@4.0.0-beta.73@4.0.0-beta.73": "patches/effect@4.0.0-beta.73.patch",
106 "react-native-nitro-modules@0.35.9@0.35.9": "patches/react-native-nitro-modules@0.35.9.patch"
107 }59 }
108}60}
packages/shared/package.json+6-1
...@@ -51,6 +51,10 @@...@@ -51,6 +51,10 @@
51 "types": "./src/schemaJson.ts",51 "types": "./src/schemaJson.ts",
52 "import": "./src/schemaJson.ts"52 "import": "./src/schemaJson.ts"
53 },53 },
54 "./schemaYaml": {
55 "types": "./src/schemaYaml.ts",
56 "import": "./src/schemaYaml.ts"
57 },
54 "./toolActivity": {58 "./toolActivity": {
55 "types": "./src/toolActivity.ts",59 "types": "./src/toolActivity.ts",
56 "import": "./src/toolActivity.ts"60 "import": "./src/toolActivity.ts"
...@@ -118,7 +122,8 @@...@@ -118,7 +122,8 @@
118 },122 },
119 "dependencies": {123 "dependencies": {
120 "@t3tools/contracts": "workspace:*",124 "@t3tools/contracts": "workspace:*",
121 "effect": "catalog:"125 "effect": "catalog:",
126 "yaml": "catalog:"
122 },127 },
123 "devDependencies": {128 "devDependencies": {
124 "@effect/platform-node": "catalog:",129 "@effect/platform-node": "catalog:",
packages/shared/src/schemaYaml.test.ts created+58
...@@ -0,0 +1,58 @@
1import * as Schema from "effect/Schema";
2import { describe, expect, it } from "vite-plus/test";
3
4import { fromYaml, fromYamlString } from "./schemaYaml.ts";
5
6const ProjectConfig = Schema.Struct({
7 name: Schema.String,
8 enabled: Schema.Boolean,
9 tags: Schema.Array(Schema.String),
10});
11
12describe("schemaYaml helpers", () => {
13 it("decodes YAML through a schema", () => {
14 const decodeConfig = Schema.decodeUnknownSync(fromYaml(ProjectConfig));
15
16 expect(
17 decodeConfig(`name: t3code
18enabled: true
19tags:
20 - codex
21 - effect
22`),
23 ).toEqual({
24 name: "t3code",
25 enabled: true,
26 tags: ["codex", "effect"],
27 });
28 });
29
30 it("encodes values as YAML text", () => {
31 const encodeConfig = Schema.encodeSync(fromYaml(ProjectConfig));
32
33 expect(
34 encodeConfig({
35 name: "t3code",
36 enabled: true,
37 tags: ["codex"],
38 }),
39 ).toBe(`name: t3code
40enabled: true
41tags:
42 - codex
43`);
44 });
45
46 it("can be used as a schema transformation directly", () => {
47 const schema = Schema.String.pipe(Schema.decodeTo(Schema.Unknown, fromYamlString));
48 const decodeYaml = Schema.decodeUnknownSync(schema);
49
50 expect(decodeYaml("answer: 42\n")).toEqual({ answer: 42 });
51 });
52
53 it("rejects malformed YAML", () => {
54 const decodeYaml = Schema.decodeUnknownSync(fromYaml(Schema.Unknown));
55
56 expect(() => decodeYaml("name: ok\n bad-indent: nope\n")).toThrow();
57 });
58});
packages/shared/src/schemaYaml.ts created+132
...@@ -0,0 +1,132 @@
1import * as Effect from "effect/Effect";
2import * as Option from "effect/Option";
3import * as Schema from "effect/Schema";
4import * as SchemaGetter from "effect/SchemaGetter";
5import * as SchemaIssue from "effect/SchemaIssue";
6import * as SchemaTransformation from "effect/SchemaTransformation";
7import {
8 parse as parseYamlString,
9 stringify as stringifyYamlValue,
10 type CreateNodeOptions,
11 type DocumentOptions,
12 type ParseOptions,
13 type SchemaOptions,
14 type ToJSOptions,
15 type ToStringOptions,
16} from "yaml";
17
18export type YamlParseOptions = ParseOptions & DocumentOptions & SchemaOptions & ToJSOptions;
19export type YamlStringifyOptions = DocumentOptions &
20 SchemaOptions &
21 ParseOptions &
22 CreateNodeOptions &
23 ToStringOptions;
24
25function formatYamlError(error: unknown): string {
26 return error instanceof Error ? error.message : String(error);
27}
28
29/**
30 * Parses a YAML string into a value.
31 *
32 * **When to use**
33 *
34 * Use when you need a schema getter to parse a present encoded YAML string
35 * during decoding.
36 *
37 * **Details**
38 *
39 * Parse failures become `SchemaIssue.InvalidValue` values.
40 *
41 * **Example** (Parse YAML)
42 *
43 * ```ts
44 * import { parseYaml } from "@t3tools/shared/schemaYaml"
45 *
46 * const parse = parseYaml<string>()
47 * // Getter<unknown, string>
48 * ```
49 *
50 * @see {@link stringifyYaml} for the inverse operation
51 */
52export function parseYaml<E extends string>(
53 options?: YamlParseOptions,
54): SchemaGetter.Getter<unknown, E> {
55 return SchemaGetter.transformOrFail((input: E) =>
56 Effect.try({
57 try: () => parseYamlString(input, options) as unknown,
58 catch: (error) =>
59 new SchemaIssue.InvalidValue(Option.some(input), { message: formatYamlError(error) }),
60 }),
61 );
62}
63
64/**
65 * Stringifies a present value as YAML.
66 *
67 * **When to use**
68 *
69 * Use when you need a schema getter to serialize a present decoded value to
70 * YAML text during encoding.
71 *
72 * **Details**
73 *
74 * Stringify failures become `SchemaIssue.InvalidValue` values.
75 *
76 * **Example** (Stringify YAML)
77 *
78 * ```ts
79 * import { stringifyYaml } from "@t3tools/shared/schemaYaml"
80 *
81 * const stringify = stringifyYaml()
82 * // Getter<string, unknown>
83 * ```
84 *
85 * @see {@link parseYaml} for the inverse operation
86 */
87export function stringifyYaml(
88 options?: YamlStringifyOptions,
89): SchemaGetter.Getter<string, unknown> {
90 return SchemaGetter.transformOrFail((input: unknown) =>
91 Effect.try({
92 try: () => stringifyYamlValue(input, options),
93 catch: (error) =>
94 new SchemaIssue.InvalidValue(Option.some(input), { message: formatYamlError(error) }),
95 }),
96 );
97}
98
99/**
100 * Decodes a YAML string and encodes a value as YAML text.
101 *
102 * **When to use**
103 *
104 * Use when you need a schema transformation to decode YAML stored or
105 * transmitted as a string before validating the parsed structure.
106 *
107 * **Details**
108 *
109 * Decode and encode failures become `InvalidValue` schema issues.
110 *
111 * **Example** (Parsing YAML)
112 *
113 * ```ts
114 * import * as Schema from "effect/Schema"
115 * import { fromYamlString } from "@t3tools/shared/schemaYaml"
116 *
117 * const schema = Schema.String.pipe(Schema.decodeTo(Schema.Unknown, fromYamlString))
118 * ```
119 */
120export const fromYamlString = new SchemaTransformation.Transformation<unknown, string>(
121 parseYaml(),
122 stringifyYaml(),
123);
124
125/**
126 * Build a schema that decodes a YAML string into `A`.
127 *
128 * Decode parses the input as YAML before validating the parsed value with the
129 * provided schema. Encode validates the value and serializes it as YAML text.
130 */
131export const fromYaml = <S extends Schema.Top>(schema: S) =>
132 Schema.String.pipe(Schema.decodeTo(schema, fromYamlString));
pnpm-lock.yaml+8-15
...@@ -30,9 +30,6 @@ catalogs:...@@ -30,9 +30,6 @@ catalogs:
30 vite-plus:30 vite-plus:
31 specifier: latest31 specifier: latest
32 version: 0.1.2432 version: 0.1.24
33 yaml:
34 specifier: ^2.9.0
35 version: 2.9.0
3633
37overrides:34overrides:
38 '@effect/atom-react': 4.0.0-beta.7335 '@effect/atom-react': 4.0.0-beta.73
...@@ -45,6 +42,7 @@ overrides:...@@ -45,6 +42,7 @@ overrides:
45 effect: 4.0.0-beta.7342 effect: 4.0.0-beta.73
46 vite: npm:@voidzero-dev/vite-plus-core@latest43 vite: npm:@voidzero-dev/vite-plus-core@latest
47 vitest: npm:@voidzero-dev/vite-plus-test@latest44 vitest: npm:@voidzero-dev/vite-plus-test@latest
45 yaml: ^2.9.0
4846
49packageExtensionsChecksum: sha256-MDpMSm2Rk8Y7FDIbaAgFkT45PZBPV7JBzjTAft+noEM=47packageExtensionsChecksum: sha256-MDpMSm2Rk8Y7FDIbaAgFkT45PZBPV7JBzjTAft+noEM=
5048
...@@ -93,9 +91,6 @@ importers:...@@ -93,9 +91,6 @@ importers:
93 vitest:91 vitest:
94 specifier: npm:@voidzero-dev/vite-plus-test@latest92 specifier: npm:@voidzero-dev/vite-plus-test@latest
95 version: '@voidzero-dev/vite-plus-test@0.1.24(@types/node@24.12.4)(@voidzero-dev/vite-plus-core@0.1.24(@types/node@24.12.4)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(yaml@2.9.0))(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(yaml@2.9.0)'93 version: '@voidzero-dev/vite-plus-test@0.1.24(@types/node@24.12.4)(@voidzero-dev/vite-plus-core@0.1.24(@types/node@24.12.4)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(yaml@2.9.0))(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(typescript@6.0.3)(unrun@0.2.39)(yaml@2.9.0)'
96 yaml:
97 specifier: 'catalog:'
98 version: 2.9.0
9994
100 apps/desktop:95 apps/desktop:
101 dependencies:96 dependencies:
...@@ -670,6 +665,9 @@ importers:...@@ -670,6 +665,9 @@ importers:
670 effect:665 effect:
671 specifier: 4.0.0-beta.73666 specifier: 4.0.0-beta.73
672 version: 4.0.0-beta.73(patch_hash=a28d840fa97ffebabe628e5562837c537d83c40cfdad8049de73c38086f2fb01)667 version: 4.0.0-beta.73(patch_hash=a28d840fa97ffebabe628e5562837c537d83c40cfdad8049de73c38086f2fb01)
668 yaml:
669 specifier: ^2.9.0
670 version: 2.9.0
673 devDependencies:671 devDependencies:
674 '@effect/platform-node':672 '@effect/platform-node':
675 specifier: 4.0.0-beta.73673 specifier: 4.0.0-beta.73
...@@ -3808,7 +3806,7 @@ packages:...@@ -3808,7 +3806,7 @@ packages:
3808 typescript: ^5.0.0 || ^6.0.03806 typescript: ^5.0.0 || ^6.0.0
3809 unplugin-unused: ^0.5.03807 unplugin-unused: ^0.5.0
3810 unrun: '*'3808 unrun: '*'
3811 yaml: ^2.4.23809 yaml: ^2.9.0
3812 peerDependenciesMeta:3810 peerDependenciesMeta:
3813 '@arethetypeswrong/core':3811 '@arethetypeswrong/core':
3814 optional: true3812 optional: true
...@@ -8041,11 +8039,6 @@ packages:...@@ -8041,11 +8039,6 @@ packages:
8041 resolution: {integrity: sha512-qhjK/bzSRZ6HtTvgeFvjNPJGWdZ0+x5NREV/9XZWFjIGezew2b4r5JPy66IfOhd5OA7KeFwk1JfmEbnTvev0cA==}8039 resolution: {integrity: sha512-qhjK/bzSRZ6HtTvgeFvjNPJGWdZ0+x5NREV/9XZWFjIGezew2b4r5JPy66IfOhd5OA7KeFwk1JfmEbnTvev0cA==}
8042 hasBin: true8040 hasBin: true
80438041
8044 yaml@2.7.1:
8045 resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==}
8046 engines: {node: '>= 14'}
8047 hasBin: true
8048
8049 yaml@2.9.0:8042 yaml@2.9.0:
8050 resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==}8043 resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==}
8051 engines: {node: '>= 14.6'}8044 engines: {node: '>= 14.6'}
...@@ -10525,7 +10518,9 @@ snapshots:...@@ -10525,7 +10518,9 @@ snapshots:
10525 metro-runtime: 0.84.410518 metro-runtime: 0.84.4
10526 transitivePeerDependencies:10519 transitivePeerDependencies:
10527 - '@babel/core'10520 - '@babel/core'
10521 - bufferutil
10528 - supports-color10522 - supports-color
10523 - utf-8-validate
1052910524
10530 '@react-native/normalize-colors@0.85.3': {}10525 '@react-native/normalize-colors@0.85.3': {}
1053110526
...@@ -16274,9 +16269,7 @@ snapshots:...@@ -16274,9 +16269,7 @@ snapshots:
16274 vscode-languageserver-textdocument: 1.0.1216269 vscode-languageserver-textdocument: 1.0.12
16275 vscode-languageserver-types: 3.17.516270 vscode-languageserver-types: 3.17.5
16276 vscode-uri: 3.1.016271 vscode-uri: 3.1.0
16277 yaml: 2.7.116272 yaml: 2.9.0
16278
16279 yaml@2.7.1: {}
1628016273
16281 yaml@2.9.0: {}16274 yaml@2.9.0: {}
1628216275
pnpm-workspace.yaml+1
...@@ -45,6 +45,7 @@ overrides:...@@ -45,6 +45,7 @@ overrides:
45 effect: "catalog:"45 effect: "catalog:"
46 vite: "catalog:"46 vite: "catalog:"
47 vitest: "catalog:"47 vitest: "catalog:"
48 yaml: "catalog:"
48peerDependencyRules:49peerDependencyRules:
49 allowAny:50 allowAny:
50 - vite51 - vite
scripts/build-desktop-artifact.ts+9-7
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1#!/usr/bin/env node1#!/usr/bin/env node
22
3import { parse as parseYaml } from "yaml";3import { fromYaml } from "@t3tools/shared/schemaYaml";
4import rootPackageJson from "../package.json" with { type: "json" };4import rootPackageJson from "../package.json" with { type: "json" };
5import desktopPackageJson from "../apps/desktop/package.json" with { type: "json" };5import desktopPackageJson from "../apps/desktop/package.json" with { type: "json" };
6import serverPackageJson from "../apps/server/package.json" with { type: "json" };6import serverPackageJson from "../apps/server/package.json" with { type: "json" };
...@@ -29,22 +29,24 @@ const LINUX_ICON_SIZES = [16, 22, 24, 32, 48, 64, 128, 256, 512] as const;...@@ -29,22 +29,24 @@ const LINUX_ICON_SIZES = [16, 22, 24, 32, 48, 64, 128, 256, 512] as const;
29const BuildPlatform = Schema.Literals(["mac", "linux", "win"]);29const BuildPlatform = Schema.Literals(["mac", "linux", "win"]);
30const BuildArch = Schema.Literals(["arm64", "x64", "universal"]);30const BuildArch = Schema.Literals(["arm64", "x64", "universal"]);
3131
32interface WorkspaceConfig {32const WorkspaceConfig = Schema.Struct({
33 readonly catalog?: Record<string, string>;33 catalog: Schema.optional(Schema.Record(Schema.String, Schema.String)),
34 readonly overrides?: Record<string, string>;34 overrides: Schema.optional(Schema.Record(Schema.String, Schema.String)),
35}35});
36type WorkspaceConfig = typeof WorkspaceConfig.Type;
3637
37const RepoRoot = Effect.service(Path.Path).pipe(38const RepoRoot = Effect.service(Path.Path).pipe(
38 Effect.flatMap((path) => path.fromFileUrl(new URL("..", import.meta.url))),39 Effect.flatMap((path) => path.fromFileUrl(new URL("..", import.meta.url))),
39);40);
40const encodeJsonString = Schema.encodeEffect(Schema.UnknownFromJsonString);41const encodeJsonString = Schema.encodeEffect(Schema.UnknownFromJsonString);
42const decodeWorkspaceConfig = Schema.decodeEffect(fromYaml(WorkspaceConfig));
4143
42const readWorkspaceConfig = Effect.fn("readWorkspaceConfig")(function* () {44const readWorkspaceConfig = Effect.fn("readWorkspaceConfig")(function* () {
43 const fs = yield* FileSystem.FileSystem;45 const fs = yield* FileSystem.FileSystem;
44 const path = yield* Path.Path;46 const path = yield* Path.Path;
45 const repoRoot = yield* RepoRoot;47 const repoRoot = yield* RepoRoot;
46 const workspaceYaml = yield* fs.readFileString(path.join(repoRoot, "pnpm-workspace.yaml"));48 const workspaceYaml = yield* fs.readFileString(path.join(repoRoot, "pnpm-workspace.yaml"));
47 return parseYaml(workspaceYaml) as WorkspaceConfig;49 return yield* decodeWorkspaceConfig(workspaceYaml);
48});50});
4951
50interface DesktopBuildIconAssets {52interface DesktopBuildIconAssets {
...@@ -776,7 +778,7 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* (...@@ -776,7 +778,7 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* (
776 try: () => resolveCatalogDependencies(workspaceOverrides, workspaceCatalog, "apps/desktop"),778 try: () => resolveCatalogDependencies(workspaceOverrides, workspaceCatalog, "apps/desktop"),
777 catch: (cause) =>779 catch: (cause) =>
778 new BuildScriptError({780 new BuildScriptError({
779 message: "Could not resolve overrides from package.json.",781 message: "Could not resolve overrides from pnpm-workspace.yaml.",
780 cause,782 cause,
781 }),783 }),
782 });784 });
scripts/lib/reference-repos.ts+4-4
...@@ -3,7 +3,7 @@ export interface ReferenceRepo {...@@ -3,7 +3,7 @@ export interface ReferenceRepo {
3 readonly prefix: string;3 readonly prefix: string;
4 readonly repository: string;4 readonly repository: string;
5 readonly latestRef: string;5 readonly latestRef: string;
6 readonly packageJsonPath: string;6 readonly versionSourcePath: string;
7 readonly packageVersionPath: ReadonlyArray<string>;7 readonly packageVersionPath: ReadonlyArray<string>;
8 readonly versionTagPrefix: string;8 readonly versionTagPrefix: string;
9}9}
...@@ -14,8 +14,8 @@ export const referenceRepos: ReadonlyArray<ReferenceRepo> = [...@@ -14,8 +14,8 @@ export const referenceRepos: ReadonlyArray<ReferenceRepo> = [
14 prefix: ".repos/effect-smol",14 prefix: ".repos/effect-smol",
15 repository: "https://github.com/Effect-TS/effect-smol.git",15 repository: "https://github.com/Effect-TS/effect-smol.git",
16 latestRef: "main",16 latestRef: "main",
17 packageJsonPath: "package.json",17 versionSourcePath: "pnpm-workspace.yaml",
18 packageVersionPath: ["workspaces", "catalog", "effect"],18 packageVersionPath: ["catalog", "effect"],
19 versionTagPrefix: "effect@",19 versionTagPrefix: "effect@",
20 },20 },
21 {21 {
...@@ -23,7 +23,7 @@ export const referenceRepos: ReadonlyArray<ReferenceRepo> = [...@@ -23,7 +23,7 @@ export const referenceRepos: ReadonlyArray<ReferenceRepo> = [
23 prefix: ".repos/alchemy-effect",23 prefix: ".repos/alchemy-effect",
24 repository: "https://github.com/alchemy-run/alchemy-effect.git",24 repository: "https://github.com/alchemy-run/alchemy-effect.git",
25 latestRef: "main",25 latestRef: "main",
26 packageJsonPath: "infra/relay/package.json",26 versionSourcePath: "infra/relay/package.json",
27 packageVersionPath: ["dependencies", "alchemy"],27 packageVersionPath: ["dependencies", "alchemy"],
28 versionTagPrefix: "v",28 versionTagPrefix: "v",
29 },29 },
scripts/sync-reference-repos.test.ts+6-6
...@@ -63,8 +63,8 @@ it.layer(NodeServices.layer)("sync-reference-repos", (it) => {...@@ -63,8 +63,8 @@ it.layer(NodeServices.layer)("sync-reference-repos", (it) => {
63 prefix: "sync-reference-repos-version-",63 prefix: "sync-reference-repos-version-",
64 });64 });
65 yield* fs.writeFileString(65 yield* fs.writeFileString(
66 path.join(rootDir, "package.json"),66 path.join(rootDir, "pnpm-workspace.yaml"),
67 '{"workspaces":{"catalog":{"effect":"4.0.0-beta.73"}}}',67 "catalog:\n effect: 4.0.0-beta.73\n",
68 );68 );
6969
70 assert.equal(70 assert.equal(
...@@ -110,8 +110,8 @@ it.layer(NodeServices.layer)("sync-reference-repos", (it) => {...@@ -110,8 +110,8 @@ it.layer(NodeServices.layer)("sync-reference-repos", (it) => {
110 prefix: "sync-reference-repos-plan-",110 prefix: "sync-reference-repos-plan-",
111 });111 });
112 yield* fs.writeFileString(112 yield* fs.writeFileString(
113 path.join(rootDir, "package.json"),113 path.join(rootDir, "pnpm-workspace.yaml"),
114 '{"workspaces":{"catalog":{"effect":"4.0.0-beta.73"}}}',114 "catalog:\n effect: 4.0.0-beta.73\n",
115 );115 );
116116
117 const addPlan = yield* planReferenceRepoSync(effectSmol, rootDir, false);117 const addPlan = yield* planReferenceRepoSync(effectSmol, rootDir, false);
...@@ -140,8 +140,8 @@ it.layer(NodeServices.layer)("sync-reference-repos", (it) => {...@@ -140,8 +140,8 @@ it.layer(NodeServices.layer)("sync-reference-repos", (it) => {
140 prefix: "sync-reference-repos-run-",140 prefix: "sync-reference-repos-run-",
141 });141 });
142 yield* fs.writeFileString(142 yield* fs.writeFileString(
143 path.join(rootDir, "package.json"),143 path.join(rootDir, "pnpm-workspace.yaml"),
144 '{"workspaces":{"catalog":{"effect":"4.0.0-beta.73"}}}',144 "catalog:\n effect: 4.0.0-beta.73\n",
145 );145 );
146146
147 yield* syncReferenceRepos({ rootDir, repoId: "effect-smol" }).pipe(147 yield* syncReferenceRepos({ rootDir, repoId: "effect-smol" }).pipe(
scripts/sync-reference-repos.ts+36-7
...@@ -12,6 +12,7 @@ import * as Schema from "effect/Schema";...@@ -12,6 +12,7 @@ import * as Schema from "effect/Schema";
12import * as Stream from "effect/Stream";12import * as Stream from "effect/Stream";
13import { Command, Flag } from "effect/unstable/cli";13import { Command, Flag } from "effect/unstable/cli";
14import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";14import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
15import { fromYaml } from "@t3tools/shared/schemaYaml";
1516
16import { referenceRepos, type ReferenceRepo } from "./lib/reference-repos.ts";17import { referenceRepos, type ReferenceRepo } from "./lib/reference-repos.ts";
1718
...@@ -36,7 +37,8 @@ export class ReferenceRepoSyncError extends Data.TaggedError("ReferenceRepoSyncE...@@ -36,7 +37,8 @@ export class ReferenceRepoSyncError extends Data.TaggedError("ReferenceRepoSyncE
36 readonly cause?: unknown;37 readonly cause?: unknown;
37}> {}38}> {}
3839
39const decodePackageJson = Schema.decodeUnknownEffect(Schema.UnknownFromJsonString);40const decodeJsonSource = Schema.decodeUnknownEffect(Schema.UnknownFromJsonString);
41const decodeYamlSource = Schema.decodeEffect(fromYaml(Schema.Unknown));
4042
41const collectStreamAsString = <E>(stream: Stream.Stream<Uint8Array, E>): Effect.Effect<string, E> =>43const collectStreamAsString = <E>(stream: Stream.Stream<Uint8Array, E>): Effect.Effect<string, E> =>
42 stream.pipe(44 stream.pipe(
...@@ -58,6 +60,33 @@ function readNestedString(input: unknown, keys: ReadonlyArray<string>): string |...@@ -58,6 +60,33 @@ function readNestedString(input: unknown, keys: ReadonlyArray<string>): string |
58 return typeof value === "string" && value.length > 0 ? value : undefined;60 return typeof value === "string" && value.length > 0 ? value : undefined;
59}61}
6062
63function decodeVersionSource(
64 sourcePath: string,
65 content: string,
66): Effect.Effect<unknown, ReferenceRepoSyncError> {
67 if (sourcePath.endsWith(".yaml") || sourcePath.endsWith(".yml")) {
68 return decodeYamlSource(content).pipe(
69 Effect.mapError(
70 (cause) =>
71 new ReferenceRepoSyncError({
72 message: `Unable to parse version source ${sourcePath}.`,
73 cause,
74 }),
75 ),
76 );
77 }
78
79 return decodeJsonSource(content).pipe(
80 Effect.mapError(
81 (cause) =>
82 new ReferenceRepoSyncError({
83 message: `Unable to parse version source ${sourcePath}.`,
84 cause,
85 }),
86 ),
87 );
88}
89
61function getSelectedRepos(90function getSelectedRepos(
62 repoId: string | undefined,91 repoId: string | undefined,
63): Effect.Effect<ReadonlyArray<ReferenceRepo>, ReferenceRepoSyncError> {92): Effect.Effect<ReadonlyArray<ReferenceRepo>, ReferenceRepoSyncError> {
...@@ -88,22 +117,22 @@ export const resolveReferenceRepoRef = Effect.fn("resolveReferenceRepoRef")(func...@@ -88,22 +117,22 @@ export const resolveReferenceRepoRef = Effect.fn("resolveReferenceRepoRef")(func
88117
89 const fs = yield* FileSystem.FileSystem;118 const fs = yield* FileSystem.FileSystem;
90 const path = yield* Path.Path;119 const path = yield* Path.Path;
91 const packageJsonPath = path.join(rootDir, repo.packageJsonPath);120 const versionSourcePath = path.join(rootDir, repo.versionSourcePath);
92 const packageJson = yield* fs.readFileString(packageJsonPath).pipe(121 const versionSourceContent = yield* fs.readFileString(versionSourcePath).pipe(
93 Effect.flatMap(decodePackageJson),
94 Effect.mapError(122 Effect.mapError(
95 (cause) =>123 (cause) =>
96 new ReferenceRepoSyncError({124 new ReferenceRepoSyncError({
97 message: `Unable to read package version for '${repo.id}' from ${packageJsonPath}.`,125 message: `Unable to read package version for '${repo.id}' from ${versionSourcePath}.`,
98 cause,126 cause,
99 }),127 }),
100 ),128 ),
101 );129 );
102 const version = readNestedString(packageJson, repo.packageVersionPath);130 const versionSource = yield* decodeVersionSource(repo.versionSourcePath, versionSourceContent);
131 const version = readNestedString(versionSource, repo.packageVersionPath);
103132
104 if (!version) {133 if (!version) {
105 return yield* new ReferenceRepoSyncError({134 return yield* new ReferenceRepoSyncError({
106 message: `Unable to resolve package version for '${repo.id}' at ${repo.packageJsonPath}:${repo.packageVersionPath.join(135 message: `Unable to resolve package version for '${repo.id}' at ${repo.versionSourcePath}:${repo.packageVersionPath.join(
107 ".",136 ".",
108 )}.`,137 )}.`,
109 });138 });