99 lines
2.9 KiB
JavaScript
99 lines
2.9 KiB
JavaScript
/* global __DEV__ */
|
|
|
|
import {defer, from as observableFrom, of as observableOf, throwError} from 'rxjs'
|
|
import {mergeMap} from 'rxjs/operators'
|
|
|
|
// eslint-disable-next-line import/no-commonjs
|
|
const {StructureBuilder} = require('@sanity/structure')
|
|
|
|
let prevStructureError = null
|
|
if (__DEV__) {
|
|
if (module.hot && module.hot.data) {
|
|
prevStructureError = module.hot.data.prevError
|
|
}
|
|
}
|
|
|
|
export function isSubscribable (thing) {
|
|
return thing && (typeof thing.then === 'function' || typeof thing.subscribe === 'function')
|
|
}
|
|
|
|
export function isStructure (structure) {
|
|
return (
|
|
structure &&
|
|
(typeof structure === 'function' ||
|
|
typeof structure.serialize !== 'function' ||
|
|
typeof structure.then !== 'function' ||
|
|
typeof structure.subscribe !== 'function' ||
|
|
typeof structure.type !== 'string')
|
|
)
|
|
}
|
|
|
|
export function serializeStructure (item, context, resolverArgs = []) {
|
|
// Lazy
|
|
if (typeof item === 'function') {
|
|
return serializeStructure(item(...resolverArgs), context, resolverArgs)
|
|
}
|
|
|
|
// Promise/observable returning a function, builder or plain JSON structure
|
|
if (isSubscribable(item)) {
|
|
return observableFrom(item).pipe(
|
|
mergeMap(val => serializeStructure(val, context, resolverArgs))
|
|
)
|
|
}
|
|
|
|
// Builder?
|
|
if (item && typeof item.serialize === 'function') {
|
|
return serializeStructure(item.serialize(context))
|
|
}
|
|
|
|
// Plain value?
|
|
return observableOf(item)
|
|
}
|
|
|
|
export function getDefaultStructure () {
|
|
const items = StructureBuilder.documentTypeListItems()
|
|
return StructureBuilder.list()
|
|
.id('__root__')
|
|
.title('Content')
|
|
.showIcons(items.some(item => item.getSchemaType().icon))
|
|
.items(items)
|
|
}
|
|
|
|
// We are lazy-requiring/resolving the structure inside of a function in order to catch errors
|
|
// on the root-level of the module. Any loading errors will be caught and emitted as errors
|
|
// eslint-disable-next-line complexity
|
|
export function loadStructure () {
|
|
let structure
|
|
try {
|
|
const mod = require('part:@sanity/desk-tool/structure?') || getDefaultStructure()
|
|
structure = mod && mod.__esModule ? mod.default : mod
|
|
|
|
// On invalid modules, when HMR kicks in, we sometimes get an empty object back when the
|
|
// source has changed without fixing the problem. In this case, keep showing the error
|
|
if (
|
|
__DEV__ &&
|
|
prevStructureError &&
|
|
structure &&
|
|
structure.constructor.name === 'Object' &&
|
|
Object.keys(structure).length === 0
|
|
) {
|
|
return throwError(prevStructureError)
|
|
}
|
|
|
|
prevStructureError = null
|
|
} catch (err) {
|
|
prevStructureError = err
|
|
return throwError(err)
|
|
}
|
|
|
|
if (!isStructure(structure)) {
|
|
return throwError(
|
|
new Error(
|
|
`Structure needs to export a function, an observable, a promise or a stucture builder, got ${typeof structure}`
|
|
)
|
|
)
|
|
}
|
|
|
|
// Defer to catch immediately thrown errors on serialization
|
|
return defer(() => serializeStructure(structure))
|
|
}
|