@sanity/schema 5.14.0-next.9 → 5.14.0
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 +191 -20
- package/lib/_internal.js +415 -0
- package/lib/_internal.js.map +1 -1
- package/package.json +6 -6
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
|
};
|