| 1 | import { |
| 2 | T3_PROJECT_FILE_NAME, |
| 3 | type EnvironmentId, |
| 4 | type T3ProjectFile, |
| 5 | type T3ProjectFileScript, |
| 6 | } from "@t3tools/contracts"; |
| 7 | import { parseT3ProjectFile } from "@t3tools/shared/t3ProjectFile"; |
| 8 | import { useMemo } from "react"; |
| 9 | |
| 10 | import { useProjectFileQuery } from "~/components/files/projectFilesQueryState"; |
| 11 | |
| 12 | const NO_SCRIPTS: ReadonlyArray<T3ProjectFileScript> = []; |
| 13 | |
| 14 | export interface T3ProjectFileState { |
| 15 | /** |
| 16 | * - `valid`: t3.json exists and decoded. |
| 17 | * - `invalid`: t3.json exists but fails to decode (the server then ignores |
| 18 | * the whole file, including `iconPath` and every script). |
| 19 | * - `missing`: no readable t3.json at the workspace root. |
| 20 | * - `loading`: the file query has not settled yet. |
| 21 | */ |
| 22 | status: "loading" | "missing" | "invalid" | "valid"; |
| 23 | /** The decoded file when status is `valid`, null otherwise. */ |
| 24 | file: T3ProjectFile | null; |
| 25 | scripts: ReadonlyArray<T3ProjectFileScript>; |
| 26 | } |
| 27 | |
| 28 | /** |
| 29 | * Decoded state of the project's checked-in `t3.json`, including whether the |
| 30 | * file exists but is broken — which the runtime otherwise swallows silently. |
| 31 | */ |
| 32 | export function useT3ProjectFileState( |
| 33 | environmentId: EnvironmentId, |
| 34 | cwd: string | null, |
| 35 | ): T3ProjectFileState { |
| 36 | const query = useProjectFileQuery(environmentId, cwd ?? "", T3_PROJECT_FILE_NAME, cwd !== null); |
| 37 | const contents = query.data && !query.data.truncated ? query.data.contents : null; |
| 38 | const isPending = query.isPending; |
| 39 | return useMemo(() => { |
| 40 | if (contents === null) { |
| 41 | return { |
| 42 | status: isPending ? "loading" : "missing", |
| 43 | file: null, |
| 44 | scripts: NO_SCRIPTS, |
| 45 | } as const; |
| 46 | } |
| 47 | const file = parseT3ProjectFile(contents); |
| 48 | if (file === null) { |
| 49 | return { status: "invalid", file: null, scripts: NO_SCRIPTS } as const; |
| 50 | } |
| 51 | return { status: "valid", file, scripts: file.scripts ?? NO_SCRIPTS } as const; |
| 52 | }, [contents, isPending]); |
| 53 | } |
| 54 | |
| 55 | /** |
| 56 | * Scripts declared in the project's checked-in `t3.json`, offered in the |
| 57 | * scripts menu for import. Missing, truncated, or invalid files resolve to |
| 58 | * an empty list. |
| 59 | */ |
| 60 | export function useT3ProjectFileScripts( |
| 61 | environmentId: EnvironmentId, |
| 62 | cwd: string | null, |
| 63 | ): ReadonlyArray<T3ProjectFileScript> { |
| 64 | return useT3ProjectFileState(environmentId, cwd).scripts; |
| 65 | } |