| author | |
| committer | |
| log | 37bf0f0d1d3ca53ca0b8f349ac7eaf086afaf975 |
| tree | 67a498e84663108dcc7a7a5e47dc506f609639fd |
| parent | 6a1c4da528a3ab433dc19de2d728a66a1ee92a79 |
| signature | Signed by PGP key B5690EEEBB952194 |
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"; |
| 18 | import { resolveCatalogDependencies } from "../../../scripts/lib/resolve-catalog.ts"; | 18 | import { resolveCatalogDependencies } from "../../../scripts/lib/resolve-catalog.ts"; |
| 19 | import { fromJsonStringPretty } from "@t3tools/shared/schemaJson"; | 19 | import { fromJsonStringPretty } from "@t3tools/shared/schemaJson"; |
| 20 | import { fromYaml } from "@t3tools/shared/schemaYaml"; | ||
| 20 | import serverPackageJson from "../package.json" with { type: "json" }; | 21 | import serverPackageJson from "../package.json" with { type: "json" }; |
| 21 | import { parse as parseYaml } from "yaml"; | ||
| 22 | 22 | ||
| 23 | interface PackageJson { | 23 | interface PackageJson { |
| 24 | name: string; | 24 | name: string; |
| ... | @@ -39,10 +39,12 @@ interface PackageJson { | ... | @@ -39,10 +39,12 @@ interface PackageJson { |
| 39 | const PackageJsonPrettyJson = fromJsonStringPretty(Schema.Unknown); | 39 | const PackageJsonPrettyJson = fromJsonStringPretty(Schema.Unknown); |
| 40 | const encodePackageJson = Schema.encodeEffect(PackageJsonPrettyJson); | 40 | const encodePackageJson = Schema.encodeEffect(PackageJsonPrettyJson); |
| 41 | 41 | ||
| 42 | interface WorkspaceConfig { | 42 | const 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 | }); |
| 46 | type WorkspaceConfig = typeof WorkspaceConfig.Type; | ||
| 47 | const decodeWorkspaceConfig = Schema.decodeEffect(fromYaml(WorkspaceConfig)); | ||
| 46 | 48 | ||
| 47 | class CliError extends Data.TaggedError("CliError")<{ | 49 | class 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 | }); |
| 63 | 65 | ||
| 64 | const runCommand = Effect.fn("runCommand")(function* (command: ChildProcess.Command) { | 66 | const 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 @@ | ||
| 1 | import * as Schema from "effect/Schema"; | ||
| 2 | import { describe, expect, it } from "vite-plus/test"; | ||
| 3 | |||
| 4 | import { fromYaml, fromYamlString } from "./schemaYaml.ts"; | ||
| 5 | |||
| 6 | const ProjectConfig = Schema.Struct({ | ||
| 7 | name: Schema.String, | ||
| 8 | enabled: Schema.Boolean, | ||
| 9 | tags: Schema.Array(Schema.String), | ||
| 10 | }); | ||
| 11 | |||
| 12 | describe("schemaYaml helpers", () => { | ||
| 13 | it("decodes YAML through a schema", () => { | ||
| 14 | const decodeConfig = Schema.decodeUnknownSync(fromYaml(ProjectConfig)); | ||
| 15 | |||
| 16 | expect( | ||
| 17 | decodeConfig(`name: t3code | ||
| 18 | enabled: true | ||
| 19 | tags: | ||
| 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 | ||
| 40 | enabled: true | ||
| 41 | tags: | ||
| 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 @@ | ||
| 1 | import * as Effect from "effect/Effect"; | ||
| 2 | import * as Option from "effect/Option"; | ||
| 3 | import * as Schema from "effect/Schema"; | ||
| 4 | import * as SchemaGetter from "effect/SchemaGetter"; | ||
| 5 | import * as SchemaIssue from "effect/SchemaIssue"; | ||
| 6 | import * as SchemaTransformation from "effect/SchemaTransformation"; | ||
| 7 | import { | ||
| 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 | |||
| 18 | export type YamlParseOptions = ParseOptions & DocumentOptions & SchemaOptions & ToJSOptions; | ||
| 19 | export type YamlStringifyOptions = DocumentOptions & | ||
| 20 | SchemaOptions & | ||
| 21 | ParseOptions & | ||
| 22 | CreateNodeOptions & | ||
| 23 | ToStringOptions; | ||
| 24 | |||
| 25 | function 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 | */ | ||
| 52 | export 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 | */ | ||
| 87 | export 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 | */ | ||
| 120 | export 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 | */ | ||
| 131 | export 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: latest | 31 | specifier: latest |
| 32 | version: 0.1.24 | 32 | version: 0.1.24 |
| 33 | yaml: | ||
| 34 | specifier: ^2.9.0 | ||
| 35 | version: 2.9.0 | ||
| 36 | 33 | ||
| 37 | overrides: | 34 | overrides: |
| 38 | '@effect/atom-react': 4.0.0-beta.73 | 35 | '@effect/atom-react': 4.0.0-beta.73 |
| ... | @@ -45,6 +42,7 @@ overrides: | ... | @@ -45,6 +42,7 @@ overrides: |
| 45 | effect: 4.0.0-beta.73 | 42 | effect: 4.0.0-beta.73 |
| 46 | vite: npm:@voidzero-dev/vite-plus-core@latest | 43 | vite: npm:@voidzero-dev/vite-plus-core@latest |
| 47 | vitest: npm:@voidzero-dev/vite-plus-test@latest | 44 | vitest: npm:@voidzero-dev/vite-plus-test@latest |
| 45 | yaml: ^2.9.0 | ||
| 48 | 46 | ||
| 49 | packageExtensionsChecksum: sha256-MDpMSm2Rk8Y7FDIbaAgFkT45PZBPV7JBzjTAft+noEM= | 47 | packageExtensionsChecksum: sha256-MDpMSm2Rk8Y7FDIbaAgFkT45PZBPV7JBzjTAft+noEM= |
| 50 | 48 | ||
| ... | @@ -93,9 +91,6 @@ importers: | ... | @@ -93,9 +91,6 @@ importers: |
| 93 | vitest: | 91 | vitest: |
| 94 | specifier: npm:@voidzero-dev/vite-plus-test@latest | 92 | 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 | ||
| 99 | 94 | ||
| 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.73 | 666 | 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.73 | 673 | specifier: 4.0.0-beta.73 |
| ... | @@ -3808,7 +3806,7 @@ packages: | ... | @@ -3808,7 +3806,7 @@ packages: |
| 3808 | typescript: ^5.0.0 || ^6.0.0 | 3806 | typescript: ^5.0.0 || ^6.0.0 |
| 3809 | unplugin-unused: ^0.5.0 | 3807 | unplugin-unused: ^0.5.0 |
| 3810 | unrun: '*' | 3808 | unrun: '*' |
| 3811 | yaml: ^2.4.2 | 3809 | yaml: ^2.9.0 |
| 3812 | peerDependenciesMeta: | 3810 | peerDependenciesMeta: |
| 3813 | '@arethetypeswrong/core': | 3811 | '@arethetypeswrong/core': |
| 3814 | optional: true | 3812 | 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: true | 8040 | hasBin: true |
| 8043 | 8041 | ||
| 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.4 | 10518 | metro-runtime: 0.84.4 |
| 10526 | transitivePeerDependencies: | 10519 | transitivePeerDependencies: |
| 10527 | - '@babel/core' | 10520 | - '@babel/core' |
| 10521 | - bufferutil | ||
| 10528 | - supports-color | 10522 | - supports-color |
| 10523 | - utf-8-validate | ||
| 10529 | 10524 | ||
| 10530 | '@react-native/normalize-colors@0.85.3': {} | 10525 | '@react-native/normalize-colors@0.85.3': {} |
| 10531 | 10526 | ||
| ... | @@ -16274,9 +16269,7 @@ snapshots: | ... | @@ -16274,9 +16269,7 @@ snapshots: |
| 16274 | vscode-languageserver-textdocument: 1.0.12 | 16269 | vscode-languageserver-textdocument: 1.0.12 |
| 16275 | vscode-languageserver-types: 3.17.5 | 16270 | vscode-languageserver-types: 3.17.5 |
| 16276 | vscode-uri: 3.1.0 | 16271 | vscode-uri: 3.1.0 |
| 16277 | yaml: 2.7.1 | 16272 | yaml: 2.9.0 |
| 16278 | |||
| 16279 | yaml@2.7.1: {} | ||
| 16280 | 16273 | ||
| 16281 | yaml@2.9.0: {} | 16274 | yaml@2.9.0: {} |
| 16282 | 16275 |
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:" | ||
| 48 | peerDependencyRules: | 49 | peerDependencyRules: |
| 49 | allowAny: | 50 | allowAny: |
| 50 | - vite | 51 | - vite |
scripts/build-desktop-artifact.ts+9-7| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | #!/usr/bin/env node | 1 | #!/usr/bin/env node |
| 2 | 2 | ||
| 3 | import { parse as parseYaml } from "yaml"; | 3 | import { fromYaml } from "@t3tools/shared/schemaYaml"; |
| 4 | import rootPackageJson from "../package.json" with { type: "json" }; | 4 | import rootPackageJson from "../package.json" with { type: "json" }; |
| 5 | import desktopPackageJson from "../apps/desktop/package.json" with { type: "json" }; | 5 | import desktopPackageJson from "../apps/desktop/package.json" with { type: "json" }; |
| 6 | import serverPackageJson from "../apps/server/package.json" with { type: "json" }; | 6 | import 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; |
| 29 | const BuildPlatform = Schema.Literals(["mac", "linux", "win"]); | 29 | const BuildPlatform = Schema.Literals(["mac", "linux", "win"]); |
| 30 | const BuildArch = Schema.Literals(["arm64", "x64", "universal"]); | 30 | const BuildArch = Schema.Literals(["arm64", "x64", "universal"]); |
| 31 | 31 | ||
| 32 | interface WorkspaceConfig { | 32 | const 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 | }); |
| 36 | type WorkspaceConfig = typeof WorkspaceConfig.Type; | ||
| 36 | 37 | ||
| 37 | const RepoRoot = Effect.service(Path.Path).pipe( | 38 | const 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 | ); |
| 40 | const encodeJsonString = Schema.encodeEffect(Schema.UnknownFromJsonString); | 41 | const encodeJsonString = Schema.encodeEffect(Schema.UnknownFromJsonString); |
| 42 | const decodeWorkspaceConfig = Schema.decodeEffect(fromYaml(WorkspaceConfig)); | ||
| 41 | 43 | ||
| 42 | const readWorkspaceConfig = Effect.fn("readWorkspaceConfig")(function* () { | 44 | const 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 | }); |
| 49 | 51 | ||
| 50 | interface DesktopBuildIconAssets { | 52 | interface 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 | ); |
| 69 | 69 | ||
| 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 | ); |
| 116 | 116 | ||
| 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 | ); |
| 146 | 146 | ||
| 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"; |
| 12 | import * as Stream from "effect/Stream"; | 12 | import * as Stream from "effect/Stream"; |
| 13 | import { Command, Flag } from "effect/unstable/cli"; | 13 | import { Command, Flag } from "effect/unstable/cli"; |
| 14 | import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; | 14 | import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; |
| 15 | import { fromYaml } from "@t3tools/shared/schemaYaml"; | ||
| 15 | 16 | ||
| 16 | import { referenceRepos, type ReferenceRepo } from "./lib/reference-repos.ts"; | 17 | import { referenceRepos, type ReferenceRepo } from "./lib/reference-repos.ts"; |
| 17 | 18 | ||
| ... | @@ -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 | }> {} |
| 38 | 39 | ||
| 39 | const decodePackageJson = Schema.decodeUnknownEffect(Schema.UnknownFromJsonString); | 40 | const decodeJsonSource = Schema.decodeUnknownEffect(Schema.UnknownFromJsonString); |
| 41 | const decodeYamlSource = Schema.decodeEffect(fromYaml(Schema.Unknown)); | ||
| 40 | 42 | ||
| 41 | const collectStreamAsString = <E>(stream: Stream.Stream<Uint8Array, E>): Effect.Effect<string, E> => | 43 | const 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 | } |
| 60 | 62 | ||
| 63 | function 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 | |||
| 61 | function getSelectedRepos( | 90 | function 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 |
| 88 | 117 | ||
| 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); | ||
| 103 | 132 | ||
| 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 | }); |