{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["// eslint-disable-next-line no-control-regex\nconst ENCODE_URL_ATTR_CHAR_REGEXP = /[\\x00-\\x20\"'()*,/:;<=>?@[\\\\\\]{}\\x7f]/g\n\nconst HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/\nconst HEX_ESCAPE_REPLACE_REGEXP = /%([0-9A-Fa-f]{2})/g\n\nconst NON_LATIN1_REGEXP = /[^\\x20-\\x7e\\xa0-\\xff]/g\n\n// eslint-disable-next-line no-control-regex\nconst QESC_REGEXP = /\\\\([\\u0000-\\u007f])/g\n\nconst QUOTE_REGEXP = /([\\\\\"])/g\n\nconst PARAM_REGEXP =\n /;[\\x09\\x20]*([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\\x09\\x20]*=[\\x09\\x20]*(\"(?:[\\x20!\\x23-\\x5b\\x5d-\\x7e\\x80-\\xff]|\\\\[\\x20-\\x7e])*\"|[!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\\x09\\x20]*/g // eslint-disable-line no-control-regex\nconst TEXT_REGEXP = /^[\\x20-\\x7e\\x80-\\xff]+$/\nconst TOKEN_REGEXP = /^[!#$%&'*+.0-9A-Z^_`a-z|~-]+$/\n\nconst EXT_VALUE_REGEXP =\n /^([A-Za-z0-9!#$%&+\\-^_`{}~]+)'(?:[A-Za-z]{2,3}(?:-[A-Za-z]{3}){0,3}|[A-Za-z]{4,8}|)'((?:%[0-9A-Fa-f]{2}|[A-Za-z0-9!#$&+.^_`|~-])+)$/\n\n// eslint-disable-next-line no-control-regex\nconst DISPOSITION_TYPE_REGEXP = /^([!#$%&'*+.0-9A-Z^_`a-z|~-]+)[\\x09\\x20]*(?:$|;)/\n\nconst getlatin1 = (val: unknown) => {\n // simple Unicode -> ISO-8859-1 transformation\n return String(val).replace(NON_LATIN1_REGEXP, '?')\n}\n\nexport class ContentDisposition {\n type: string\n parameters: Record\n constructor(type: string, parameters: Record) {\n this.type = type\n this.parameters = parameters\n }\n}\n\nconst qstring = (val: unknown) => '\"' + String(val).replace(QUOTE_REGEXP, '\\\\$1') + '\"'\n\nconst pencode = (char: string) => '%' + String(char).charCodeAt(0).toString(16).toUpperCase()\n\nfunction ustring(val: unknown): string {\n const str = String(val)\n\n // percent encode as UTF-8\n const encoded = encodeURIComponent(str).replace(ENCODE_URL_ATTR_CHAR_REGEXP, pencode)\n\n return \"UTF-8''\" + encoded\n}\n\nconst basename = (str: string) => str.slice(str.lastIndexOf('/') + 1)\n\nfunction format({\n parameters,\n type\n}: Partial<{\n parameters: Record\n type: string | boolean | undefined\n}>) {\n if (!type || typeof type !== 'string' || !TOKEN_REGEXP.test(type)) {\n throw new TypeError('invalid type')\n }\n\n // start with normalized type\n let string = String(type).toLowerCase()\n\n // append parameters\n if (parameters && typeof parameters === 'object') {\n const params = Object.keys(parameters).sort()\n\n for (const param of params) {\n const val = param.slice(-1) === '*' ? ustring(parameters[param]) : qstring(parameters[param])\n\n string += '; ' + param + '=' + val\n }\n }\n\n return string\n}\n\nfunction createParams(filename?: string, fallback?: string | boolean) {\n if (filename === undefined) return\n\n const params: Partial<\n Record & {\n filename: string\n }\n > = {}\n\n // fallback defaults to true\n if (fallback === undefined) fallback = true\n\n if (typeof fallback === 'string' && NON_LATIN1_REGEXP.test(fallback)) {\n throw new TypeError('fallback must be ISO-8859-1 string')\n }\n\n // restrict to file base name\n const name = basename(filename)\n\n // determine if name is suitable for quoted string\n const isQuotedString = TEXT_REGEXP.test(name)\n\n // generate fallback name\n const fallbackName = typeof fallback !== 'string' ? fallback && getlatin1(name) : basename(fallback)\n const hasFallback = typeof fallbackName === 'string' && fallbackName !== name\n\n // set extended filename parameter\n if (hasFallback || !isQuotedString || HEX_ESCAPE_REGEXP.test(name)) {\n params['filename*'] = name\n }\n\n // set filename parameter\n if (isQuotedString || hasFallback) {\n params.filename = hasFallback ? fallbackName : name\n }\n\n return params\n}\n\nconst pdecode = (_str: string, hex: string) => String.fromCharCode(parseInt(hex, 16))\n\n/**\n * Create an attachment Content-Disposition header.\n *\n * @param filename file name\n * @param options\n */\n\nexport function contentDisposition(\n filename?: string,\n options: Partial<{\n type: string\n fallback: string | boolean\n }> = {}\n): string {\n // format into string\n return format(new ContentDisposition(options.type || 'attachment', createParams(filename, options.fallback)))\n}\n\nfunction decodefield(str: string) {\n const match = EXT_VALUE_REGEXP.exec(str)\n\n if (!match) throw new TypeError('invalid extended field value')\n\n const charset = match[1].toLowerCase()\n const encoded = match[2]\n let value: string\n\n switch (charset) {\n case 'iso-8859-1':\n value = getlatin1(encoded.replace(HEX_ESCAPE_REPLACE_REGEXP, pdecode))\n break\n case 'utf-8':\n try {\n value = decodeURIComponent(encoded)\n } catch {\n throw new TypeError('invalid encoded utf-8')\n }\n break\n default:\n throw new TypeError('unsupported charset in extended field')\n }\n\n return value\n}\n\n/**\n * Parse Content-Disposition header string.\n * @param header string\n */\nexport function parse(header: string): ContentDisposition {\n let match = DISPOSITION_TYPE_REGEXP.exec(header)\n\n if (!match) throw new TypeError('invalid type format')\n\n // normalize type\n let index = match[0].length\n const type = match[1].toLowerCase()\n\n let key: string\n const names = []\n const params = {}\n let value: string | string[]\n\n // calculate index to start at\n index = PARAM_REGEXP.lastIndex = match[0].slice(-1) === ';' ? index - 1 : index\n\n // match parameters\n while ((match = PARAM_REGEXP.exec(header))) {\n if (match.index !== index) throw new TypeError('invalid parameter format')\n\n index += match[0].length\n key = match[1].toLowerCase()\n value = match[2]\n\n if (names.indexOf(key) !== -1) {\n throw new TypeError('invalid duplicate parameter')\n }\n\n names.push(key)\n\n if (key.indexOf('*') + 1 === key.length) {\n // decode extended value\n key = key.slice(0, -1)\n value = decodefield(value)\n\n // overwrite existing value\n params[key] = value\n continue\n }\n\n if (typeof params[key] === 'string') continue\n\n if (value[0] === '\"') {\n value = value.slice(1, value.length - 1).replace(QESC_REGEXP, '$1')\n }\n\n params[key] = value\n }\n\n if (index !== -1 && index !== header.length) {\n throw new TypeError('invalid parameter format')\n }\n\n return new ContentDisposition(type, params)\n}\n"],"names":[],"mappings":"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"}