UNPKG

@sanity/import

Version:

Import documents to a Sanity dataset

105 lines (104 loc) 4.36 kB
import { generateHelpUrl } from '@sanity/generate-help-url'; import debug from 'debug'; import pMap from 'p-map'; import { getAssetUrlStatus } from './util/urlExists.js'; const logger = debug('sanity:import:asset-validation'); const DEFAULT_VERIFY_CONCURRENCY = 12; const REQUIRED_PROPERTIES = { _id: 'string', _type: 'string', assetId: 'string', extension: 'string', mimeType: 'string', path: 'string', sha1hash: 'string', size: 'number', url: 'string' }; export async function validateAssetDocuments(docs, options) { const { targetDataset, targetProjectId } = options; const concurrency = options.assetVerificationConcurrency || DEFAULT_VERIFY_CONCURRENCY; const assetDocs = docs.filter((doc)=>/^sanity\.[a-zA-Z]+Asset$/.test(doc._type || '')); if (assetDocs.length === 0) { return; } options.onProgress({ step: 'Validating asset documents' }); for (const doc of assetDocs)validateAssetDocumentProperties(doc); // Don't allow assets that reference different datasets (unless explicitly allowing it) if (!options.allowAssetsInDifferentDataset) { for (const doc of assetDocs){ const id = doc._id || doc.url; const { dataset, projectId } = getLocationFromDocument(doc); const resolveText = `See ${generateHelpUrl('import-asset-has-different-target')}`; if (projectId !== targetProjectId) { throw new Error(`Asset ${id} references a different project ID than the specified target (asset is in ${projectId}, importing to ${targetProjectId}). ${resolveText}`); } if (dataset !== targetDataset) { throw new Error(`Asset ${id} references a different dataset than the specified target (asset is in ${dataset}, importing to ${targetDataset}). ${resolveText}`); } } } if (!options.allowFailingAssets) { await pMap(assetDocs, ensureAssetUrlExists, { concurrency }); } } function getLocationFromDocument(doc) { const url = doc.path || doc.url || ''; const path = url.replace(/^https:\/\/cdn\.sanity\.[a-z]+\//, ''); const [, projectId, dataset] = path.split('/'); return { dataset: dataset || '', projectId: projectId || '' }; } async function ensureAssetUrlExists(assetDoc) { const url = assetDoc.url; const start = Date.now(); const status = await getAssetUrlStatus(url); logger(`${url}: %d (%d ms)`, status, Date.now() - start); if (status === 200) { return true; } if (status !== 404) { throw new Error(`Document ${assetDoc._id} points to a URL that could not be verified (${url}): ` + `server returned HTTP ${status}. ` + `Re-run with --allow-failing-assets to skip URL verification.`); } const helpUrl = generateHelpUrl('import-asset-file-does-not-exist'); throw new Error(`Document ${assetDoc._id} points to a URL that does not exist (${url}). See ${helpUrl}.`); } function validateAssetDocumentProperties(assetDoc) { for (const prop of Object.keys(REQUIRED_PROPERTIES)){ const expectedType = REQUIRED_PROPERTIES[prop]; const propValue = assetDoc[prop]; if (typeof propValue !== expectedType) { const errorType = propValue === undefined ? 'is missing' : 'has invalid type for'; throw new Error(`Asset document ${assetDoc._id} ${errorType} required property "${prop}"`); } } if (assetDoc._type === 'sanity.imageAsset') { validateImageMetadata(assetDoc); } } function validateImageMetadata(assetDoc) { if (!assetDoc.metadata) { throw new Error(`Asset document ${assetDoc._id} is missing required property "metadata"`); } if (!assetDoc.metadata.dimensions) { throw new Error(`Asset document ${assetDoc._id} is missing required property "metadata.dimensions"`); } const dimensionProps = [ 'width', 'height', 'aspectRatio' ]; const metadata = assetDoc.metadata; for (const prop of dimensionProps){ if (typeof metadata.dimensions?.[prop] !== 'number') { throw new TypeError(`Asset document ${assetDoc._id} is missing required property "metadata.dimensions.${prop}"`); } } } //# sourceMappingURL=validateAssetDocuments.js.map