@sanity/schema 5.14.0-next.9 → 5.14.1-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/_internal.d.ts +177 -6
- package/lib/_internal.js +415 -0
- package/lib/_internal.js.map +1 -1
- package/package.json +6 -6
package/lib/_internal.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { a as SchemaValidationResult, i as ProblemPathTypeSegment, l as Schema$1, n as ProblemPathPropertySegment, o as TypeWithProblems, r as ProblemPathSegment, s as _FIXME_, t as ProblemPath } from "./_chunks-dts/typedefs.js";
|
|
2
2
|
import { SetSynchronization, SynchronizationRequest, SynchronizationResult } from "@sanity/descriptors";
|
|
3
3
|
import * as _sanity_types0 from "@sanity/types";
|
|
4
|
-
import { Schema, SchemaType, SchemaTypeDefinition, SchemaValidationProblem, SchemaValidationProblemGroup } from "@sanity/types";
|
|
4
|
+
import { SanityDocumentLike, Schema, SchemaType, SchemaTypeDefinition, SchemaValidationProblem, SchemaValidationProblemGroup } from "@sanity/types";
|
|
5
|
+
import { ComponentType, ReactNode } from "react";
|
|
5
6
|
import { SchemaType as SchemaType$1 } from "groq-js";
|
|
6
7
|
/** The scheduler is capable of executing work in different ways. */
|
|
7
8
|
type Scheduler = {
|
|
@@ -44,6 +45,180 @@ declare function resolveSearchConfigForBaseFieldPaths(type: any, maxDepth?: numb
|
|
|
44
45
|
*/
|
|
45
46
|
declare function resolveSearchConfig(type: any, maxDepth?: number): any;
|
|
46
47
|
declare const ALL_FIELDS_GROUP_NAME = "all-fields";
|
|
48
|
+
declare function createSchemaFromManifestTypes(schemaDef: {
|
|
49
|
+
name: string;
|
|
50
|
+
types: unknown[];
|
|
51
|
+
}): Schema$1;
|
|
52
|
+
interface MediaLibraryConfig {
|
|
53
|
+
enabled?: boolean;
|
|
54
|
+
libraryId?: string;
|
|
55
|
+
__internal?: {
|
|
56
|
+
frontendHost?: string;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
declare const SANITY_WORKSPACE_SCHEMA_ID_PREFIX = "_.schemas";
|
|
60
|
+
declare const SANITY_WORKSPACE_SCHEMA_TYPE = "system.schema";
|
|
61
|
+
declare const CURRENT_WORKSPACE_SCHEMA_VERSION = "2025-05-01";
|
|
62
|
+
type ManifestSerializable = string | number | boolean | {
|
|
63
|
+
[k: string]: ManifestSerializable;
|
|
64
|
+
} | ManifestSerializable[];
|
|
65
|
+
interface CreateManifest {
|
|
66
|
+
version: number;
|
|
67
|
+
createdAt: string;
|
|
68
|
+
workspaces: ManifestWorkspaceFile[];
|
|
69
|
+
studioVersion: string | null;
|
|
70
|
+
}
|
|
71
|
+
interface ManifestWorkspaceFile extends Omit<CreateWorkspaceManifest, 'schema' | 'tools'> {
|
|
72
|
+
schema: string;
|
|
73
|
+
tools: string;
|
|
74
|
+
}
|
|
75
|
+
interface CreateWorkspaceManifest {
|
|
76
|
+
name: string;
|
|
77
|
+
title?: string;
|
|
78
|
+
subtitle?: string;
|
|
79
|
+
basePath: string;
|
|
80
|
+
dataset: string;
|
|
81
|
+
projectId: string;
|
|
82
|
+
mediaLibrary?: MediaLibraryConfig;
|
|
83
|
+
schema: ManifestSchemaType[];
|
|
84
|
+
tools: ManifestTool[];
|
|
85
|
+
/**
|
|
86
|
+
* returns undefined in the case of the icon not being able to be stringified
|
|
87
|
+
*/
|
|
88
|
+
icon: string | undefined;
|
|
89
|
+
}
|
|
90
|
+
interface ManifestSchemaType {
|
|
91
|
+
type: string;
|
|
92
|
+
name: string;
|
|
93
|
+
title?: string;
|
|
94
|
+
deprecated?: {
|
|
95
|
+
reason: string;
|
|
96
|
+
};
|
|
97
|
+
readOnly?: boolean | 'conditional';
|
|
98
|
+
hidden?: boolean | 'conditional';
|
|
99
|
+
validation?: ManifestValidationGroup[];
|
|
100
|
+
fields?: ManifestField[];
|
|
101
|
+
to?: ManifestReferenceMember[];
|
|
102
|
+
of?: ManifestArrayMember[];
|
|
103
|
+
preview?: {
|
|
104
|
+
select: Record<string, string>;
|
|
105
|
+
};
|
|
106
|
+
fieldsets?: ManifestFieldset[];
|
|
107
|
+
options?: Record<string, ManifestSerializable>;
|
|
108
|
+
marks?: {
|
|
109
|
+
annotations?: ManifestArrayMember[];
|
|
110
|
+
decorators?: ManifestTitledValue[];
|
|
111
|
+
};
|
|
112
|
+
lists?: ManifestTitledValue[];
|
|
113
|
+
styles?: ManifestTitledValue[];
|
|
114
|
+
}
|
|
115
|
+
interface ManifestFieldset {
|
|
116
|
+
name: string;
|
|
117
|
+
title?: string;
|
|
118
|
+
[index: string]: ManifestSerializable | undefined;
|
|
119
|
+
}
|
|
120
|
+
interface ManifestTitledValue {
|
|
121
|
+
value: string;
|
|
122
|
+
title?: string;
|
|
123
|
+
}
|
|
124
|
+
type ManifestField = ManifestSchemaType & {
|
|
125
|
+
fieldset?: string;
|
|
126
|
+
};
|
|
127
|
+
type ManifestArrayMember = Omit<ManifestSchemaType, 'name'> & {
|
|
128
|
+
name?: string;
|
|
129
|
+
};
|
|
130
|
+
type ManifestReferenceMember = Omit<ManifestSchemaType, 'name'> & {
|
|
131
|
+
name?: string;
|
|
132
|
+
};
|
|
133
|
+
interface ManifestValidationGroup {
|
|
134
|
+
rules: ManifestValidationRule[];
|
|
135
|
+
message?: string;
|
|
136
|
+
level?: 'error' | 'warning' | 'info';
|
|
137
|
+
}
|
|
138
|
+
type ManifestValidationRule = {
|
|
139
|
+
flag: string;
|
|
140
|
+
constraint?: ManifestSerializable;
|
|
141
|
+
[index: string]: ManifestSerializable | undefined;
|
|
142
|
+
};
|
|
143
|
+
interface ManifestTool {
|
|
144
|
+
name: string;
|
|
145
|
+
title: string;
|
|
146
|
+
/**
|
|
147
|
+
* returns undefined in the case of the icon not being able to be stringified
|
|
148
|
+
*/
|
|
149
|
+
icon: string | undefined;
|
|
150
|
+
type: string | null;
|
|
151
|
+
}
|
|
152
|
+
type DefaultWorkspaceSchemaId = `${typeof SANITY_WORKSPACE_SCHEMA_ID_PREFIX}.${string}`;
|
|
153
|
+
type PrefixedWorkspaceSchemaId = `${DefaultWorkspaceSchemaId}.${string}`;
|
|
154
|
+
type WorkspaceSchemaId = DefaultWorkspaceSchemaId | PrefixedWorkspaceSchemaId;
|
|
155
|
+
interface StoredWorkspaceSchema extends SanityDocumentLike {
|
|
156
|
+
_type: typeof SANITY_WORKSPACE_SCHEMA_TYPE;
|
|
157
|
+
_id: WorkspaceSchemaId;
|
|
158
|
+
version: typeof CURRENT_WORKSPACE_SCHEMA_VERSION | undefined;
|
|
159
|
+
tag?: string;
|
|
160
|
+
workspace: {
|
|
161
|
+
name: string;
|
|
162
|
+
title?: string;
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* The API expects JSON coming in, but will store a string to save on attribute paths.
|
|
166
|
+
* Consumers must use JSON.parse on the value, put we deploy to the API using ManifestSchemaType[]
|
|
167
|
+
*/
|
|
168
|
+
schema: string | ManifestSchemaType[];
|
|
169
|
+
}
|
|
170
|
+
interface ManifestWorkspaceInput {
|
|
171
|
+
name: string;
|
|
172
|
+
title?: string;
|
|
173
|
+
subtitle?: string;
|
|
174
|
+
basePath: string;
|
|
175
|
+
projectId: string;
|
|
176
|
+
dataset: string;
|
|
177
|
+
icon?: ComponentType | ReactNode;
|
|
178
|
+
mediaLibrary?: MediaLibraryConfig;
|
|
179
|
+
schema: Schema;
|
|
180
|
+
tools: ManifestToolInput[];
|
|
181
|
+
}
|
|
182
|
+
interface ManifestToolInput {
|
|
183
|
+
title: string;
|
|
184
|
+
name: string;
|
|
185
|
+
icon?: ComponentType | ReactNode;
|
|
186
|
+
__internalApplicationType?: string;
|
|
187
|
+
}
|
|
188
|
+
type IconResolver = (props: {
|
|
189
|
+
icon?: ComponentType | ReactNode;
|
|
190
|
+
title: string;
|
|
191
|
+
subtitle?: string;
|
|
192
|
+
}) => string | undefined | Promise<string | undefined>;
|
|
193
|
+
declare function extractCreateWorkspaceManifest(workspace: ManifestWorkspaceInput, iconResolver?: IconResolver): Promise<CreateWorkspaceManifest>;
|
|
194
|
+
/**
|
|
195
|
+
* Extracts all serializable properties from userland schema types,
|
|
196
|
+
* so they best-effort can be used as definitions for Schema.compile
|
|
197
|
+
. */
|
|
198
|
+
declare function extractManifestSchemaTypes(schema: Schema): ManifestSchemaType[];
|
|
199
|
+
declare const validForNamesChars = "a-zA-Z0-9_-";
|
|
200
|
+
declare const validForNamesPattern: RegExp;
|
|
201
|
+
declare function getWorkspaceSchemaId(args: {
|
|
202
|
+
workspaceName: string;
|
|
203
|
+
tag?: string;
|
|
204
|
+
}): {
|
|
205
|
+
safeBaseId: DefaultWorkspaceSchemaId;
|
|
206
|
+
safeTaggedId: WorkspaceSchemaId;
|
|
207
|
+
idWarning: string | undefined;
|
|
208
|
+
};
|
|
209
|
+
interface ParsedWorkspaceSchemaId {
|
|
210
|
+
schemaId: string;
|
|
211
|
+
workspace: string;
|
|
212
|
+
}
|
|
213
|
+
declare function parseWorkspaceSchemaId(id: string, errors: string[]): ParsedWorkspaceSchemaId | undefined;
|
|
214
|
+
declare function createStoredWorkspaceSchemaPayload(args: {
|
|
215
|
+
workspace: {
|
|
216
|
+
name: string;
|
|
217
|
+
title?: string;
|
|
218
|
+
};
|
|
219
|
+
schema: ManifestSchemaType[];
|
|
220
|
+
tag?: string;
|
|
221
|
+
}): Omit<StoredWorkspaceSchema, '_id' | '_type'>;
|
|
47
222
|
declare const builtinTypes: ({
|
|
48
223
|
name: string;
|
|
49
224
|
title: string;
|
|
@@ -240,10 +415,6 @@ declare const builtinTypes: ({
|
|
|
240
415
|
readOnly: boolean;
|
|
241
416
|
})[];
|
|
242
417
|
})[];
|
|
243
|
-
declare function createSchemaFromManifestTypes(schemaDef: {
|
|
244
|
-
name: string;
|
|
245
|
-
types: unknown[];
|
|
246
|
-
}): Schema$1;
|
|
247
418
|
interface ExtractSchemaOptions {
|
|
248
419
|
enforceRequiredFields?: boolean;
|
|
249
420
|
}
|
|
@@ -311,4 +482,4 @@ declare class ValidationError extends Error {
|
|
|
311
482
|
problems: SchemaValidationProblemGroup[];
|
|
312
483
|
constructor(problems: SchemaValidationProblemGroup[]);
|
|
313
484
|
}
|
|
314
|
-
export { ALL_FIELDS_GROUP_NAME, DEFAULT_MAX_FIELD_DEPTH, DescriptorConverter, type _FIXME_ as FIXME, type SchemaValidationResult as Problem, type SchemaValidationResult as ValidationResult, type ProblemPath, type ProblemPathPropertySegment, type ProblemPathSegment, type ProblemPathTypeSegment, SchemaSynchronizationRequest, SchemaSynchronizationResult, type TypeWithProblems, ValidationError, builtinTypes, createSchemaFromManifestTypes, extractSchema, groupProblems, isActionEnabled, processSchemaSynchronization, resolveSearchConfig, resolveSearchConfigForBaseFieldPaths, validateMediaLibraryAssetAspect, validateSchema };
|
|
485
|
+
export { ALL_FIELDS_GROUP_NAME, type CreateManifest, type CreateWorkspaceManifest, DEFAULT_MAX_FIELD_DEPTH, type DefaultWorkspaceSchemaId, DescriptorConverter, type _FIXME_ as FIXME, type IconResolver, type ManifestSchemaType, type ManifestWorkspaceFile, type ParsedWorkspaceSchemaId, type SchemaValidationResult as Problem, type SchemaValidationResult as ValidationResult, type ProblemPath, type ProblemPathPropertySegment, type ProblemPathSegment, type ProblemPathTypeSegment, SchemaSynchronizationRequest, SchemaSynchronizationResult, type StoredWorkspaceSchema, type TypeWithProblems, ValidationError, type WorkspaceSchemaId, builtinTypes, createSchemaFromManifestTypes, createStoredWorkspaceSchemaPayload, extractCreateWorkspaceManifest, extractManifestSchemaTypes, extractSchema, getWorkspaceSchemaId, groupProblems, isActionEnabled, parseWorkspaceSchemaId, processSchemaSynchronization, resolveSearchConfig, resolveSearchConfigForBaseFieldPaths, validForNamesChars, validForNamesPattern, validateMediaLibraryAssetAspect, validateSchema };
|
package/lib/_internal.js
CHANGED
|
@@ -14,6 +14,7 @@ import isPlainObject from "lodash-es/isPlainObject.js";
|
|
|
14
14
|
import omit from "lodash-es/omit.js";
|
|
15
15
|
import leven from "leven";
|
|
16
16
|
import inspect from "object-inspect";
|
|
17
|
+
import startCase from "lodash-es/startCase.js";
|
|
17
18
|
import { createReferenceTypeNode } from "groq-js";
|
|
18
19
|
const MAX_IDLE_WORK = 8.333333333333334;
|
|
19
20
|
class IdleScheduler {
|
|
@@ -1821,6 +1822,14 @@ function validateField(field, visitorContext) {
|
|
|
1821
1822
|
`The type "${field.type}" is a document type and should not be used as a field type directly. Use a "reference" if you want to create a link to the document, or use "object" if you want to embed fields inline.`,
|
|
1822
1823
|
HELP_IDS.FIELD_TYPE_IS_DOCUMENT
|
|
1823
1824
|
)
|
|
1825
|
+
), field.title && typeof field.title != "string" && problems.push(
|
|
1826
|
+
warning(
|
|
1827
|
+
`Field "${field.name}" has a non-string title. This is known to cause problems and will not be supported in future versions. Please use a string instead.`
|
|
1828
|
+
)
|
|
1829
|
+
), field.description && typeof field.description != "string" && problems.push(
|
|
1830
|
+
warning(
|
|
1831
|
+
`Field "${field.name}" has a non-string description. This is known to cause problems and will not be supported in future versions. Please use a string instead.`
|
|
1832
|
+
)
|
|
1824
1833
|
), problems;
|
|
1825
1834
|
}
|
|
1826
1835
|
function getDuplicateFields(array2) {
|
|
@@ -2350,6 +2359,405 @@ function stringToRegExp(str) {
|
|
|
2350
2359
|
const match = str.match(/^\/(.*)\/([gimuy]*)$/);
|
|
2351
2360
|
return match ? new RegExp(match[1], match[2]) : new RegExp(str);
|
|
2352
2361
|
}
|
|
2362
|
+
const DEFAULT_IMAGE_FIELDS = ["asset", "hotspot", "crop", "media"], DEFAULT_FILE_FIELDS = ["asset", "media"], DEFAULT_GEOPOINT_FIELDS = ["lat", "lng", "alt"], DEFAULT_SLUG_FIELDS = ["current", "source"];
|
|
2363
|
+
function getCustomFields(type) {
|
|
2364
|
+
const fields = type.fieldsets ? type.fieldsets.flatMap((fs) => fs.single ? fs.field : fs.fields.map((field) => ({
|
|
2365
|
+
...field,
|
|
2366
|
+
fieldset: fs.name
|
|
2367
|
+
}))) : type.fields;
|
|
2368
|
+
return isType$1(type, "block") ? [] : isType$1(type, "slug") ? fields.filter((f) => !DEFAULT_SLUG_FIELDS.includes(f.name)) : isType$1(type, "geopoint") ? fields.filter((f) => !DEFAULT_GEOPOINT_FIELDS.includes(f.name)) : isType$1(type, "image") ? fields.filter((f) => !DEFAULT_IMAGE_FIELDS.includes(f.name)) : isType$1(type, "file") ? fields.filter((f) => !DEFAULT_FILE_FIELDS.includes(f.name)) : fields;
|
|
2369
|
+
}
|
|
2370
|
+
function isReference(type) {
|
|
2371
|
+
return isType$1(type, "reference");
|
|
2372
|
+
}
|
|
2373
|
+
function isCrossDatasetReference(type) {
|
|
2374
|
+
return isType$1(type, "crossDatasetReference");
|
|
2375
|
+
}
|
|
2376
|
+
function isGlobalDocumentReference(type) {
|
|
2377
|
+
return isType$1(type, "globalDocumentReference");
|
|
2378
|
+
}
|
|
2379
|
+
function isObjectField(maybeOjectField) {
|
|
2380
|
+
return typeof maybeOjectField == "object" && maybeOjectField !== null && "name" in maybeOjectField;
|
|
2381
|
+
}
|
|
2382
|
+
function isCustomized(maybeCustomized) {
|
|
2383
|
+
const internalOwnProps = getSchemaTypeInternalOwnProps(maybeCustomized);
|
|
2384
|
+
return isObjectField(maybeCustomized) && !isReference(maybeCustomized) && !isCrossDatasetReference(maybeCustomized) && !isGlobalDocumentReference(maybeCustomized) && "fields" in maybeCustomized && Array.isArray(maybeCustomized.fields) && // needed to differentiate inline, named array object types from globally defined types
|
|
2385
|
+
// we only consider it customized if the _definition_ has fields declared
|
|
2386
|
+
// this holds for all customizable object-like types: object, document, image and file
|
|
2387
|
+
internalOwnProps?.fields ? !!getCustomFields(maybeCustomized).length : !1;
|
|
2388
|
+
}
|
|
2389
|
+
function isType$1(schemaType, typeName) {
|
|
2390
|
+
return schemaType.name === typeName ? !0 : schemaType.type ? isType$1(schemaType.type, typeName) : !1;
|
|
2391
|
+
}
|
|
2392
|
+
function isDefined(value) {
|
|
2393
|
+
return value != null;
|
|
2394
|
+
}
|
|
2395
|
+
function isRecord(value) {
|
|
2396
|
+
return !!value && typeof value == "object";
|
|
2397
|
+
}
|
|
2398
|
+
function isPrimitive(value) {
|
|
2399
|
+
return isString(value) || isBoolean(value) || isNumber(value);
|
|
2400
|
+
}
|
|
2401
|
+
function isString(value) {
|
|
2402
|
+
return typeof value == "string";
|
|
2403
|
+
}
|
|
2404
|
+
function isNumber(value) {
|
|
2405
|
+
return typeof value == "number";
|
|
2406
|
+
}
|
|
2407
|
+
function isBoolean(value) {
|
|
2408
|
+
return typeof value == "boolean";
|
|
2409
|
+
}
|
|
2410
|
+
function getSchemaTypeInternalOwnProps(type) {
|
|
2411
|
+
return type?._internal_ownProps;
|
|
2412
|
+
}
|
|
2413
|
+
function getDefinedTypeName(type) {
|
|
2414
|
+
return getSchemaTypeInternalOwnProps(type)?.type;
|
|
2415
|
+
}
|
|
2416
|
+
const MAX_CUSTOM_PROPERTY_DEPTH = 5, noopIconResolver = () => {
|
|
2417
|
+
};
|
|
2418
|
+
async function extractCreateWorkspaceManifest(workspace, iconResolver = noopIconResolver) {
|
|
2419
|
+
const serializedSchema = extractManifestSchemaTypes(workspace.schema), serializedTools = await extractManifestTools(workspace.tools, iconResolver);
|
|
2420
|
+
return {
|
|
2421
|
+
name: workspace.name,
|
|
2422
|
+
title: workspace.title,
|
|
2423
|
+
subtitle: workspace.subtitle,
|
|
2424
|
+
basePath: workspace.basePath,
|
|
2425
|
+
projectId: workspace.projectId,
|
|
2426
|
+
dataset: workspace.dataset,
|
|
2427
|
+
icon: await iconResolver({
|
|
2428
|
+
icon: workspace.icon,
|
|
2429
|
+
title: workspace.title ?? workspace.name,
|
|
2430
|
+
subtitle: workspace.subtitle
|
|
2431
|
+
}),
|
|
2432
|
+
mediaLibrary: workspace.mediaLibrary,
|
|
2433
|
+
schema: serializedSchema,
|
|
2434
|
+
tools: serializedTools
|
|
2435
|
+
};
|
|
2436
|
+
}
|
|
2437
|
+
function extractManifestSchemaTypes(schema) {
|
|
2438
|
+
const typeNames = schema.getTypeNames(), studioDefaultTypeNames = Schema.compile({
|
|
2439
|
+
name: "default",
|
|
2440
|
+
types: builtinTypes
|
|
2441
|
+
}).getTypeNames();
|
|
2442
|
+
return typeNames.filter((typeName) => !studioDefaultTypeNames.includes(typeName)).map((typeName) => schema.get(typeName)).filter((type) => typeof type < "u").map((type) => transformType(type));
|
|
2443
|
+
}
|
|
2444
|
+
function transformCommonTypeFields(type, typeName, context) {
|
|
2445
|
+
const arrayProps = typeName === "array" && type.jsonType === "array" ? transformArrayMember(type) : {}, referenceProps = isReference(type) ? transformReference(type) : {}, crossDatasetRefProps = isCrossDatasetReference(type) ? transformCrossDatasetReference(type) : {}, globalRefProps = isGlobalDocumentReference(type) ? transformGlobalDocumentReference(type) : {}, objectFields = type.jsonType === "object" && type.type && isCustomized(type) ? {
|
|
2446
|
+
fields: getCustomFields(type).map((objectField) => transformField(objectField))
|
|
2447
|
+
} : {};
|
|
2448
|
+
return {
|
|
2449
|
+
...retainCustomTypeProps(type),
|
|
2450
|
+
...transformValidation(type.validation),
|
|
2451
|
+
...ensureString("description", type.description),
|
|
2452
|
+
...objectFields,
|
|
2453
|
+
...arrayProps,
|
|
2454
|
+
...referenceProps,
|
|
2455
|
+
...crossDatasetRefProps,
|
|
2456
|
+
...globalRefProps,
|
|
2457
|
+
...ensureConditional("readOnly", type.readOnly),
|
|
2458
|
+
...ensureConditional("hidden", type.hidden),
|
|
2459
|
+
...transformFieldsets(type),
|
|
2460
|
+
// fieldset prop gets instrumented via getCustomFields
|
|
2461
|
+
...ensureString("fieldset", type.fieldset),
|
|
2462
|
+
...transformBlockType(type)
|
|
2463
|
+
};
|
|
2464
|
+
}
|
|
2465
|
+
function transformFieldsets(type) {
|
|
2466
|
+
if (type.jsonType !== "object")
|
|
2467
|
+
return {};
|
|
2468
|
+
const fieldsets = type.fieldsets?.filter((fs) => !fs.single).map((fs) => {
|
|
2469
|
+
const options = isRecord(fs.options) ? { options: retainSerializableProps(fs.options) } : {};
|
|
2470
|
+
return {
|
|
2471
|
+
name: fs.name,
|
|
2472
|
+
...ensureCustomTitle(fs.name, fs.title),
|
|
2473
|
+
...ensureString("description", fs.description),
|
|
2474
|
+
...ensureConditional("readOnly", fs.readOnly),
|
|
2475
|
+
...ensureConditional("hidden", fs.hidden),
|
|
2476
|
+
...options
|
|
2477
|
+
};
|
|
2478
|
+
});
|
|
2479
|
+
return fieldsets?.length ? { fieldsets } : {};
|
|
2480
|
+
}
|
|
2481
|
+
function transformType(type, context) {
|
|
2482
|
+
const typeName = type.type ? type.type.name : type.jsonType;
|
|
2483
|
+
return {
|
|
2484
|
+
...transformCommonTypeFields(type, typeName),
|
|
2485
|
+
name: type.name,
|
|
2486
|
+
type: typeName,
|
|
2487
|
+
...ensureCustomTitle(type.name, type.title)
|
|
2488
|
+
};
|
|
2489
|
+
}
|
|
2490
|
+
function retainCustomTypeProps(type) {
|
|
2491
|
+
const manuallySerializedFields = [
|
|
2492
|
+
//explicitly added
|
|
2493
|
+
"name",
|
|
2494
|
+
"title",
|
|
2495
|
+
"description",
|
|
2496
|
+
"readOnly",
|
|
2497
|
+
"hidden",
|
|
2498
|
+
"validation",
|
|
2499
|
+
"fieldsets",
|
|
2500
|
+
"fields",
|
|
2501
|
+
"to",
|
|
2502
|
+
"of",
|
|
2503
|
+
// not serialized
|
|
2504
|
+
"type",
|
|
2505
|
+
"jsonType",
|
|
2506
|
+
"__experimental_actions",
|
|
2507
|
+
"__experimental_formPreviewTitle",
|
|
2508
|
+
"__experimental_omnisearch_visibility",
|
|
2509
|
+
"__experimental_search",
|
|
2510
|
+
"components",
|
|
2511
|
+
"icon",
|
|
2512
|
+
"orderings",
|
|
2513
|
+
"preview",
|
|
2514
|
+
"groups",
|
|
2515
|
+
//only exists on fields
|
|
2516
|
+
"group"
|
|
2517
|
+
// we know about these, but let them be generically handled
|
|
2518
|
+
// deprecated
|
|
2519
|
+
// rows (from text)
|
|
2520
|
+
// initialValue
|
|
2521
|
+
// options
|
|
2522
|
+
// crossDatasetReference props
|
|
2523
|
+
], typeWithoutManuallyHandledFields = Object.fromEntries(
|
|
2524
|
+
Object.entries(type).filter(
|
|
2525
|
+
([key]) => !manuallySerializedFields.includes(key)
|
|
2526
|
+
)
|
|
2527
|
+
);
|
|
2528
|
+
return retainSerializableProps(typeWithoutManuallyHandledFields);
|
|
2529
|
+
}
|
|
2530
|
+
function retainSerializableProps(maybeSerializable, depth = 0) {
|
|
2531
|
+
if (!(depth > MAX_CUSTOM_PROPERTY_DEPTH) && isDefined(maybeSerializable)) {
|
|
2532
|
+
if (isPrimitive(maybeSerializable))
|
|
2533
|
+
return maybeSerializable === "" ? void 0 : maybeSerializable;
|
|
2534
|
+
if (maybeSerializable instanceof RegExp)
|
|
2535
|
+
return maybeSerializable.toString();
|
|
2536
|
+
if (Array.isArray(maybeSerializable)) {
|
|
2537
|
+
const arrayItems = maybeSerializable.map((item) => retainSerializableProps(item, depth + 1)).filter((item) => isDefined(item));
|
|
2538
|
+
return arrayItems.length ? arrayItems : void 0;
|
|
2539
|
+
}
|
|
2540
|
+
if (isRecord(maybeSerializable)) {
|
|
2541
|
+
const serializableEntries = Object.entries(maybeSerializable).map(([key, value]) => [key, retainSerializableProps(value, depth + 1)]).filter(([, value]) => isDefined(value));
|
|
2542
|
+
return serializableEntries.length ? Object.fromEntries(serializableEntries) : void 0;
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
function transformField(field, context) {
|
|
2547
|
+
const fieldType = field.type, typeName = getDefinedTypeName(fieldType) ?? fieldType.name;
|
|
2548
|
+
return {
|
|
2549
|
+
...transformCommonTypeFields(fieldType, typeName),
|
|
2550
|
+
name: field.name,
|
|
2551
|
+
type: typeName,
|
|
2552
|
+
...ensureCustomTitle(field.name, fieldType.title),
|
|
2553
|
+
// this prop gets added synthetically via getCustomFields
|
|
2554
|
+
...ensureString("fieldset", field.fieldset)
|
|
2555
|
+
};
|
|
2556
|
+
}
|
|
2557
|
+
function transformArrayMember(arrayMember, context) {
|
|
2558
|
+
return {
|
|
2559
|
+
of: arrayMember.of.map((type) => {
|
|
2560
|
+
const typeName = getDefinedTypeName(type) ?? type.name;
|
|
2561
|
+
return {
|
|
2562
|
+
...transformCommonTypeFields(type, typeName),
|
|
2563
|
+
type: typeName,
|
|
2564
|
+
...typeName === type.name ? {} : { name: type.name },
|
|
2565
|
+
...ensureCustomTitle(type.name, type.title)
|
|
2566
|
+
};
|
|
2567
|
+
})
|
|
2568
|
+
};
|
|
2569
|
+
}
|
|
2570
|
+
function transformReference(reference2) {
|
|
2571
|
+
return {
|
|
2572
|
+
to: (reference2.to ?? []).map((type) => ({
|
|
2573
|
+
...retainCustomTypeProps(type),
|
|
2574
|
+
type: type.name
|
|
2575
|
+
}))
|
|
2576
|
+
};
|
|
2577
|
+
}
|
|
2578
|
+
function transformCrossDatasetReference(reference2) {
|
|
2579
|
+
return {
|
|
2580
|
+
to: (reference2.to ?? []).map((crossDataset) => {
|
|
2581
|
+
const preview = crossDataset.preview?.select ? { preview: { select: crossDataset.preview.select } } : {};
|
|
2582
|
+
return {
|
|
2583
|
+
type: crossDataset.type,
|
|
2584
|
+
...ensureCustomTitle(crossDataset.type, crossDataset.title),
|
|
2585
|
+
...preview
|
|
2586
|
+
};
|
|
2587
|
+
})
|
|
2588
|
+
};
|
|
2589
|
+
}
|
|
2590
|
+
function transformGlobalDocumentReference(reference2) {
|
|
2591
|
+
return {
|
|
2592
|
+
to: (reference2.to ?? []).map((crossDataset) => {
|
|
2593
|
+
const preview = crossDataset.preview?.select ? { preview: { select: crossDataset.preview.select } } : {};
|
|
2594
|
+
return {
|
|
2595
|
+
type: crossDataset.type,
|
|
2596
|
+
...ensureCustomTitle(crossDataset.type, crossDataset.title),
|
|
2597
|
+
...preview
|
|
2598
|
+
};
|
|
2599
|
+
})
|
|
2600
|
+
};
|
|
2601
|
+
}
|
|
2602
|
+
const transformTypeValidationRule = (rule) => ({
|
|
2603
|
+
...rule,
|
|
2604
|
+
constraint: "constraint" in rule && (typeof rule.constraint == "string" ? rule.constraint.toLowerCase() : retainSerializableProps(rule.constraint))
|
|
2605
|
+
}), validationRuleTransformers = {
|
|
2606
|
+
type: transformTypeValidationRule
|
|
2607
|
+
};
|
|
2608
|
+
function transformValidation(validation) {
|
|
2609
|
+
const validationArray = (Array.isArray(validation) ? validation : [validation]).filter(
|
|
2610
|
+
(value) => typeof value == "object" && "_type" in value
|
|
2611
|
+
), disallowedFlags = ["type"], disallowedConstraintTypes = [Rule.FIELD_REF], serializedValidation = validationArray.map(({ _rules, _message, _level }) => {
|
|
2612
|
+
const message = typeof _message == "string" ? { message: _message } : {};
|
|
2613
|
+
return {
|
|
2614
|
+
rules: _rules.filter((rule) => {
|
|
2615
|
+
if (!("constraint" in rule))
|
|
2616
|
+
return !1;
|
|
2617
|
+
const { flag, constraint } = rule;
|
|
2618
|
+
return disallowedFlags.includes(flag) ? !1 : !(typeof constraint == "object" && "type" in constraint && disallowedConstraintTypes.includes(constraint.type));
|
|
2619
|
+
}).reduce((rules, rule) => {
|
|
2620
|
+
const transformedRule = (validationRuleTransformers[rule.flag] ?? ((spec) => retainSerializableProps(spec)))(rule);
|
|
2621
|
+
return transformedRule ? [...rules, transformedRule] : rules;
|
|
2622
|
+
}, []),
|
|
2623
|
+
level: _level,
|
|
2624
|
+
...message
|
|
2625
|
+
};
|
|
2626
|
+
}).filter((group) => !!group.rules.length);
|
|
2627
|
+
return serializedValidation.length ? { validation: serializedValidation } : {};
|
|
2628
|
+
}
|
|
2629
|
+
function ensureCustomTitle(typeName, value) {
|
|
2630
|
+
const titleObject = ensureString("title", value), defaultTitle = startCase(typeName);
|
|
2631
|
+
return titleObject.title === defaultTitle ? {} : titleObject;
|
|
2632
|
+
}
|
|
2633
|
+
function ensureString(key, value) {
|
|
2634
|
+
return typeof value == "string" ? {
|
|
2635
|
+
[key]: value
|
|
2636
|
+
} : {};
|
|
2637
|
+
}
|
|
2638
|
+
function ensureConditional(key, value) {
|
|
2639
|
+
return typeof value == "boolean" ? {
|
|
2640
|
+
[key]: value
|
|
2641
|
+
} : typeof value == "function" ? {
|
|
2642
|
+
[key]: "conditional"
|
|
2643
|
+
} : {};
|
|
2644
|
+
}
|
|
2645
|
+
function transformBlockType(blockType, context) {
|
|
2646
|
+
if (blockType.jsonType !== "object" || !isType$1(blockType, "block"))
|
|
2647
|
+
return {};
|
|
2648
|
+
const childrenField = blockType.fields?.find((field) => field.name === "children");
|
|
2649
|
+
if (!childrenField)
|
|
2650
|
+
return {};
|
|
2651
|
+
const ofType = childrenField.type.of;
|
|
2652
|
+
if (!ofType)
|
|
2653
|
+
return {};
|
|
2654
|
+
const spanType = ofType.find((memberType) => memberType.name === "span");
|
|
2655
|
+
if (!spanType)
|
|
2656
|
+
return {};
|
|
2657
|
+
const inlineObjectTypes = ofType.filter((memberType) => memberType.name !== "span") || [];
|
|
2658
|
+
return {
|
|
2659
|
+
marks: {
|
|
2660
|
+
annotations: spanType.annotations.map((t) => transformType(t)),
|
|
2661
|
+
decorators: resolveEnabledDecorators(spanType)
|
|
2662
|
+
},
|
|
2663
|
+
lists: resolveEnabledListItems(blockType),
|
|
2664
|
+
styles: resolveEnabledStyles(blockType),
|
|
2665
|
+
of: inlineObjectTypes.map((t) => transformType(t))
|
|
2666
|
+
};
|
|
2667
|
+
}
|
|
2668
|
+
function resolveEnabledStyles(blockType) {
|
|
2669
|
+
const styleField = blockType.fields?.find((btField) => btField.name === "style");
|
|
2670
|
+
return resolveTitleValueArray(styleField?.type?.options?.list);
|
|
2671
|
+
}
|
|
2672
|
+
function resolveEnabledDecorators(spanType) {
|
|
2673
|
+
return "decorators" in spanType ? resolveTitleValueArray(spanType.decorators) : void 0;
|
|
2674
|
+
}
|
|
2675
|
+
function resolveEnabledListItems(blockType) {
|
|
2676
|
+
const listField = blockType.fields?.find((btField) => btField.name === "listItem");
|
|
2677
|
+
return resolveTitleValueArray(listField?.type?.options?.list);
|
|
2678
|
+
}
|
|
2679
|
+
function resolveTitleValueArray(possibleArray) {
|
|
2680
|
+
if (!possibleArray || !Array.isArray(possibleArray))
|
|
2681
|
+
return;
|
|
2682
|
+
const titledValues = possibleArray.filter(
|
|
2683
|
+
(d) => isRecord(d) && !!d.value && isString(d.value)
|
|
2684
|
+
).map((item) => ({
|
|
2685
|
+
value: item.value,
|
|
2686
|
+
...ensureString("title", item.title)
|
|
2687
|
+
}));
|
|
2688
|
+
if (titledValues?.length)
|
|
2689
|
+
return titledValues;
|
|
2690
|
+
}
|
|
2691
|
+
const extractManifestTools = async (tools, iconResolver = noopIconResolver) => Promise.all(
|
|
2692
|
+
tools.map(async (tool) => {
|
|
2693
|
+
const { title, name, icon, __internalApplicationType: type } = tool;
|
|
2694
|
+
return {
|
|
2695
|
+
title,
|
|
2696
|
+
name,
|
|
2697
|
+
type: type || null,
|
|
2698
|
+
icon: await iconResolver({
|
|
2699
|
+
icon,
|
|
2700
|
+
title
|
|
2701
|
+
})
|
|
2702
|
+
};
|
|
2703
|
+
})
|
|
2704
|
+
), SANITY_WORKSPACE_SCHEMA_ID_PREFIX = "_.schemas", CURRENT_WORKSPACE_SCHEMA_VERSION = "2025-05-01", validForNamesChars = "a-zA-Z0-9_-", validForNamesPattern = new RegExp(`^[${validForNamesChars}]+$`, "g"), validForIdChars = "a-zA-Z0-9._-", validForIdPattern = new RegExp(`^[${validForIdChars}]+$`, "g"), requiredInId = SANITY_WORKSPACE_SCHEMA_ID_PREFIX.replace(/[.]/g, "\\."), idPatternString = `^${requiredInId}\\.([${validForNamesChars}]+)`, baseIdPattern = new RegExp(`${idPatternString}$`), taggedIdPattern = new RegExp(`${idPatternString}\\.tag\\.([${validForNamesChars}]+)$`);
|
|
2705
|
+
function getWorkspaceSchemaId(args) {
|
|
2706
|
+
const { workspaceName: rawWorkspaceName, tag } = args;
|
|
2707
|
+
let workspaceName = rawWorkspaceName, idWarning;
|
|
2708
|
+
workspaceName.match(validForNamesPattern) || (workspaceName = workspaceName.replace(new RegExp(`[^${validForNamesChars}]`, "g"), "_"), idWarning = [
|
|
2709
|
+
`Workspace "${rawWorkspaceName}" contains characters unsupported by schema _id [${validForNamesChars}], they will be replaced with _.`,
|
|
2710
|
+
"This could lead duplicate schema ids: consider renaming your workspace."
|
|
2711
|
+
].join(`
|
|
2712
|
+
`));
|
|
2713
|
+
const safeBaseId = `${SANITY_WORKSPACE_SCHEMA_ID_PREFIX}.${workspaceName}`;
|
|
2714
|
+
return {
|
|
2715
|
+
safeBaseId,
|
|
2716
|
+
safeTaggedId: `${safeBaseId}${tag ? `.tag.${tag}` : ""}`,
|
|
2717
|
+
idWarning
|
|
2718
|
+
};
|
|
2719
|
+
}
|
|
2720
|
+
function parseWorkspaceSchemaId(id, errors) {
|
|
2721
|
+
const trimmedId = id.trim();
|
|
2722
|
+
if (!trimmedId.match(validForIdPattern)) {
|
|
2723
|
+
errors.push(`id can only contain characters in [${validForIdChars}] but found: "${trimmedId}"`);
|
|
2724
|
+
return;
|
|
2725
|
+
}
|
|
2726
|
+
if (trimmedId.startsWith("-")) {
|
|
2727
|
+
errors.push(`id cannot start with - (dash) but found: "${trimmedId}"`);
|
|
2728
|
+
return;
|
|
2729
|
+
}
|
|
2730
|
+
if (trimmedId.match(/\.\./g)) {
|
|
2731
|
+
errors.push(`id cannot have consecutive . (period) characters, but found: "${trimmedId}"`);
|
|
2732
|
+
return;
|
|
2733
|
+
}
|
|
2734
|
+
const [, workspace] = trimmedId.match(taggedIdPattern) ?? trimmedId.match(baseIdPattern) ?? [];
|
|
2735
|
+
if (!workspace) {
|
|
2736
|
+
errors.push(
|
|
2737
|
+
[
|
|
2738
|
+
`id must either match ${SANITY_WORKSPACE_SCHEMA_ID_PREFIX}.<workspaceName> `,
|
|
2739
|
+
`or ${SANITY_WORKSPACE_SCHEMA_ID_PREFIX}.<workspaceName>.tag.<tag> but found: "${trimmedId}". `,
|
|
2740
|
+
`Note that workspace name characters not in [${validForNamesChars}] has to be replaced with _ for schema id.`
|
|
2741
|
+
].join("")
|
|
2742
|
+
);
|
|
2743
|
+
return;
|
|
2744
|
+
}
|
|
2745
|
+
return {
|
|
2746
|
+
schemaId: trimmedId,
|
|
2747
|
+
workspace
|
|
2748
|
+
};
|
|
2749
|
+
}
|
|
2750
|
+
function createStoredWorkspaceSchemaPayload(args) {
|
|
2751
|
+
return {
|
|
2752
|
+
version: CURRENT_WORKSPACE_SCHEMA_VERSION,
|
|
2753
|
+
tag: args.tag,
|
|
2754
|
+
workspace: {
|
|
2755
|
+
name: args.workspace.name,
|
|
2756
|
+
title: args.workspace.title
|
|
2757
|
+
},
|
|
2758
|
+
schema: args.schema
|
|
2759
|
+
};
|
|
2760
|
+
}
|
|
2353
2761
|
const documentDefaultFields = (typeName) => ({
|
|
2354
2762
|
_id: {
|
|
2355
2763
|
type: "objectAttribute",
|
|
@@ -2950,12 +3358,19 @@ export {
|
|
|
2950
3358
|
ValidationError,
|
|
2951
3359
|
builtinTypes,
|
|
2952
3360
|
createSchemaFromManifestTypes,
|
|
3361
|
+
createStoredWorkspaceSchemaPayload,
|
|
3362
|
+
extractCreateWorkspaceManifest,
|
|
3363
|
+
extractManifestSchemaTypes,
|
|
2953
3364
|
extractSchema,
|
|
3365
|
+
getWorkspaceSchemaId,
|
|
2954
3366
|
groupProblems,
|
|
2955
3367
|
isActionEnabled,
|
|
3368
|
+
parseWorkspaceSchemaId,
|
|
2956
3369
|
processSchemaSynchronization,
|
|
2957
3370
|
resolveSearchConfig,
|
|
2958
3371
|
resolveSearchConfigForBaseFieldPaths,
|
|
3372
|
+
validForNamesChars,
|
|
3373
|
+
validForNamesPattern,
|
|
2959
3374
|
validateMediaLibraryAssetAspect,
|
|
2960
3375
|
validateSchema
|
|
2961
3376
|
};
|