gatsby-source-sanity
Version:
Gatsby source plugin for building websites using Sanity.io as a backend.
237 lines • 10.9 kB
JavaScript
;
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