UNPKG

sanity

Version:

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

414 lines (413 loc) • 19.5 kB
"use strict"; var node_worker_threads = require("node:worker_threads"), jsxRuntime = require("react/jsx-runtime"), DOMPurify = require("isomorphic-dompurify"), lodashEs = require("lodash-es"), server = require("react-dom/server"), sanity = require("sanity"), compilerRuntime = require("react/compiler-runtime"), ui = require("@sanity/ui"), theme$1 = require("@sanity/ui/theme"), react = require("react"), reactIs = require("react-is"), getStudioWorkspaces = require("../../../_chunks-cjs/getStudioWorkspaces.cjs"), mockBrowserEnvironment = require("../../../_chunks-cjs/mockBrowserEnvironment.cjs"); function _interopDefaultCompat(e) { return e && typeof e == "object" && "default" in e ? e : { default: e }; } var DOMPurify__default = /* @__PURE__ */ _interopDefaultCompat(DOMPurify); const theme = theme$1.buildTheme(), SchemaIcon = (t0) => { const $ = compilerRuntime.c(6), { icon, title, subtitle } = t0; let t1; $[0] !== icon || $[1] !== subtitle || $[2] !== title ? (t1 = normalizeIcon(icon, title, subtitle), $[0] = icon, $[1] = subtitle, $[2] = title, $[3] = t1) : t1 = $[3]; let t2; return $[4] !== t1 ? (t2 = /* @__PURE__ */ jsxRuntime.jsx(ui.ThemeProvider, { theme, children: t1 }), $[4] = t1, $[5] = t2) : t2 = $[5], t2; }; function normalizeIcon(Icon, title, subtitle = "") { return reactIs.isValidElementType(Icon) ? /* @__PURE__ */ jsxRuntime.jsx(Icon, {}) : react.isValidElement(Icon) ? Icon : sanity.createDefaultIcon(title, subtitle); } const DEFAULT_IMAGE_FIELDS = ["asset", "hotspot", "crop", "media"], DEFAULT_FILE_FIELDS = ["asset", "media"], DEFAULT_GEOPOINT_FIELDS = ["lat", "lng", "alt"], DEFAULT_SLUG_FIELDS = ["current", "source"]; function getCustomFields(type) { const fields = type.fieldsets ? type.fieldsets.flatMap((fs) => fs.single ? fs.field : fs.fields.map((field) => ({ ...field, fieldset: fs.name }))) : type.fields; return isType(type, "block") ? [] : isType(type, "slug") ? fields.filter((f) => !DEFAULT_SLUG_FIELDS.includes(f.name)) : isType(type, "geopoint") ? fields.filter((f) => !DEFAULT_GEOPOINT_FIELDS.includes(f.name)) : isType(type, "image") ? fields.filter((f) => !DEFAULT_IMAGE_FIELDS.includes(f.name)) : isType(type, "file") ? fields.filter((f) => !DEFAULT_FILE_FIELDS.includes(f.name)) : fields; } function isReference(type) { return isType(type, "reference"); } function isCrossDatasetReference(type) { return isType(type, "crossDatasetReference"); } function isGlobalDocumentReference(type) { return isType(type, "globalDocumentReference"); } function isObjectField(maybeOjectField) { return typeof maybeOjectField == "object" && maybeOjectField !== null && "name" in maybeOjectField; } function isCustomized(maybeCustomized) { const internalOwnProps = getSchemaTypeInternalOwnProps(maybeCustomized); 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 // we only consider it customized if the _definition_ has fields declared // this holds for all customizable object-like types: object, document, image and file internalOwnProps?.fields ? !!getCustomFields(maybeCustomized).length : !1; } function isType(schemaType, typeName) { return schemaType.name === typeName ? !0 : schemaType.type ? isType(schemaType.type, typeName) : !1; } function isDefined(value) { return value != null; } function isRecord(value) { return !!value && typeof value == "object"; } function isPrimitive(value) { return isString(value) || isBoolean(value) || isNumber(value); } function isString(value) { return typeof value == "string"; } function isNumber(value) { return typeof value == "boolean"; } function isBoolean(value) { return typeof value == "number"; } function getSchemaTypeInternalOwnProps(type) { return type?._internal_ownProps; } function getDefinedTypeName(type) { return getSchemaTypeInternalOwnProps(type)?.type; } const HTML_TAGS = ["img", "style"], SVG_TAGS = ["svg", "a", "altglyph", "altglyphdef", "altglyphitem", "animatecolor", "animatemotion", "animatetransform", "circle", "clippath", "defs", "desc", "ellipse", "filter", "font", "g", "glyph", "glyphref", "hkern", "image", "line", "lineargradient", "marker", "mask", "metadata", "mpath", "path", "pattern", "polygon", "polyline", "radialgradient", "rect", "stop", "style", "switch", "symbol", "text", "textpath", "title", "tref", "tspan", "view", "vkern"], SVG_FILTER_TAGS = ["feBlend", "feColorMatrix", "feComponentTransfer", "feComposite", "feConvolveMatrix", "feDiffuseLighting", "feDisplacementMap", "feDistantLight", "feDropShadow", "feFlood", "feFuncA", "feFuncB", "feFuncG", "feFuncR", "feGaussianBlur", "feImage", "feMerge", "feMergeNode", "feMorphology", "feOffset", "fePointLight", "feSpecularLighting", "feSpotLight", "feTile", "feTurbulence"], ALLOWED_TAGS = [...SVG_TAGS, ...HTML_TAGS, ...SVG_FILTER_TAGS], HTML_ATTRIBUTES = ["alt", "class", "crossorigin", "decoding", "elementtiming", "fetchpriority", "height", "loading", "src", "srcset", "style", "width"], SVG_ATTRIBUTES = ["accent-height", "accumulate", "additive", "alignment-baseline", "amplitude", "ascent", "attributename", "attributetype", "azimuth", "basefrequency", "baseline-shift", "begin", "bias", "by", "class", "clip", "clippathunits", "clip-path", "clip-rule", "color", "color-interpolation", "color-interpolation-filters", "color-profile", "color-rendering", "cx", "cy", "d", "dx", "dy", "diffuseconstant", "direction", "display", "divisor", "dur", "edgemode", "elevation", "end", "exponent", "fill", "fill-opacity", "fill-rule", "filter", "filterunits", "flood-color", "flood-opacity", "font-family", "font-size", "font-size-adjust", "font-stretch", "font-style", "font-variant", "font-weight", "fx", "fy", "g1", "g2", "glyph-name", "glyphref", "gradientunits", "gradienttransform", "height", "href", "id", "image-rendering", "in", "in2", "intercept", "k", "k1", "k2", "k3", "k4", "kerning", "keypoints", "keysplines", "keytimes", "lang", "lengthadjust", "letter-spacing", "kernelmatrix", "kernelunitlength", "lighting-color", "local", "marker-end", "marker-mid", "marker-start", "markerheight", "markerunits", "markerwidth", "maskcontentunits", "maskunits", "max", "mask", "media", "method", "mode", "min", "name", "numoctaves", "offset", "operator", "opacity", "order", "orient", "orientation", "origin", "overflow", "paint-order", "path", "pathlength", "patterncontentunits", "patterntransform", "patternunits", "points", "preservealpha", "preserveaspectratio", "primitiveunits", "r", "rx", "ry", "radius", "refx", "refy", "repeatcount", "repeatdur", "restart", "result", "rotate", "scale", "seed", "shape-rendering", "slope", "specularconstant", "specularexponent", "spreadmethod", "startoffset", "stddeviation", "stitchtiles", "stop-color", "stop-opacity", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke", "stroke-width", "style", "surfacescale", "systemlanguage", "tabindex", "tablevalues", "targetx", "targety", "transform", "transform-origin", "text-anchor", "text-decoration", "text-rendering", "textlength", "type", "u1", "u2", "unicode", "values", "viewbox", "visibility", "version", "vert-adv-y", "vert-origin-x", "vert-origin-y", "width", "word-spacing", "wrap", "writing-mode", "xchannelselector", "ychannelselector", "x", "x1", "x2", "xmlns", "y", "y1", "y2", "z", "zoomandpan"], ALLOWED_ATTR = [...SVG_ATTRIBUTES, ...HTML_ATTRIBUTES], config = { ALLOWED_ATTR, ALLOWED_TAGS, /** * Required to allow for the use of `style` tags, * namely rendering the style tags from `styled-components` */ FORCE_BODY: !0 }, MAX_CUSTOM_PROPERTY_DEPTH = 5; function extractCreateWorkspaceManifest(workspace) { const serializedSchema = extractManifestSchemaTypes(workspace.schema), serializedTools = extractManifestTools(workspace.tools); return { name: workspace.name, title: workspace.title, subtitle: workspace.subtitle, basePath: workspace.basePath, projectId: workspace.projectId, dataset: workspace.dataset, icon: resolveIcon({ icon: workspace.icon, title: workspace.title, subtitle: workspace.subtitle }), mediaLibrary: workspace.mediaLibrary, schema: serializedSchema, tools: serializedTools }; } function extractManifestSchemaTypes(schema) { const typeNames = schema.getTypeNames(), studioDefaultTypeNames = sanity.createSchema({ name: "default", types: [] }).getTypeNames(); return typeNames.filter((typeName) => !studioDefaultTypeNames.includes(typeName)).map((typeName) => schema.get(typeName)).filter((type) => typeof type < "u").map((type) => transformType(type)); } function transformCommonTypeFields(type, typeName, context) { 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) ? { fields: getCustomFields(type).map((objectField) => transformField(objectField)) } : {}; return { ...retainCustomTypeProps(type), ...transformValidation(type.validation), ...ensureString("description", type.description), ...objectFields, ...arrayProps, ...referenceProps, ...crossDatasetRefProps, ...globalRefProps, ...ensureConditional("readOnly", type.readOnly), ...ensureConditional("hidden", type.hidden), ...transformFieldsets(type), // fieldset prop gets instrumented via getCustomFields ...ensureString("fieldset", type.fieldset), ...transformBlockType(type) }; } function transformFieldsets(type) { if (type.jsonType !== "object") return {}; const fieldsets = type.fieldsets?.filter((fs) => !fs.single).map((fs) => { const options = isRecord(fs.options) ? { options: retainSerializableProps(fs.options) } : {}; return { name: fs.name, ...ensureCustomTitle(fs.name, fs.title), ...ensureString("description", fs.description), ...ensureConditional("readOnly", fs.readOnly), ...ensureConditional("hidden", fs.hidden), ...options }; }); return fieldsets?.length ? { fieldsets } : {}; } function transformType(type, context) { const typeName = type.type ? type.type.name : type.jsonType; return { ...transformCommonTypeFields(type, typeName), name: type.name, type: typeName, ...ensureCustomTitle(type.name, type.title) }; } function retainCustomTypeProps(type) { const manuallySerializedFields = [ //explicitly added "name", "title", "description", "readOnly", "hidden", "validation", "fieldsets", "fields", "to", "of", // not serialized "type", "jsonType", "__experimental_actions", "__experimental_formPreviewTitle", "__experimental_omnisearch_visibility", "__experimental_search", "components", "icon", "orderings", "preview", "groups", //only exists on fields "group" // we know about these, but let them be generically handled // deprecated // rows (from text) // initialValue // options // crossDatasetReference props ], typeWithoutManuallyHandledFields = Object.fromEntries(Object.entries(type).filter(([key]) => !manuallySerializedFields.includes(key))); return retainSerializableProps(typeWithoutManuallyHandledFields); } function retainSerializableProps(maybeSerializable, depth = 0) { if (!(depth > MAX_CUSTOM_PROPERTY_DEPTH) && isDefined(maybeSerializable)) { if (isPrimitive(maybeSerializable)) return maybeSerializable === "" ? void 0 : maybeSerializable; if (maybeSerializable instanceof RegExp) return maybeSerializable.toString(); if (Array.isArray(maybeSerializable)) { const arrayItems = maybeSerializable.map((item) => retainSerializableProps(item, depth + 1)).filter((item) => isDefined(item)); return arrayItems.length ? arrayItems : void 0; } if (isRecord(maybeSerializable)) { const serializableEntries = Object.entries(maybeSerializable).map(([key, value]) => [key, retainSerializableProps(value, depth + 1)]).filter(([, value]) => isDefined(value)); return serializableEntries.length ? Object.fromEntries(serializableEntries) : void 0; } } } function transformField(field, context) { const fieldType = field.type, typeName = getDefinedTypeName(fieldType) ?? fieldType.name; return { ...transformCommonTypeFields(fieldType, typeName), name: field.name, type: typeName, ...ensureCustomTitle(field.name, fieldType.title), // this prop gets added synthetically via getCustomFields ...ensureString("fieldset", field.fieldset) }; } function transformArrayMember(arrayMember, context) { return { of: arrayMember.of.map((type) => { const typeName = getDefinedTypeName(type) ?? type.name; return { ...transformCommonTypeFields(type, typeName), type: typeName, ...typeName === type.name ? {} : { name: type.name }, ...ensureCustomTitle(type.name, type.title) }; }) }; } function transformReference(reference) { return { to: (reference.to ?? []).map((type) => ({ ...retainCustomTypeProps(type), type: type.name })) }; } function transformCrossDatasetReference(reference) { return { to: (reference.to ?? []).map((crossDataset) => { const preview = crossDataset.preview?.select ? { preview: { select: crossDataset.preview.select } } : {}; return { type: crossDataset.type, ...ensureCustomTitle(crossDataset.type, crossDataset.title), ...preview }; }) }; } function transformGlobalDocumentReference(reference) { return { to: (reference.to ?? []).map((crossDataset) => { const preview = crossDataset.preview?.select ? { preview: { select: crossDataset.preview.select } } : {}; return { type: crossDataset.type, ...ensureCustomTitle(crossDataset.type, crossDataset.title), ...preview }; }) }; } const transformTypeValidationRule = (rule) => ({ ...rule, constraint: "constraint" in rule && (typeof rule.constraint == "string" ? rule.constraint.toLowerCase() : retainSerializableProps(rule.constraint)) }), validationRuleTransformers = { type: transformTypeValidationRule }; function transformValidation(validation) { const validationArray = (Array.isArray(validation) ? validation : [validation]).filter((value) => typeof value == "object" && "_type" in value), disallowedFlags = ["type"], disallowedConstraintTypes = [sanity.ConcreteRuleClass.FIELD_REF], serializedValidation = validationArray.map(({ _rules, _message, _level }) => { const message = typeof _message == "string" ? { message: _message } : {}; return { rules: _rules.filter((rule) => { if (!("constraint" in rule)) return !1; const { flag, constraint } = rule; return disallowedFlags.includes(flag) ? !1 : !(typeof constraint == "object" && "type" in constraint && disallowedConstraintTypes.includes(constraint.type)); }).reduce((rules, rule) => { const transformedRule = (validationRuleTransformers[rule.flag] ?? ((spec) => retainSerializableProps(spec)))(rule); return transformedRule ? [...rules, transformedRule] : rules; }, []), level: _level, ...message }; }).filter((group) => !!group.rules.length); return serializedValidation.length ? { validation: serializedValidation } : {}; } function ensureCustomTitle(typeName, value) { const titleObject = ensureString("title", value), defaultTitle = lodashEs.startCase(typeName); return titleObject.title === defaultTitle ? {} : titleObject; } function ensureString(key, value) { return typeof value == "string" ? { [key]: value } : {}; } function ensureConditional(key, value) { return typeof value == "boolean" ? { [key]: value } : typeof value == "function" ? { [key]: "conditional" } : {}; } function transformBlockType(blockType, context) { if (blockType.jsonType !== "object" || !isType(blockType, "block")) return {}; const childrenField = blockType.fields?.find((field) => field.name === "children"); if (!childrenField) return {}; const ofType = childrenField.type.of; if (!ofType) return {}; const spanType = ofType.find((memberType) => memberType.name === "span"); if (!spanType) return {}; const inlineObjectTypes = ofType.filter((memberType) => memberType.name !== "span") || []; return { marks: { annotations: spanType.annotations.map((t) => transformType(t)), decorators: resolveEnabledDecorators(spanType) }, lists: resolveEnabledListItems(blockType), styles: resolveEnabledStyles(blockType), of: inlineObjectTypes.map((t) => transformType(t)) }; } function resolveEnabledStyles(blockType) { const styleField = blockType.fields?.find((btField) => btField.name === "style"); return resolveTitleValueArray(styleField?.type?.options?.list); } function resolveEnabledDecorators(spanType) { return "decorators" in spanType ? resolveTitleValueArray(spanType.decorators) : void 0; } function resolveEnabledListItems(blockType) { const listField = blockType.fields?.find((btField) => btField.name === "listItem"); return resolveTitleValueArray(listField?.type?.options?.list); } function resolveTitleValueArray(possibleArray) { if (!possibleArray || !Array.isArray(possibleArray)) return; const titledValues = possibleArray.filter((d) => isRecord(d) && !!d.value && isString(d.value)).map((item) => ({ value: item.value, ...ensureString("title", item.title) })); if (titledValues?.length) return titledValues; } const extractManifestTools = (tools) => tools.map((tool) => { const { title, name, icon, __internalApplicationType: type } = tool; return { title, name, type: type || null, icon: resolveIcon({ icon, title }) }; }), resolveIcon = (props) => { try { const html = server.renderToString(/* @__PURE__ */ jsxRuntime.jsx(SchemaIcon, { ...props })); return DOMPurify__default.default.sanitize(html.trim(), config); } catch { return null; } }; async function main() { if (node_worker_threads.isMainThread || !node_worker_threads.parentPort) throw new Error("This module must be run as a worker thread"); const opts = node_worker_threads.workerData, cleanup = mockBrowserEnvironment.mockBrowserEnvironment(opts.workDir); try { const workspaces = await getStudioWorkspaces.getStudioWorkspaces({ basePath: opts.workDir }); for (const workspace of workspaces) node_worker_threads.parentPort?.postMessage(extractCreateWorkspaceManifest(workspace)); } finally { node_worker_threads.parentPort?.close(), cleanup(); } } main().then(() => process.exit()); //# sourceMappingURL=extractManifest.cjs.map