UNPKG

@sanity/import

Version:

Import documents to a Sanity dataset

91 lines (75 loc) 2.47 kB
import {Transform, type TransformCallback} from 'node:stream' import {StringDecoder} from 'node:string_decoder' import {validateDocument} from '../documentHasErrors.js' import {type SanityDocument} from '../types.js' import { ReplacementCharError, validateLineForReplacementChar, } from './validateReplacementCharacters.js' interface JsonStreamerOptions { allowReplacementCharacters?: boolean | undefined } export function getJsonStreamer(options: JsonStreamerOptions = {}): NodeJS.ReadWriteStream { let lineNumber = 0 let remainder = '' const decoder = new StringDecoder('utf8') const {allowReplacementCharacters} = options return new Transform({ objectMode: true, transform(chunk: Buffer, _encoding: string, callback: TransformCallback) { const text = remainder + decoder.write(chunk) const lines = text.split('\n') // Last element may be an incomplete line - save for next chunk remainder = lines.pop() ?? '' for (const line of lines) { parseLine(this, line) } callback() }, flush(callback: TransformCallback) { // Flush any remaining bytes from the decoder remainder += decoder.end() if (remainder) { parseLine(this, remainder) remainder = '' } callback() }, }) function parseLine(stream: Transform, row: string) { lineNumber++ if (!row) { return } try { if (allowReplacementCharacters !== true) { const replacementError = validateLineForReplacementChar(row, lineNumber) if (replacementError) { throw new ReplacementCharError(replacementError) } } const doc = JSON.parse(row) as SanityDocument const error = validateDocument(doc) if (error) { throw new Error(error) } stream.push(doc) } catch (err) { if (err instanceof ReplacementCharError) { stream.emit('error', err) } else if (err instanceof Error) { stream.emit('error', new Error(getErrorMessage(err))) } else { stream.emit( 'error', new Error(`Unknown error occurred at line #${lineNumber}: ${String(err)}`), ) } } } function getErrorMessage(err: Error): string { const suffix = lineNumber === 1 ? '\n\nMake sure this is valid ndjson (one JSON-document *per line*)' : '' return `Failed to parse line #${lineNumber}: ${err.message}${suffix}` } }