1import * as Exit from "effect/Exit";
2import * as Schema from "effect/Schema";
3
4import { T3ProjectFile, T3_PROJECT_FILE_SCHEMA_URL } from "@t3tools/contracts";
5
6import { fromLenientJson } from "./schemaJson.ts";
7
8/**
9 * Codec between the raw `t3.json` file contents (lenient JSONC string) and the
10 * decoded {@link T3ProjectFile}.
11 */
12export const T3ProjectFileFromJson = fromLenientJson(T3ProjectFile);
13
14const decodeT3ProjectFile = Schema.decodeExit(T3ProjectFileFromJson);
15
16/**
17 * Decode raw `t3.json` contents, treating invalid or malformed files as
18 * absent. Clients use this to read optional defaults (scripts, thread env
19 * mode) without surfacing decode errors to the user.
20 */
21export function parseT3ProjectFile(contents: string): T3ProjectFile | null {
22 const decoded = decodeT3ProjectFile(contents);
23 return Exit.isSuccess(decoded) ? decoded.value : null;
24}
25
26/**
27 * Build the publishable JSON Schema document for `t3.json` (draft 2020-12).
28 *
29 * Served from the marketing site at {@link T3_PROJECT_FILE_SCHEMA_URL} so
30 * editors get LSP support via a `$schema` reference.
31 */
32export function buildT3ProjectFileJsonSchema(): Record<string, unknown> {
33 // Closed objects, as before effect rc.113 changed the generator default;
34 // editors then flag unknown keys in t3.json.
35 const document = Schema.toJsonSchemaDocument(T3ProjectFile, { onExcessProperty: "error" });
36 const jsonSchema: Record<string, unknown> = {
37 $schema: "https://json-schema.org/draft/2020-12/schema",
38 $id: T3_PROJECT_FILE_SCHEMA_URL,
39 ...document.schema,
40 };
41 if (document.definitions && Object.keys(document.definitions).length > 0) {
42 jsonSchema.$defs = document.definitions;
43 }
44 return jsonSchema;
45}