UNPKG

gatsby-source-sanity

Version:

Gatsby source plugin for building websites using Sanity.io as a backend.

237 lines 10.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const path = require("path"); const oneline = require("oneline"); const split = require("split2"); const through = require("through2"); const fs_extra_1 = require("fs-extra"); const lodash_1 = require("lodash"); const operators_1 = require("rxjs/operators"); const graphql_1 = require("gatsby/graphql"); const SanityClient = require("@sanity/client"); const pump_1 = require("./util/pump"); const rejectOnApiError_1 = require("./util/rejectOnApiError"); const normalize_1 = require("./util/normalize"); const getDocumentStream_1 = require("./util/getDocumentStream"); const cache_1 = require("./util/cache"); const removeSystemDocuments_1 = require("./util/removeSystemDocuments"); const handleDrafts_1 = require("./util/handleDrafts"); const handleListenerEvent_1 = require("./util/handleListenerEvent"); const remoteGraphQLSchema_1 = require("./util/remoteGraphQLSchema"); const debug_1 = require("./debug"); const extendImageNode_1 = require("./images/extendImageNode"); const resolveReferences_1 = require("./util/resolveReferences"); const rewriteGraphQLSchema_1 = require("./util/rewriteGraphQLSchema"); const getGraphQLResolverMap_1 = require("./util/getGraphQLResolverMap"); const documentIds_1 = require("./util/documentIds"); const defaultConfig = { version: '1', overlayDrafts: false, graphqlApi: 'default', }; const stateCache = {}; exports.onPreBootstrap = async (context, pluginConfig) => { const config = Object.assign(Object.assign({}, defaultConfig), pluginConfig); const { reporter, actions } = context; if (!actions.createTypes) { reporter.panic(oneline ` You are using a version of Gatsby not supported by gatsby-source-sanity. Either upgrade gatsby to >= 2.2.0 or downgrade to gatsby-source-sanity@^1.0.0 `); return; } validateConfig(config, reporter); try { reporter.info('[sanity] Fetching remote GraphQL schema'); const client = getClient(config); const api = await remoteGraphQLSchema_1.getRemoteGraphQLSchema(client, config); reporter.info('[sanity] Transforming to Gatsby-compatible GraphQL SDL'); const graphqlSdl = await rewriteGraphQLSchema_1.rewriteGraphQLSchema(api, { config, reporter }); const graphqlSdlKey = cache_1.getCacheKey(pluginConfig, cache_1.CACHE_KEYS.GRAPHQL_SDL); stateCache[graphqlSdlKey] = graphqlSdl; reporter.info('[sanity] Stitching GraphQL schemas from SDL'); const typeMap = remoteGraphQLSchema_1.getTypeMapFromGraphQLSchema(api); const typeMapKey = cache_1.getCacheKey(pluginConfig, cache_1.CACHE_KEYS.TYPE_MAP); stateCache[typeMapKey] = typeMap; } catch (err) { if (err.isWarning) { err.message.split('\n').forEach((line) => reporter.warn(line)); } else { reporter.panic(err.stack); } } }; exports.createResolvers = (actions, pluginConfig) => { const typeMapKey = cache_1.getCacheKey(pluginConfig, cache_1.CACHE_KEYS.TYPE_MAP); const typeMap = (stateCache[typeMapKey] || remoteGraphQLSchema_1.defaultTypeMap); actions.createResolvers(getGraphQLResolverMap_1.getGraphQLResolverMap(typeMap)); }; exports.sourceNodes = async (context, pluginConfig) => { const config = Object.assign(Object.assign({}, defaultConfig), pluginConfig); const { dataset, overlayDrafts, watchMode } = config; const { actions, getNode, createNodeId, createContentDigest, reporter } = context; const { createNode, createTypes, createParentChildLink } = actions; const graphqlSdlKey = cache_1.getCacheKey(pluginConfig, cache_1.CACHE_KEYS.GRAPHQL_SDL); const graphqlSdl = stateCache[graphqlSdlKey]; createTypes(graphqlSdl); const typeMapKey = cache_1.getCacheKey(pluginConfig, cache_1.CACHE_KEYS.TYPE_MAP); const typeMap = (stateCache[typeMapKey] || remoteGraphQLSchema_1.defaultTypeMap); const client = getClient(config); const url = client.getUrl(`/data/export/${dataset}`); reporter.info('[sanity] Fetching export stream for dataset'); const inputStream = await getDocumentStream_1.getDocumentStream(url, config.token); const processingOptions = { typeMap, createNodeId, createNode, createContentDigest, createParentChildLink, overlayDrafts, }; const draftDocs = []; const publishedNodes = new Map(); await pump_1.pump([ inputStream, split(JSON.parse), rejectOnApiError_1.rejectOnApiError(), overlayDrafts ? handleDrafts_1.extractDrafts(draftDocs) : handleDrafts_1.removeDrafts(), removeSystemDocuments_1.removeSystemDocuments(), through.obj((doc, enc, cb) => { const type = normalize_1.getTypeName(doc._type); if (!typeMap.objects[type]) { reporter.warn(`[sanity] Document "${doc._id}" has type ${doc._type} (${type}), which is not declared in the GraphQL schema. Make sure you run "graphql deploy". Skipping document.`); cb(); return; } const node = normalize_1.processDocument(doc, processingOptions); debug_1.default('Got document with ID %s (mapped to %s)', doc._id, node.id); cb(); }), ]); if (draftDocs.length > 0) { reporter.info('[sanity] Overlaying drafts'); draftDocs.forEach(draft => { normalize_1.processDocument(draft, processingOptions); const published = getNode(draft.id); if (published) { publishedNodes.set(documentIds_1.unprefixId(draft._id), published); } }); } if (watchMode) { reporter.info('[sanity] Watch mode enabled, starting a listener'); client .listen('*') .pipe(operators_1.filter(event => overlayDrafts || !event.documentId.startsWith('drafts.')), operators_1.filter(event => !event.documentId.startsWith('_.'))) .subscribe(event => handleListenerEvent_1.handleListenerEvent(event, publishedNodes, context, processingOptions)); } reporter.info('[sanity] Done exporting!'); }; exports.onPreExtractQueries = async (context, pluginConfig) => { const { getNodes, store } = context; const typeMapKey = cache_1.getCacheKey(pluginConfig, cache_1.CACHE_KEYS.TYPE_MAP); const typeMap = (stateCache[typeMapKey] || remoteGraphQLSchema_1.defaultTypeMap); let shouldAddFragments = typeof typeMap.objects.SanityImageAsset !== 'undefined'; if (!shouldAddFragments) { shouldAddFragments = getNodes().some(node => Boolean(node.internal && node.internal.type === 'SanityImageAsset')); } if (shouldAddFragments) { const program = store.getState().program; await fs_extra_1.copy(path.join(__dirname, '..', 'fragments', 'imageFragments.js'), `${program.directory}/.cache/fragments/sanity-image-fragments.js`); } }; const resolveReferencesConfig = new graphql_1.GraphQLInputObjectType({ name: 'SanityResolveReferencesConfiguration', fields: { maxDepth: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLInt), description: 'Max depth to resolve references to', }, }, }); exports.setFieldsOnGraphQLNodeType = async (context, pluginConfig) => { const { type } = context; const typeMapKey = cache_1.getCacheKey(pluginConfig, cache_1.CACHE_KEYS.TYPE_MAP); const typeMap = (stateCache[typeMapKey] || remoteGraphQLSchema_1.defaultTypeMap); const schemaType = typeMap.objects[type.name]; let fields = {}; if (type.name === 'SanityImageAsset') { fields = Object.assign(Object.assign({}, fields), extendImageNode_1.extendImageNode(context, pluginConfig)); } if (!schemaType) { debug_1.default('[%s] Not in type map', type.name); return fields; } return Object.keys(schemaType.fields).reduce((acc, fieldName) => { const field = schemaType.fields[fieldName]; const aliasFor = field.aliasFor; if (field.namedType.name.value === 'JSON' && aliasFor) { const aliasName = '_' + lodash_1.camelCase(`raw ${field.aliasFor}`); acc[aliasName] = { type: graphql_1.GraphQLJSON, args: { resolveReferences: { type: resolveReferencesConfig }, }, resolve: (obj, args) => { const raw = `_${lodash_1.camelCase(`raw_data_${field.aliasFor || fieldName}`)}`; const value = obj[raw] || obj[fieldName] || obj[aliasFor]; return args.resolveReferences ? resolveReferences_1.resolveReferences(value, context, { maxDepth: args.resolveReferences.maxDepth, overlayDrafts: pluginConfig.overlayDrafts, }) : value; }, }; return acc; } if (typeMap.scalars.includes(field.namedType.name.value)) { return acc; } const aliasName = '_' + lodash_1.camelCase(`raw ${fieldName}`); acc[aliasName] = { type: graphql_1.GraphQLJSON, args: { resolveReferences: { type: resolveReferencesConfig }, }, resolve: (obj, args) => { const raw = `_${lodash_1.camelCase(`raw_data_${field.aliasFor || fieldName}`)}`; const value = obj[raw] || obj[aliasName] || obj[fieldName]; return args.resolveReferences ? resolveReferences_1.resolveReferences(value, context, { maxDepth: args.resolveReferences.maxDepth, overlayDrafts: pluginConfig.overlayDrafts, }) : value; }, }; return acc; }, fields); }; function validateConfig(config, reporter) { if (!config.projectId) { throw new Error('[sanity] `projectId` must be specified'); } if (!config.dataset) { throw new Error('[sanity] `dataset` must be specified'); } if (config.overlayDrafts && !config.token) { reporter.warn('[sanity] `overlayDrafts` is set to `true`, but no token is given'); } const inDevelopMode = process.env.gatsby_executing_command === 'develop'; if (config.watchMode && !inDevelopMode) { reporter.warn('[sanity] Using `watchMode` when not in develop mode might prevent your build from completing'); } } function getClient(config) { const { projectId, dataset, token } = config; return new SanityClient({ projectId, dataset, token, useCdn: false, }); } //# sourceMappingURL=gatsby-node.js.map