UNPKG

@sanity/schema

Version:

- **`Schema`** A collection of types - **`Type`** A specification of a data structure. Available through schema lookup. - **`Member type`** A member type is a type contained by a schema type. For example, an array may specify the allowed item types by def

1,462 lines (1,461 loc) • 59 kB
import { omit, pick, omitBy, isUndefined, uniqBy, isFinite, capitalize, startCase, isPlainObject, toPath, flatMap, castArray, cloneDeep } from "lodash-es"; import arrify from "arrify"; const DEFAULT_OVERRIDEABLE_FIELDS = [ "jsonType", "type", "name", "title", "description", "options", "fieldsets", "validation", "readOnly", "hidden", "components", "diffComponent", "initialValue", "deprecated" ], OWN_PROPS_NAME = "_internal_ownProps", ALL_FIELDS_GROUP_NAME = "all-fields"; function lazyGetter(target, key, getter, config = {}) { return Object.defineProperty(target, key, { configurable: !0, enumerable: config.enumerable !== !1, get() { const val = getter(); return Object.defineProperty(target, key, { value: val, writable: !!config.writable, configurable: !1 }), val; } }), target; } function hiddenGetter(target, key, value) { Object.defineProperty(target, key, { enumerable: !1, writable: !1, configurable: !1, value }); } const OVERRIDABLE_FIELDS$f = [...DEFAULT_OVERRIDEABLE_FIELDS], ANY_CORE = { name: "any", type: null, jsonType: "any" }, AnyType = { get() { return ANY_CORE; }, extend(subTypeDef, extendMember) { const ownProps = { ...subTypeDef, of: subTypeDef.of.map((fieldDef) => ({ name: fieldDef.name, type: extendMember(omit(fieldDef, "name")) })) }, parsed = Object.assign(pick(ANY_CORE, OVERRIDABLE_FIELDS$f), ownProps, { type: ANY_CORE }); return hiddenGetter(parsed, OWN_PROPS_NAME, ownProps), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { if (extensionDef.of) throw new Error('Cannot override `of` property of subtypes of "array"'); const subOwnProps = pick(extensionDef, OVERRIDABLE_FIELDS$f), current = Object.assign({}, parent, subOwnProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, subOwnProps), subtype(current); } }; } } }, OVERRIDABLE_FIELDS$e = [...DEFAULT_OVERRIDEABLE_FIELDS], ARRAY_CORE = { name: "array", type: null, jsonType: "array", of: [] }, ArrayType = { get() { return ARRAY_CORE; }, extend(subTypeDef, createMemberType) { const parsed = Object.assign(pick(ARRAY_CORE, OVERRIDABLE_FIELDS$e), subTypeDef, { type: ARRAY_CORE }); return lazyGetter(parsed, "of", () => subTypeDef.of.map((ofTypeDef) => createMemberType.cached(ofTypeDef))), lazyGetter(parsed, OWN_PROPS_NAME, () => ({ ...subTypeDef, of: parsed.of }), { enumerable: !1, writable: !1 }), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { if (extensionDef.of) throw new Error('Cannot override `of` property of subtypes of "array"'); const ownProps = pick(extensionDef, OVERRIDABLE_FIELDS$e), current = Object.assign({}, parent, ownProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, ownProps), subtype(current); } }; } } }; function warnIfPreviewOnOptions(type) { type.options && type.options.preview && console.warn(`Heads up! The preview config is no longer defined on "options", but instead on the type/field itself. Please move {options: {preview: ...}} to {..., preview: ...} on the type/field definition of "${type.name}". `); } function warnIfPreviewHasFields(type) { const preview = type.preview || (type.options || {}).preview; preview && "fields" in preview && console.warn(`Heads up! "preview.fields" should be renamed to "preview.select". Please update the preview config for "${type.name}". `); } function isEmpty(object) { for (const key in object) if (object.hasOwnProperty(key)) return !1; return !0; } function _stringify(value, options, depth) { if (depth > options.maxDepth) return "..."; if (Array.isArray(value)) { if (value.length === 0) return "[empty]"; const capLength = Math.max(value.length - options.maxBreadth), asString2 = value.slice(0, options.maxBreadth).map((item, index) => _stringify(item, options, depth + 1)).concat(capLength > 0 ? `\u2026+${capLength}` : []).join(", "); return depth === 0 ? asString2 : `[${asString2}]`; } if (typeof value == "object" && value !== null) { const keys = Object.keys(value).filter( (key) => !options.ignoreKeys.includes(key) && typeof value[key] < "u" ); if (isEmpty(pick(value, keys))) return "{empty}"; const asString2 = keys.slice(0, options.maxBreadth).map((key) => `${key}: ${_stringify(value[key], options, depth + 1)}`).join(", "); return depth === 0 ? asString2 : `{${asString2}}`; } const asString = String(value); return asString === "" ? '""' : asString; } function stringify(value, options = {}) { const opts = { maxDepth: "maxDepth" in options ? options.maxDepth : 2, maxBreadth: "maxBreadth" in options ? options.maxBreadth : 2, ignoreKeys: "ignoreKeys" in options ? options.ignoreKeys : [] }; return _stringify(value, opts, 0); } const OPTIONS = { maxEntries: 2, maxDepth: 2, maxBreadth: 2, ignoreKeys: ["_id", "_type", "_key", "_ref"] }; function createFallbackPrepare(fieldNames) { return (value) => ({ title: stringify(pick(value, fieldNames), OPTIONS) }); } function isBlockField(field) { return field.type === "array" && field.of && field.of.some((member) => member.type === "block") || !1; } const TITLE_CANDIDATES = ["title", "name", "label", "heading", "header", "caption"], DESCRIPTION_CANDIDATES = ["description", ...TITLE_CANDIDATES]; function fieldHasReferenceTo(fieldDef, refType) { return arrify(fieldDef.to || []).some((memberTypeDef) => memberTypeDef.type === refType); } function isImageAssetField(fieldDef) { return fieldHasReferenceTo(fieldDef, "sanity.imageAsset"); } function resolveImageAssetPath(typeDef) { const fields = typeDef.fields || [], imageAssetField = fields.find(isImageAssetField); if (imageAssetField) return imageAssetField.name; const fieldWithImageAsset = fields.find( (fieldDef) => (fieldDef.fields || []).some(isImageAssetField) ); return fieldWithImageAsset ? `${fieldWithImageAsset.name}.asset` : void 0; } function isFileAssetField(fieldDef) { return fieldHasReferenceTo(fieldDef, "sanity.fileAsset"); } function resolveFileAssetPath(typeDef) { const fields = typeDef.fields || [], assetField = fields.find(isFileAssetField); if (assetField) return assetField.name; const fieldWithFileAsset = fields.find( (fieldDef) => (fieldDef.fields || []).some(isFileAssetField) ); return fieldWithFileAsset ? `${fieldWithFileAsset.name}.asset` : void 0; } function guessPreviewFields(rawObjectTypeDef) { const objectTypeDef = { fields: [], ...rawObjectTypeDef }, stringFieldNames = objectTypeDef.fields.filter((field) => field.type === "string").map((field) => field.name), blockFieldNames = objectTypeDef.fields.filter(isBlockField).map((field) => field.name); let titleField = TITLE_CANDIDATES.find( (candidate) => stringFieldNames.includes(candidate) || blockFieldNames.includes(candidate) ), descField = DESCRIPTION_CANDIDATES.find( (candidate) => candidate !== titleField && (stringFieldNames.includes(candidate) || blockFieldNames.includes(candidate)) ); titleField || (titleField = stringFieldNames[0] || blockFieldNames[0], descField = stringFieldNames[1] || blockFieldNames[1]); const mediaField = objectTypeDef.fields.find((field) => field.type === "image"), imageAssetPath = resolveImageAssetPath(objectTypeDef); if (!titleField) { const fileAssetPath = resolveFileAssetPath(objectTypeDef); fileAssetPath && (titleField = `${fileAssetPath}.originalFilename`), imageAssetPath && (titleField = `${imageAssetPath}.originalFilename`); } if (!titleField && !imageAssetPath) { const fieldNames = objectTypeDef.fields.map((field) => field.name); return { select: fieldNames.reduce((acc, fieldName) => (acc[fieldName] = fieldName, acc), {}), prepare: createFallbackPrepare(fieldNames) }; } return { select: omitBy( { title: titleField, description: descField, media: mediaField ? mediaField.name : imageAssetPath }, isUndefined ) }; } function parseSelection(selection) { return selection.reduce((acc, field) => (acc[field] = field, acc), {}); } function parsePreview(preview) { if (!preview) return preview; const select = preview.select || preview.fields || {}; return Array.isArray(select) ? { ...pick(preview, ["prepare", "component"]), select: parseSelection(select) } : { ...pick(preview, ["prepare", "component"]), select }; } function createPreviewGetter(objectTypeDef) { return function() { return warnIfPreviewOnOptions(objectTypeDef), warnIfPreviewHasFields(objectTypeDef), parsePreview(objectTypeDef.preview || (objectTypeDef.options || {}).preview) || guessPreviewFields(objectTypeDef); }; } const DEFAULT_LINK_ANNOTATION = { type: "object", name: "link", title: "Link", i18nTitleKey: "inputs.portable-text.annotation.link", options: { modal: { type: "popover" } }, fields: [ { name: "href", type: "url", title: "Link", description: "A valid web, email, phone, or relative link.", validation: (Rule3) => Rule3.uri({ scheme: ["http", "https", "tel", "mailto"], allowRelative: !0 }) } ] }, DEFAULT_TEXT_FIELD = { type: "text", name: "text", title: "Text" }, DEFAULT_MARKS_FIELD = { name: "marks", type: "array", of: [{ type: "string" }], title: "Marks" }, LIST_TYPES = { bullet: { title: "Bulleted list", value: "bullet", i18nTitleKey: "inputs.portable-text.list-type.bullet" }, numbered: { title: "Numbered list", value: "number", i18nTitleKey: "inputs.portable-text.list-type.number" } }, DEFAULT_LIST_TYPES = [LIST_TYPES.bullet, LIST_TYPES.numbered], BLOCK_STYLES = { normal: { title: "Normal", value: "normal", i18nTitleKey: "inputs.portable-text.style.normal" }, h1: { title: "Heading 1", value: "h1", i18nTitleKey: "inputs.portable-text.style.h1" }, h2: { title: "Heading 2", value: "h2", i18nTitleKey: "inputs.portable-text.style.h2" }, h3: { title: "Heading 3", value: "h3", i18nTitleKey: "inputs.portable-text.style.h3" }, h4: { title: "Heading 4", value: "h4", i18nTitleKey: "inputs.portable-text.style.h4" }, h5: { title: "Heading 5", value: "h5", i18nTitleKey: "inputs.portable-text.style.h5" }, h6: { title: "Heading 6", value: "h6", i18nTitleKey: "inputs.portable-text.style.h6" }, blockquote: { title: "Quote", value: "blockquote", i18nTitleKey: "inputs.portable-text.style.quote" } }, DEFAULT_BLOCK_STYLES = [ BLOCK_STYLES.normal, BLOCK_STYLES.h1, BLOCK_STYLES.h2, BLOCK_STYLES.h3, BLOCK_STYLES.h4, BLOCK_STYLES.h5, BLOCK_STYLES.h6, BLOCK_STYLES.blockquote ], DECORATOR_STRONG = { title: "Strong", value: "strong", i18nTitleKey: "inputs.portable-text.decorator.strong" }, DECORATOR_EMPHASIS = { title: "Italic", value: "em", i18nTitleKey: "inputs.portable-text.decorator.emphasis" }, DECORATOR_CODE = { title: "Code", value: "code", i18nTitleKey: "inputs.portable-text.decorator.code" }, DECORATOR_UNDERLINE = { title: "Underline", value: "underline", i18nTitleKey: "inputs.portable-text.decorator.underline" }, DECORATOR_STRIKE = { title: "Strike", value: "strike-through", i18nTitleKey: "inputs.portable-text.decorator.strike-through" }, DECORATORS = { strong: DECORATOR_STRONG, em: DECORATOR_EMPHASIS, code: DECORATOR_CODE, underline: DECORATOR_UNDERLINE, strikeThrough: DECORATOR_STRIKE }, DEFAULT_DECORATORS = [ DECORATORS.strong, DECORATORS.em, DECORATORS.code, DECORATORS.underline, DECORATORS.strikeThrough ], INHERITED_FIELDS$1 = [ "type", "name", "title", "jsonType", "description", "options", "fieldsets", "icon" ], BLOCK_CORE = { name: "block", title: "Block", type: null, jsonType: "object" }, DEFAULT_OPTIONS$3 = {}, BlockType = { get() { return BLOCK_CORE; }, extend(subTypeDef, extendMember) { const options = { ...subTypeDef.options || DEFAULT_OPTIONS$3 }, { marks, styles, lists, of, ...rest } = subTypeDef, childrenField = createChildrenField(marks, of), styleField = createStyleField(styles), listItemField = createListItemField(lists), markDefsField = { name: "markDefs", title: "Mark definitions", type: "array", of: marks?.annotations || DEFAULT_ANNOTATIONS }, fields = [childrenField, styleField, listItemField, markDefsField, { name: "level", title: "Indentation", type: "number" }].concat( subTypeDef.fields || [] ), ownProps = { ...rest, options }, parsed = Object.assign(pick(BLOCK_CORE, INHERITED_FIELDS$1), ownProps, { type: BLOCK_CORE }); return lazyGetter(parsed, "fields", () => fields.map((fieldDef) => extendMember.cachedField(fieldDef))), lazyGetter(parsed, "preview", createPreviewGetter(subTypeDef)), lazyGetter( parsed, OWN_PROPS_NAME, () => ({ ...ownProps, fields: parsed.fields, preview: parsed.preview }), { enumerable: !1, writable: !1 } ), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { if (extensionDef.fields) throw new Error('Cannot override `fields` of subtypes of "block"'); const subOwnProps = pick(extensionDef, INHERITED_FIELDS$1), current = Object.assign({}, parent, subOwnProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, subOwnProps), subtype(current); } }; } } }; function ensureNormalStyle(styles) { return styles.some((style) => style.value === "normal") ? styles : [BLOCK_STYLES.normal, ...styles]; } function createStyleField(styles) { return { name: "style", title: "Style", type: "string", options: { list: ensureNormalStyle(styles || DEFAULT_BLOCK_STYLES) } }; } function createListItemField(lists) { return { name: "listItem", title: "List type", type: "string", options: { list: lists || DEFAULT_LIST_TYPES } }; } const DEFAULT_ANNOTATIONS = [DEFAULT_LINK_ANNOTATION]; function createChildrenField(marks, of = []) { return { name: "children", title: "Content", type: "array", of: [ { type: "span", fields: [DEFAULT_TEXT_FIELD, DEFAULT_MARKS_FIELD], annotations: marks && marks.annotations ? marks.annotations : DEFAULT_ANNOTATIONS, decorators: marks && marks.decorators ? marks.decorators : DEFAULT_DECORATORS }, ...of.filter((memberType) => memberType.type !== "span") ] }; } const INHERITED_FIELDS = [ "type", "name", "title", "jsonType", "description", "options", "fieldsets", "icon" ], SPAN_CORE = { name: "span", title: "Span", type: null, jsonType: "object" }, MARKS_FIELD = { name: "marks", title: "Marks", type: "array", of: [{ type: "string" }] }, TEXT_FIELD = { name: "text", title: "Text", type: "string" }, DEFAULT_OPTIONS$2 = {}, SpanType = { get() { return SPAN_CORE; }, extend(subTypeDef, extendMember) { const options = { ...subTypeDef.options || DEFAULT_OPTIONS$2 }, { annotations = [], marks = [] } = subTypeDef, fields = [MARKS_FIELD, TEXT_FIELD], ownProps = { ...subTypeDef, options }, parsed = Object.assign(pick(SPAN_CORE, INHERITED_FIELDS), ownProps, { type: SPAN_CORE }); return lazyGetter(parsed, "fields", () => fields.map((fieldDef) => extendMember.cachedField(fieldDef))), lazyGetter(parsed, "annotations", () => annotations.map(extendMember)), lazyGetter(parsed, "marks", () => marks.map(extendMember)), lazyGetter(parsed, "preview", createPreviewGetter(subTypeDef)), lazyGetter( parsed, OWN_PROPS_NAME, () => ({ ...ownProps, fields: parsed.fields, annotations: parsed.annotations, marks: parsed.marks, preview: parsed.preview }), { enumerable: !1, writable: !1 } ), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { if (extensionDef.fields) throw new Error('Cannot override `fields` of subtypes of "span"'); const subOwnProps = pick(extensionDef, INHERITED_FIELDS), current = Object.assign({}, parent, subOwnProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, subOwnProps), subtype(current); } }; } } }; var primitivePreview = { prepare: (val) => ({ title: String(val) }) }; const OVERRIDABLE_FIELDS$d = [...DEFAULT_OVERRIDEABLE_FIELDS], BOOLEAN_CORE = { name: "boolean", title: "Boolean", type: null, jsonType: "boolean" }, BooleanType = { get() { return BOOLEAN_CORE; }, extend(subTypeDef) { const ownProps = { ...subTypeDef, preview: primitivePreview }, parsed = Object.assign(pick(BOOLEAN_CORE, OVERRIDABLE_FIELDS$d), ownProps, { type: BOOLEAN_CORE }); return hiddenGetter(parsed, OWN_PROPS_NAME, ownProps), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { const subOwnProps = pick(extensionDef, OVERRIDABLE_FIELDS$d), current = Object.assign({}, parent, subOwnProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, subOwnProps), subtype(current); } }; } } }, DEFAULT_MAX_FIELD_DEPTH = 5, stringFieldsSymbols = {}, getStringFieldSymbol = (maxDepth) => (stringFieldsSymbols[maxDepth] || (stringFieldsSymbols[maxDepth] = /* @__PURE__ */ Symbol(`__cachedStringFields_${maxDepth}`)), stringFieldsSymbols[maxDepth]), isReference = (type) => type.type && type.type.name === "reference", portableTextFields = ["style", "list"], isPortableTextBlock = (type) => type.name === "block" || type.type && isPortableTextBlock(type.type), isPortableTextArray = (type) => type.jsonType === "array" && Array.isArray(type.of) && type.of.some(isPortableTextBlock); function reduceType(type, reducer, acc, path = [], maxDepth) { if (maxDepth < 0) return acc; const accumulator = reducer(acc, type, path); return type.jsonType === "array" && Array.isArray(type.of) ? reduceArray(type, reducer, accumulator, path, maxDepth) : type.jsonType === "object" && Array.isArray(type.fields) && !isReference(type) ? reduceObject(type, reducer, accumulator, path, maxDepth) : accumulator; } function reduceArray(arrayType, reducer, accumulator, path, maxDepth) { return arrayType.of.reduce( (acc, ofType) => reduceType(ofType, reducer, acc, path, maxDepth - 1), accumulator ); } function reduceObject(objectType, reducer, accumulator, path, maxDepth) { const isPtBlock = isPortableTextBlock(objectType); return objectType.fields.reduce((acc, field) => { if (isPtBlock && portableTextFields.includes(field.name)) return acc; const segment = [field.name].concat(field.type.jsonType === "array" ? [[]] : []); return reduceType(field.type, reducer, acc, path.concat(segment), maxDepth - 1); }, accumulator); } const BASE_WEIGHTS = [ { weight: 1, path: ["_id"] }, { weight: 1, path: ["_type"] } ], PREVIEW_FIELD_WEIGHT_MAP = { title: 10, subtitle: 5, description: 1.5 }; function deriveFromPreview(type, maxDepth) { const select = type?.preview?.select; if (!select) return []; const fields = []; for (const fieldName of Object.keys(select)) { if (!(fieldName in PREVIEW_FIELD_WEIGHT_MAP)) continue; const path = select[fieldName].split("."); maxDepth > -1 && path.length - 1 > maxDepth || fields.push({ weight: PREVIEW_FIELD_WEIGHT_MAP[fieldName], path }); } return fields; } function getCachedStringFieldPaths(type, maxDepth) { const symbol = getStringFieldSymbol(maxDepth); return type[symbol] || (type[symbol] = uniqBy( [ ...BASE_WEIGHTS, ...deriveFromPreview(type, maxDepth), ...getStringFieldPaths(type, maxDepth).map((path) => ({ weight: 1, path })), ...getPortableTextFieldPaths(type, maxDepth).map((path) => ({ weight: 1, path, mapWith: "pt::text" })) ], (spec) => spec.path.join(".") )), type[symbol]; } function getCachedBaseFieldPaths(type, maxDepth) { const symbol = getStringFieldSymbol(maxDepth); return type[symbol] || (type[symbol] = uniqBy( [...BASE_WEIGHTS, ...deriveFromPreview(type, maxDepth)], (spec) => spec.path.join(".") )), type[symbol]; } function getStringFieldPaths(type, maxDepth) { return reduceType(type, (accumulator, childType, path) => childType.jsonType === "string" ? [...accumulator, path] : accumulator, [], [], maxDepth); } function getPortableTextFieldPaths(type, maxDepth) { return reduceType(type, (accumulator, childType, path) => isPortableTextArray(childType) ? [...accumulator, path] : accumulator, [], [], maxDepth); } function resolveSearchConfigForBaseFieldPaths(type, maxDepth) { return getCachedBaseFieldPaths(type, normalizeMaxDepth(maxDepth)); } function resolveSearchConfig(type, maxDepth) { return getCachedStringFieldPaths(type, normalizeMaxDepth(maxDepth)); } function normalizeMaxDepth(maxDepth) { return !isFinite(maxDepth) || maxDepth < 1 || maxDepth > DEFAULT_MAX_FIELD_DEPTH ? DEFAULT_MAX_FIELD_DEPTH - 1 : maxDepth - 1; } const REF_FIELD$2 = { name: "_ref", title: "Referenced document ID", type: "string" }, WEAK_FIELD$2 = { name: "_weak", title: "Weak reference marker", type: "boolean" }, DATASET_FIELD = { name: "_dataset", title: "Target dataset", type: "string" }, PROJECT_ID_FIELD = { name: "_projectId", title: "Target project ID", type: "string", hidden: !0 }, REFERENCE_FIELDS$2 = [REF_FIELD$2, WEAK_FIELD$2, DATASET_FIELD, PROJECT_ID_FIELD], OVERRIDABLE_FIELDS$c = [...DEFAULT_OVERRIDEABLE_FIELDS], CROSS_DATASET_REFERENCE_CORE = { name: "crossDatasetReference", type: null, jsonType: "object" }; function humanize$2(arr, conjunction) { const len = arr.length; if (len === 1) return arr[0]; const first = arr.slice(0, len - 1), last = arr[len - 1]; return `${first.join(", ")} ${conjunction} ${last}`; } function buildTitle$2(type) { return !type.to || type.to.length === 0 ? "Cross dataset Reference" : `Cross dataset reference to ${humanize$2( arrify(type.to).map((toType) => toType.title || capitalize(toType.type)), "or" ).toLowerCase()}`; } const CrossDatasetReferenceType = { get() { return CROSS_DATASET_REFERENCE_CORE; }, extend(subTypeDef, createMemberType) { if (!subTypeDef.to) throw new Error( `Missing "to" field in cross dataset reference definition. Check the type ${subTypeDef.name}` ); const parsed = Object.assign( pick(CROSS_DATASET_REFERENCE_CORE, OVERRIDABLE_FIELDS$c), subTypeDef, { type: CROSS_DATASET_REFERENCE_CORE } ); return lazyGetter(parsed, "fields", () => REFERENCE_FIELDS$2.map((fieldDef) => createMemberType.cachedField(fieldDef))), lazyGetter(parsed, "to", () => arrify(subTypeDef.to).map((toType) => ({ ...toType, // eslint-disable-next-line camelcase __experimental_search: resolveSearchConfigForBaseFieldPaths(toType) }))), lazyGetter(parsed, "title", () => subTypeDef.title || buildTitle$2(parsed)), lazyGetter( parsed, OWN_PROPS_NAME, () => ({ ...subTypeDef, fields: parsed.fields, to: parsed.to, title: parsed.title }), { enumerable: !1, writable: !1 } ), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { if (extensionDef.of) throw new Error('Cannot override `of` of subtypes of "reference"'); const ownProps = pick(extensionDef, OVERRIDABLE_FIELDS$c), current = Object.assign({}, parent, ownProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, ownProps), subtype(current); } }; } } }, OVERRIDABLE_FIELDS$b = [...DEFAULT_OVERRIDEABLE_FIELDS], DATE_CORE = { name: "date", title: "Datetime", type: null, jsonType: "string" }, DateType = { get() { return DATE_CORE; }, extend(subTypeDef) { const ownProps = { ...subTypeDef, preview: primitivePreview }, parsed = Object.assign(pick(DATE_CORE, OVERRIDABLE_FIELDS$b), ownProps, { type: DATE_CORE }); return hiddenGetter(parsed, OWN_PROPS_NAME, ownProps), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { const subOwnProps = pick(extensionDef, OVERRIDABLE_FIELDS$b), current = Object.assign({}, parent, subOwnProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, subOwnProps), subtype(current); } }; } } }, OVERRIDABLE_FIELDS$a = [...DEFAULT_OVERRIDEABLE_FIELDS], DATETIME_CORE = { name: "datetime", title: "Datetime", type: null, jsonType: "string" }, DateTimeType = { get() { return DATETIME_CORE; }, extend(subTypeDef) { const ownProps = { ...subTypeDef, preview: primitivePreview }, parsed = Object.assign(pick(DATETIME_CORE, OVERRIDABLE_FIELDS$a), ownProps, { type: DATETIME_CORE }); return hiddenGetter(parsed, OWN_PROPS_NAME, ownProps), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { const subOwnProps = pick(extensionDef, OVERRIDABLE_FIELDS$a), current = Object.assign({}, parent, subOwnProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, subOwnProps), subtype(current); } }; } } }, CANDIDATES = ["title", "name", "label", "heading", "header", "caption", "description"], PRIMITIVES = ["string", "boolean", "number"], isPrimitive = (field) => PRIMITIVES.includes(field.type); function guessOrderingConfig(objectTypeDef) { let candidates = CANDIDATES.filter( (candidate) => objectTypeDef.fields.some((field) => isPrimitive(field) && field.name === candidate) ); return candidates.length === 0 && (candidates = objectTypeDef.fields.filter(isPrimitive).map((field) => field.name)), candidates.map( (name) => ({ name, i18n: { title: { key: `default-orderings.${name}`, ns: "studio" } }, title: capitalize(startCase(name)), by: [{ field: name, direction: "asc" }] }) ); } function normalizeSearchConfigs(configs) { if (!Array.isArray(configs)) throw new Error( "The search config of a document type must be an array of search config objects" ); return configs.map((conf) => { if (conf === "defaults") return conf; if (!isPlainObject(conf)) throw new Error("Search config must be an object of {path: string, weight: number}"); return { weight: "weight" in conf ? conf.weight : 1, path: toPath(conf.path), mapWith: typeof conf.mapWith == "string" ? conf.mapWith : void 0 }; }); } const OVERRIDABLE_FIELDS$9 = [ ...DEFAULT_OVERRIDEABLE_FIELDS, "orderings", "__experimental_search", "blockEditor", "icon" ], ObjectType = { get() { return { name: "object", title: "Object", type: null, jsonType: "object" }; }, extend(rawSubTypeDef, createMemberType) { const subTypeDef = { fields: [], ...rawSubTypeDef }, options = { ...subTypeDef.options }, ownProps = { ...subTypeDef, title: subTypeDef.title || (subTypeDef.name ? startCase(subTypeDef.name) : "Object"), options, orderings: subTypeDef.orderings || guessOrderingConfig(subTypeDef), fields: subTypeDef.fields.map( (fieldDef) => createMemberType.cachedObjectField(fieldDef) ) }, parsed = Object.assign(pick(this.get(), OVERRIDABLE_FIELDS$9), ownProps, { type: this.get() }); return lazyGetter(parsed, "fieldsets", () => createFieldsets(subTypeDef, parsed.fields)), lazyGetter(parsed, "groups", () => createFieldsGroups(subTypeDef, parsed.fields)), lazyGetter(parsed, "preview", createPreviewGetter(subTypeDef)), lazyGetter( parsed, OWN_PROPS_NAME, () => ({ ...ownProps, preview: parsed.preview }), { enumerable: !1, writable: !1 } ), lazyGetter( parsed, "__experimental_search", () => { const userProvidedSearchConfig = subTypeDef.__experimental_search ? normalizeSearchConfigs(subTypeDef.__experimental_search) : null; return userProvidedSearchConfig ? userProvidedSearchConfig.map( (entry) => entry === "defaults" ? normalizeSearchConfigs(subTypeDef) : entry ) : resolveSearchConfig(parsed); }, { enumerable: !1 } ), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { if (extensionDef.fields) throw new Error('Cannot override `fields` of subtypes of "object"'); const subOwnProps = pick(extensionDef, OVERRIDABLE_FIELDS$9); subOwnProps.title = extensionDef.title || subTypeDef.title || (subTypeDef.name ? startCase(subTypeDef.name) : "Object"); const current = Object.assign({}, parent, pick(extensionDef, OVERRIDABLE_FIELDS$9), { type: parent }); return lazyGetter(current, "__experimental_search", () => parent.__experimental_search), hiddenGetter(current, OWN_PROPS_NAME, subOwnProps), subtype(current); } }; } } }; function createFieldsets(typeDef, fields) { const fieldsetsByName = {}; for (const fieldset of typeDef.fieldsets || []) { if (fieldsetsByName[fieldset.name]) throw new Error( `Duplicate fieldset name "${fieldset.name}" found for type '${typeDef.title ? typeDef.title : startCase(typeDef.name)}'` ); fieldsetsByName[fieldset.name] = { title: startCase(fieldset.name), ...fieldset, fields: [] }; } const fieldsets = /* @__PURE__ */ new Set(); for (const field of fields) { if (!field.fieldset) { fieldsets.add({ single: !0, field }); continue; } const fieldset = fieldsetsByName[field.fieldset]; if (!fieldset) throw new Error( `Fieldset '${field.fieldset}' is not defined in schema for type '${typeDef.name}'` ); fieldset.fields.push(field), fieldsets.add(fieldset); } return Array.from(fieldsets); } function createFieldsGroups(typeDef, fields) { const groupsByName = {}; let numDefaultGroups = 0; for (const group of typeDef.groups || []) { if (groupsByName[group.name]) throw new Error( `Duplicate group name "${group.name}" found for type '${typeDef.title ? typeDef.title : startCase(typeDef.name)}'` ); if (groupsByName[group.name] = { title: startCase(group.name), ...group, fields: [] }, group.default && ++numDefaultGroups > 1) throw new Error( `More than one field group defined as default for type '${typeDef.title ? typeDef.title : startCase(typeDef.name)}' - only 1 is supported` ); } return fields.forEach((field) => { const fieldGroupNames = castArray(field.group || []); fieldGroupNames.length !== 0 && fieldGroupNames.forEach((fieldGroupName) => { const currentGroup = groupsByName[fieldGroupName]; if (!currentGroup) throw new Error( `Field group '${fieldGroupName}' is not defined in schema for type '${typeDef.title ? typeDef.name : startCase(typeDef.name)}'` ); currentGroup.fields.push(field); }); }), flatMap(groupsByName).filter( // All fields group is added by default in structure. // To pass the properties from the schema to the form state, we need to include it in the list of groups. (group) => group.fields.length > 0 || group.name === ALL_FIELDS_GROUP_NAME ); } const DOCUMENT_CORE = { name: "document", title: "Document", type: null, jsonType: "object" }, DocumentType = { get() { return DOCUMENT_CORE; }, extend: ObjectType.extend }, OVERRIDABLE_FIELDS$8 = [...DEFAULT_OVERRIDEABLE_FIELDS], EMAIL_CORE = { name: "email", title: "Email", type: null, jsonType: "string" }; lazyGetter( EMAIL_CORE, OWN_PROPS_NAME, () => ({ ...EMAIL_CORE, validation: (Rule3) => Rule3.email() }), { enumerable: !1 } ); const EmailType = { get() { return EMAIL_CORE; }, extend(subTypeDef) { const ownProps = { ...subTypeDef, preview: primitivePreview }, parsed = Object.assign(pick(EMAIL_CORE, OVERRIDABLE_FIELDS$8), ownProps, { type: EMAIL_CORE }); return hiddenGetter(parsed, OWN_PROPS_NAME, ownProps), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { const subOwnProps = pick(extensionDef, OVERRIDABLE_FIELDS$8), current = Object.assign({}, parent, subOwnProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, subOwnProps), subtype(current); } }; } } }, ASSET_FIELD$1 = { name: "asset", type: "reference", to: { type: "sanity.fileAsset" } }, MEDIA_LIBRARY_ASSET_FIELD$1 = { name: "media", type: "globalDocumentReference", hidden: !0, to: [{ type: "sanity.asset" }] }, OVERRIDABLE_FIELDS$7 = [...DEFAULT_OVERRIDEABLE_FIELDS], FILE_CORE = { name: "file", title: "File", type: null, jsonType: "object" }, DEFAULT_OPTIONS$1 = { accept: "" }, FileType = { get() { return FILE_CORE; }, extend(rawSubTypeDef, createMemberType) { const options = { ...rawSubTypeDef.options || DEFAULT_OPTIONS$1 }, fields = [ASSET_FIELD$1, MEDIA_LIBRARY_ASSET_FIELD$1, ...rawSubTypeDef.fields || []], subTypeDef = { ...rawSubTypeDef, fields }, parsed = Object.assign(pick(FILE_CORE, OVERRIDABLE_FIELDS$7), subTypeDef, { type: FILE_CORE, title: subTypeDef.title || (subTypeDef.name ? startCase(subTypeDef.name) : FILE_CORE.title), options, fields: subTypeDef.fields.map((fieldDef) => { const { name, fieldset, ...rest } = fieldDef, compiledField = { name, fieldset, isCustomized: !!rawSubTypeDef.fields }; return lazyGetter(compiledField, "type", () => createMemberType({ ...rest, title: fieldDef.title || startCase(name) })); }) }); return lazyGetter(parsed, "fieldsets", () => createFieldsets(subTypeDef, parsed.fields)), lazyGetter(parsed, "preview", createPreviewGetter(Object.assign({}, subTypeDef, { fields }))), lazyGetter( parsed, OWN_PROPS_NAME, () => ({ ...subTypeDef, options, fields: parsed.fields, title: parsed.title, fieldsets: parsed.fieldsets, preview: parsed.preview }), { enumerable: !1, writable: !1 } ), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { if (extensionDef.fields) throw new Error('Cannot override `fields` of subtypes of "file"'); const ownProps = pick(extensionDef, OVERRIDABLE_FIELDS$7), current = Object.assign({}, parent, ownProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, ownProps), subtype(current); } }; } } }, REF_FIELD$1 = { name: "_ref", title: "Referenced document ID", type: "string" }, WEAK_FIELD$1 = { name: "_weak", title: "Weak reference", type: "boolean" }, REFERENCE_FIELDS$1 = [REF_FIELD$1, WEAK_FIELD$1], OVERRIDABLE_FIELDS$6 = [...DEFAULT_OVERRIDEABLE_FIELDS], GLOBAL_DOCUMENT_REFERENCE_CORE = { name: "globalDocumentReference", title: "Global Document Reference", type: null, jsonType: "object" }; function humanize$1(arr, conjunction) { const len = arr.length; if (len === 1) return arr[0]; const first = arr.slice(0, len - 1), last = arr[len - 1]; return `${first.join(", ")} ${conjunction} ${last}`; } function buildTitle$1(type) { return !type.to || type.to.length === 0 ? "Global Document Reference" : `Global Document Reference to ${humanize$1( arrify(type.to).map((toType) => toType.title), "or" ).toLowerCase()}`; } const GlobalDocumentReferenceType = { get() { return GLOBAL_DOCUMENT_REFERENCE_CORE; }, extend(subTypeDef, createMemberType) { if (!subTypeDef.to) throw new Error( `Missing "to" field in global document reference definition. Check the type ${subTypeDef.name}` ); const parsed = Object.assign( pick(GLOBAL_DOCUMENT_REFERENCE_CORE, OVERRIDABLE_FIELDS$6), subTypeDef, { type: GLOBAL_DOCUMENT_REFERENCE_CORE } ); return lazyGetter(parsed, "fields", () => REFERENCE_FIELDS$1.map((fieldDef) => createMemberType.cachedField(fieldDef))), lazyGetter(parsed, "to", () => arrify(subTypeDef.to).map((toType) => ({ ...toType }))), lazyGetter(parsed, "title", () => subTypeDef.title || buildTitle$1(parsed)), lazyGetter( parsed, OWN_PROPS_NAME, () => ({ ...subTypeDef, fields: parsed.fields, to: parsed.to, title: parsed.title }), { enumerable: !1, writable: !1 } ), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { if (extensionDef.of) throw new Error('Cannot override `of` of subtypes of "globalDocumentReference"'); const ownProps = pick(extensionDef, OVERRIDABLE_FIELDS$6), current = Object.assign({}, parent, ownProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, ownProps), subtype(current); } }; } } }, ASSET_FIELD = { name: "asset", type: "reference", to: [{ type: "sanity.imageAsset" }] }, HOTSPOT_FIELD = { name: "hotspot", type: "sanity.imageHotspot" }, CROP_FIELD = { name: "crop", type: "sanity.imageCrop" }, MEDIA_LIBRARY_ASSET_FIELD = { name: "media", type: "globalDocumentReference", hidden: !0, to: [{ type: "sanity.asset" }] }, OVERRIDABLE_FIELDS$5 = [...DEFAULT_OVERRIDEABLE_FIELDS], IMAGE_CORE = { name: "image", title: "Image", type: null, jsonType: "object" }, DEFAULT_OPTIONS = {}, ImageType = { get() { return IMAGE_CORE; }, extend(rawSubTypeDef, createMemberType) { const options = { ...rawSubTypeDef.options || DEFAULT_OPTIONS }; let hotspotFields = [HOTSPOT_FIELD, CROP_FIELD]; options.hotspot || (hotspotFields = hotspotFields.map((field) => ({ ...field, hidden: !0 }))); const fields = [ ASSET_FIELD, MEDIA_LIBRARY_ASSET_FIELD, ...hotspotFields, ...rawSubTypeDef.fields || [] ], subTypeDef = { ...rawSubTypeDef, fields }, parsed = Object.assign(pick(this.get(), OVERRIDABLE_FIELDS$5), subTypeDef, { type: IMAGE_CORE, title: subTypeDef.title || (subTypeDef.name ? startCase(subTypeDef.name) : IMAGE_CORE.title), options, fields: subTypeDef.fields.map((fieldDef) => { const { name, fieldset, ...rest } = fieldDef, compiledField = { name, fieldset, isCustomized: !!rawSubTypeDef.fields }; return lazyGetter(compiledField, "type", () => createMemberType({ ...rest, title: fieldDef.title || startCase(name) })); }) }); return lazyGetter(parsed, "fieldsets", () => createFieldsets(subTypeDef, parsed.fields)), lazyGetter(parsed, "preview", createPreviewGetter(Object.assign({}, subTypeDef, { fields }))), lazyGetter( parsed, OWN_PROPS_NAME, () => ({ ...subTypeDef, options, fields: parsed.fields, title: parsed.title, fieldsets: parsed.fieldsets, preview: parsed.preview }), { enumerable: !1, writable: !1 } ), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { if (extensionDef.fields) throw new Error('Cannot override `fields` of subtypes of "image"'); const ownProps = pick(extensionDef, OVERRIDABLE_FIELDS$5), current = Object.assign({}, parent, ownProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, ownProps), subtype(current); } }; } } }, OVERRIDABLE_FIELDS$4 = [...DEFAULT_OVERRIDEABLE_FIELDS], NUMBER_CORE = { name: "number", title: "Number", type: null, jsonType: "number" }, NumberType = { get() { return NUMBER_CORE; }, extend(subTypeDef) { const ownProps = { ...subTypeDef, preview: primitivePreview }, parsed = Object.assign(pick(NUMBER_CORE, OVERRIDABLE_FIELDS$4), ownProps, { type: NUMBER_CORE }); return hiddenGetter(parsed, OWN_PROPS_NAME, ownProps), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { const subOwnProps = pick(extensionDef, OVERRIDABLE_FIELDS$4), current = Object.assign({}, parent, subOwnProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, subOwnProps), subtype(current); } }; } } }, REF_FIELD = { name: "_ref", title: "Referenced document ID", type: "string" }, WEAK_FIELD = { name: "_weak", title: "Weak reference", type: "boolean" }, REFERENCE_FIELDS = [REF_FIELD, WEAK_FIELD], OVERRIDABLE_FIELDS$3 = [...DEFAULT_OVERRIDEABLE_FIELDS], REFERENCE_CORE = { name: "reference", title: "Reference", type: null, jsonType: "object" }; function humanize(arr, conjunction) { const len = arr.length; if (len === 1) return arr[0]; const first = arr.slice(0, len - 1), last = arr[len - 1]; return `${first.join(", ")} ${conjunction} ${last}`; } function buildTitle(type) { return !type.to || type.to.length === 0 ? "Reference" : `Reference to ${humanize( arrify(type.to).map((toType) => toType.title), "or" ).toLowerCase()}`; } const ReferenceType = { get() { return REFERENCE_CORE; }, extend(subTypeDef, createMemberType) { if (!subTypeDef.to) throw new Error( `Missing "to" field in reference definition. Check the type ${subTypeDef.name}` ); const parsed = Object.assign(pick(REFERENCE_CORE, OVERRIDABLE_FIELDS$3), subTypeDef, { type: REFERENCE_CORE }); return lazyGetter(parsed, "fields", () => REFERENCE_FIELDS.map((fieldDef) => createMemberType.cachedField(fieldDef))), lazyGetter(parsed, "fieldsets", () => createFieldsets(subTypeDef, parsed.fields)), lazyGetter(parsed, "to", () => arrify(subTypeDef.to).map((toType) => createMemberType(toType))), lazyGetter(parsed, "title", () => subTypeDef.title || buildTitle(parsed)), lazyGetter( parsed, OWN_PROPS_NAME, () => ({ ...subTypeDef, fields: parsed.fields, fieldsets: parsed.fieldsets, to: parsed.to, title: parsed.title }), { enumerable: !1, writable: !1 } ), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { if (extensionDef.of) throw new Error('Cannot override `of` of subtypes of "reference"'); const ownProps = pick(extensionDef, OVERRIDABLE_FIELDS$3), current = Object.assign({}, parent, ownProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, ownProps), subtype(current); } }; } } }, OVERRIDABLE_FIELDS$2 = [...DEFAULT_OVERRIDEABLE_FIELDS], STRING_CORE = { name: "string", title: "String", type: null, jsonType: "string" }, StringType = { get() { return STRING_CORE; }, extend(subTypeDef) { const ownProps = { ...subTypeDef, preview: primitivePreview }, parsed = Object.assign(pick(STRING_CORE, OVERRIDABLE_FIELDS$2), ownProps, { type: STRING_CORE }); return hiddenGetter(parsed, OWN_PROPS_NAME, ownProps), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { const subOwnProps = pick(extensionDef, OVERRIDABLE_FIELDS$2), current = Object.assign({}, parent, subOwnProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, subOwnProps), subtype(current); } }; } } }, OVERRIDABLE_FIELDS$1 = [...DEFAULT_OVERRIDEABLE_FIELDS, "rows"], TEXT_CORE = { name: "text", title: "Text", type: null, jsonType: "string" }, TextType = { get() { return TEXT_CORE; }, extend(subTypeDef) { const ownProps = { ...subTypeDef, preview: primitivePreview }, parsed = Object.assign(pick(TEXT_CORE, OVERRIDABLE_FIELDS$1), ownProps, { type: TEXT_CORE }); return hiddenGetter(parsed, OWN_PROPS_NAME, ownProps), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { const subOwnProps = pick(extensionDef, OVERRIDABLE_FIELDS$1), current = Object.assign({}, parent, subOwnProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, subOwnProps), subtype(current); } }; } } }, OVERRIDABLE_FIELDS = [...DEFAULT_OVERRIDEABLE_FIELDS], URL_CORE = { name: "url", title: "Url", type: null, jsonType: "string" }, UrlType = { get() { return URL_CORE; }, extend(subTypeDef) { const ownProps = { ...subTypeDef, preview: primitivePreview }, parsed = Object.assign(pick(URL_CORE, OVERRIDABLE_FIELDS), ownProps, { type: URL_CORE }); return hiddenGetter(parsed, OWN_PROPS_NAME, ownProps), subtype(parsed); function subtype(parent) { return { get() { return parent; }, extend: (extensionDef) => { const subOwnownProps = pick(extensionDef, OVERRIDABLE_FIELDS), current = Object.assign({}, parent, subOwnownProps, { type: parent }); return hiddenGetter(current, OWN_PROPS_NAME, subOwnownProps), subtype(current); } }; } } }; var types = /* @__PURE__ */ Object.freeze({ __proto__: null, any: AnyType, array: ArrayType, block: BlockType, boolean: BooleanType, crossDatasetReference: CrossDatasetReferenceType, date: DateType, datetime: DateTimeType, document: DocumentType, email: EmailType, file: FileType, globalDocumentReference: GlobalDocumentReferenceType, image: ImageType, number: NumberType, object: ObjectType, reference: ReferenceType, span: SpanType, string: StringType, text: TextType, url: UrlType }); function compileRegistry(schemaDef) { const registry = /* @__PURE__ */ Object.create(null); let localTypeNames; schemaDef.parent ? (Object.assign(registry, schemaDef.parent._registry), localTypeNames = []) : (Object.assign(registry, types), localTypeNames = Object.keys(types)); const defsByName = schemaDef.types.reduce((acc, def) => { if (acc[def.name]) throw new Error(`Duplicate type name added to schema: ${def.name}`); return acc[def.name] = def, acc; }, {}), memberCache = /* @__PURE__ */ new Map(), fieldCache = /* @__PURE__ */ new Map(), objectFieldCache = /* @__PURE__ */ new Map(), extendHelper = Object.assign(extendMember, { cached(def) { let member = memberCache.get(def); return member || (member = extendMember(def), memberCache.set(def, member)), member; }, cachedField(fieldDef) { let field = fieldCache.get(fieldDef); if (!field) { const { name, ...type } = fieldDef; field = { name, type: extendMember(type) }, fieldCache.set(fieldDef, field); } return field; }, cachedObjectField(fieldDef) { let field = objectFieldCache.get(fieldDef); if (!field) { const { name, fieldset, group, ...rest } = fieldDef; field = { name, group, fieldset }, lazyGetter(field, "type", () => extendMember({ ...rest, title: fieldDef.title || startCase(name) })), objectFieldCache.set(fieldDef, field); } return field; } }); return schemaDef.types.forEach(add), { registry, localTypeNames }; function ensure(typeName) { if (!registry[typeName]) { if (!defsByName[typeName]) throw new Error(`Unknown type: ${typeName}`); add(defsByName[typeName]); } } function extendMember(memberDef) { return ensure(memberDef.type), registry[memberDef.type].extend(memberDef, extendHelper).get(); } function add(typeDef) { ensure(typeDef.type), !registry[typeDef.name] && (localTypeNames.push(typeDef.name), registry[typeDef.name] = registry[typeDef.type].extend(typeDef, extendMember)); } } class Schema { _original; _registry; #localTypeNames; static compile(schemaDef) { return new Schema(schemaDef);