UNPKG

sanity

Version:

Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches

152 lines (134 loc) 5 kB
import {type CliCommandContext, type CliOutputter} from '@sanity/cli' import chalk from 'chalk' import sortBy from 'lodash/sortBy' import uniq from 'lodash/uniq' import {isDefined} from '../../../manifest/manifestTypeHelpers' import { SANITY_WORKSPACE_SCHEMA_TYPE, type StoredWorkspaceSchema, } from '../../../manifest/manifestTypes' import {type SchemaStoreActionResult, type SchemaStoreContext} from './schemaStoreTypes' import {createManifestExtractor, ensureManifestExtractSatisfied} from './utils/mainfestExtractor' import {createManifestReader} from './utils/manifestReader' import {createSchemaApiClient} from './utils/schemaApiClient' import {getDatasetsOutString} from './utils/schemaStoreOutStrings' import { filterLogReadProjectIdMismatch, parseListSchemasConfig, type SchemaStoreCommonFlags, } from './utils/schemaStoreValidation' export interface SchemaListFlags extends SchemaStoreCommonFlags { json?: boolean id?: string } class DatasetError extends Error { public dataset: string constructor(dataset: string, options?: ErrorOptions) { super((options?.cause as {message?: string})?.message, options) this.dataset = dataset this.name = 'DatasetError' } } export default function listSchemasActionForCommand( flags: SchemaListFlags, context: CliCommandContext, ): Promise<SchemaStoreActionResult> { return listSchemasAction(flags, { ...context, manifestExtractor: createManifestExtractor(context), }) } /** * Lists stored schemas found in workspace datasets. * * Workspaces are determined by on-disk manifest file – not directly from sanity.config. * All schema store actions require a manifest to exist, so we regenerate it by default. * Manifest generation can be optionally disabled with --no-manifest-extract. * In this case the command uses and existing file or throws when missing. */ export async function listSchemasAction( flags: SchemaListFlags, context: SchemaStoreContext, ): Promise<SchemaStoreActionResult> { const {json, id, manifestDir, extractManifest} = parseListSchemasConfig(flags, context) const {output, apiClient, jsonReader, manifestExtractor} = context // prettier-ignore if (!(await ensureManifestExtractSatisfied({schemaRequired: true, extractManifest, manifestDir, manifestExtractor, output,}))) { return 'failure' } const {client, projectId} = createSchemaApiClient(apiClient) const manifest = await createManifestReader({manifestDir, output, jsonReader}).getManifest() const workspaces = manifest.workspaces.filter((workspace) => filterLogReadProjectIdMismatch(workspace, projectId, output), ) const datasets = uniq(workspaces.map((w) => w.dataset)) const schemaResults = await Promise.allSettled( datasets.map(async (dataset) => { try { const datasetClient = client.withConfig({dataset}) return id ? datasetClient.getDocument<StoredWorkspaceSchema>(id) : datasetClient.fetch<StoredWorkspaceSchema[]>(`*[_type == $type]`, { type: SANITY_WORKSPACE_SCHEMA_TYPE, }) } catch (error) { throw new DatasetError(dataset, {cause: error}) } }), ) const schemas = schemaResults .map((result, index) => { if (result.status === 'fulfilled') return result.value if (result.reason instanceof DatasetError) { const message = chalk.red( `↳ Failed to fetch schema from dataset "${result.reason.dataset}":\n ${result.reason.message}`, ) output.error(message) } else { //hubris inc: given the try-catch wrapping all the full promise "this should never happen" throw result.reason } return [] }) .filter(isDefined) .flat() if (schemas.length === 0) { const datasetString = getDatasetsOutString(datasets) output.error( id ? `Schema for id "${id}" not found in ${datasetString}` : `No schemas found in ${datasetString}`, ) return 'failure' } if (json) { output.print(`${JSON.stringify(id ? schemas[0] : schemas, null, 2)}`) } else { printSchemaList({schemas, output}) } return 'success' } function printSchemaList({ schemas, output, }: { schemas: StoredWorkspaceSchema[] output: CliOutputter }) { const ordered = sortBy( schemas.map(({_createdAt: createdAt, _id: id, workspace}) => { return [id, workspace.name, workspace.dataset, workspace.projectId, createdAt].map(String) }), ['createdAt'], ) const headings = ['Id', 'Workspace', 'Dataset', 'ProjectId', 'CreatedAt'] const rows = ordered.reverse() const maxWidths = rows.reduce( (max, row) => row.map((current, index) => Math.max(current.length, max[index])), headings.map((str) => str.length), ) const rowToString = (row: string[]) => row.map((col, i) => `${col}`.padEnd(maxWidths[i])).join(' ') output.print(chalk.cyan(rowToString(headings))) rows.forEach((row) => output.print(rowToString(row))) }