import type { Assembly } from "@jsii/spec"; import type { Schema } from "jsii-docgen"; import { createContext, FunctionComponent, useContext, useMemo } from "react"; import { useQuery, UseQueryResult } from "react-query"; import { useParams } from "react-router-dom"; import { Types, MenuItem, parseMarkdownStructure } from "./util"; import { fetchAssembly } from "../../api/package/assembly"; import { fetchJsonDocs, fetchMarkdownDocs } from "../../api/package/docs"; import { fetchMetadata, Metadata } from "../../api/package/metadata"; import { Language, languageFilename } from "../../constants/languages"; import { QUERY_PARAMS } from "../../constants/url"; import { useLanguage } from "../../hooks/useLanguage"; import { useQueryParams } from "../../hooks/useQueryParams"; import { useVersions } from "../../hooks/useVersions"; import { NotFound } from "../NotFound"; interface PathParams { name: string; scope?: string; version: string; } interface PackageState { apiReference?: Types; assembly: UseQueryResult; hasDocs: boolean; hasError: boolean; isLoadingDocs: boolean; isSupported: boolean; language: Language; markdownDocs: UseQueryResult; jsonDocs: UseQueryResult; metadata: UseQueryResult; name: string; pageDescription: string; pageTitle: string; readme?: string; scope?: string; version: string; allVersions?: string[]; menuItems: MenuItem[]; } const PackageStateContext = createContext(undefined); /** * Consumes shared page-leve data for components on the Package page */ export const usePackageState = () => { const state = useContext(PackageStateContext); if (!state) { throw new Error( "This component must be a child of a " ); } return state; }; /** * Provides shared page-level data to components on the Package page */ export const PackageStateProvider: FunctionComponent = ({ children }) => { const { name, scope, version }: PathParams = useParams(); const id = `${scope}/${name}/v${version}`; const [language] = useLanguage(); const q = useQueryParams(); const submodule = q.get(QUERY_PARAMS.SUBMODULE) ?? ""; const { data: versionData } = useVersions(); const pkgName = scope ? `${scope}/${name}` : name; const allVersions = versionData?.packages[pkgName]; const markdownDocs = useQuery(`${id}-docs-${language}-${submodule}-md`, () => fetchMarkdownDocs( name, version, languageFilename[language], scope, submodule ) ); const jsonDocs = useQuery(`${id}-docs-${language}-${submodule}-json`, () => fetchJsonDocs(name, version, languageFilename[language], scope, submodule) ); const assembly = useQuery(`${id}-assembly`, () => fetchAssembly(name, version, scope) ); const metadata = useQuery(`${id}-metadata`, () => fetchMetadata(name, version, scope) ); const pageTitle = `${scope ? `${scope}/${name}` : name} ${version}`; const pageDescription = assembly.data?.description ?? ""; const hasError = Boolean( markdownDocs.error || jsonDocs.error || assembly.error ); const hasDocs = Boolean( !markdownDocs.isLoading && !jsonDocs.isLoading && !assembly.isLoading && markdownDocs.data && jsonDocs.data && assembly.data ); // This will also be true if it cannot be verified (assembly not there) const isSupported = Boolean( language === Language.TypeScript || assembly.isLoading || assembly.error || assembly.data?.targets?.[language.toString()] != null ); const isLoadingDocs = Boolean( !metadata.isLoading && (assembly.isLoading || markdownDocs.isLoading || jsonDocs.isLoading) ); const parsedMd = useMemo(() => { if (!markdownDocs.data) return { menuItems: [] }; return parseMarkdownStructure(markdownDocs.data, { scope, name, version, language, submodule, }); }, [markdownDocs.data, name, scope, version, language, submodule]); // Handle missing JSON for assembly if (assembly.error) { return ; } return ( {children} ); };