myshenin / aws-lambda-multipart-parser

Parser of multipart/form-data requests for AWS Lambda
MIT License
74 stars 38 forks source link

TypeScript #30

Open webjay opened 1 year ago

webjay commented 1 year ago

If anyone needs it as TypeScript:

// myshenin/aws-lambda-multipart-parser#30

import { APIGatewayProxyEvent } from 'aws-lambda'

type Fields = {
  [field: string]:
    | {
        type: string
        filename: string
        contentType: string
        content: unknown
      }
    | string
}

function getValueIgnoringKeyCase(
  object: APIGatewayProxyEvent['headers'],
  key: string
) {
  const foundKey = Object.keys(object).find(
    (currentKey) => currentKey.toLocaleLowerCase() === key.toLowerCase()
  )

  return foundKey && object[foundKey]
}

function getBoundary(event: APIGatewayProxyEvent) {
  return getValueIgnoringKeyCase(event.headers, 'Content-Type')?.split('=')[1]
}

function itemMatch(item: string, re: RegExp) {
  const match = item.match(re)

  if (match === null) {
    throw new Error(`${item} not found`)
  }

  return match[0]
}

export function parseEvent(event: APIGatewayProxyEvent): Fields {
  const boundary = getBoundary(event)
  if (!boundary) {
    throw new Error('boundary not found')
  }
  const fields = event.body?.split(boundary)
  if (!fields) {
    return {}
  }

  return fields.reduce((result, item) => {
    if (/filename=".+"/g.test(item)) {
      const key = itemMatch(item, /name=".+";/g).slice(6, -2)
      // @ts-ignore
      result[key] = {
        type: 'file',
        filename: itemMatch(item, /filename=".+"/g).slice(10, -1),
        contentType: itemMatch(item, /Content-Type:\s.+/g).slice(14),
        content: item.slice(
          item.search(/Content-Type:\s.+/g) +
            itemMatch(item, /Content-Type:\s.+/g).length +
            4,
          -4
        ),
      }
    } else if (/name=".+"/g.test(item)) {
      const key = itemMatch(item, /name=".+"/g).slice(6, -1)
      // @ts-ignore
      result[key] = item.slice(
        item.search(/name=".+"/g) + itemMatch(item, /name=".+"/g).length + 4,
        -4
      )
    }

    return result
  }, {})
}