File Explorer

/var/lang/lib/node_modules/npm/node_modules/undici/lib/web/fileapi

This explorer reads the filesystem of the server it runs on, so /workspace/user isn't present here. Browsing and the terminal still work against this server's own disk from /.

util.js11.3 KB · 392 lines
'use strict' const {  kState,  kError,  kResult,  kAborted,  kLastProgressEventFired} = require('./symbols')const { ProgressEvent } = require('./progressevent')const { getEncoding } = require('./encoding')const { serializeAMimeType, parseMIMEType } = require('../fetch/data-url')const { types } = require('node:util')const { StringDecoder } = require('string_decoder')const { btoa } = require('node:buffer') /** @type {PropertyDescriptor} */const staticPropertyDescriptors = {  enumerable: true,  writable: false,  configurable: false} /** * @see https://w3c.github.io/FileAPI/#readOperation * @param {import('./filereader').FileReader} fr * @param {import('buffer').Blob} blob * @param {string} type * @param {string?} encodingName */function readOperation (fr, blob, type, encodingName) {  // 1. If fr’s state is "loading", throw an InvalidStateError  //    DOMException.  if (fr[kState] === 'loading') {    throw new DOMException('Invalid state', 'InvalidStateError')  }   // 2. Set fr’s state to "loading".  fr[kState] = 'loading'   // 3. Set fr’s result to null.  fr[kResult] = null   // 4. Set fr’s error to null.  fr[kError] = null   // 5. Let stream be the result of calling get stream on blob.  /** @type {import('stream/web').ReadableStream} */  const stream = blob.stream()   // 6. Let reader be the result of getting a reader from stream.  const reader = stream.getReader()   // 7. Let bytes be an empty byte sequence.  /** @type {Uint8Array[]} */  const bytes = []   // 8. Let chunkPromise be the result of reading a chunk from  //    stream with reader.  let chunkPromise = reader.read()   // 9. Let isFirstChunk be true.  let isFirstChunk = true   // 10. In parallel, while true:  // Note: "In parallel" just means non-blocking  // Note 2: readOperation itself cannot be async as double  // reading the body would then reject the promise, instead  // of throwing an error.  ;(async () => {    while (!fr[kAborted]) {      // 1. Wait for chunkPromise to be fulfilled or rejected.      try {        const { done, value } = await chunkPromise         // 2. If chunkPromise is fulfilled, and isFirstChunk is        //    true, queue a task to fire a progress event called        //    loadstart at fr.        if (isFirstChunk && !fr[kAborted]) {          queueMicrotask(() => {            fireAProgressEvent('loadstart', fr)          })        }         // 3. Set isFirstChunk to false.        isFirstChunk = false         // 4. If chunkPromise is fulfilled with an object whose        //    done property is false and whose value property is        //    a Uint8Array object, run these steps:        if (!done && types.isUint8Array(value)) {          // 1. Let bs be the byte sequence represented by the          //    Uint8Array object.           // 2. Append bs to bytes.          bytes.push(value)           // 3. If roughly 50ms have passed since these steps          //    were last invoked, queue a task to fire a          //    progress event called progress at fr.          if (            (              fr[kLastProgressEventFired] === undefined ||              Date.now() - fr[kLastProgressEventFired] >= 50            ) &&            !fr[kAborted]          ) {            fr[kLastProgressEventFired] = Date.now()            queueMicrotask(() => {              fireAProgressEvent('progress', fr)            })          }           // 4. Set chunkPromise to the result of reading a          //    chunk from stream with reader.          chunkPromise = reader.read()        } else if (done) {          // 5. Otherwise, if chunkPromise is fulfilled with an          //    object whose done property is true, queue a task          //    to run the following steps and abort this algorithm:          queueMicrotask(() => {            // 1. Set fr’s state to "done".            fr[kState] = 'done'             // 2. Let result be the result of package data given            //    bytes, type, blob’s type, and encodingName.            try {              const result = packageData(bytes, type, blob.type, encodingName)               // 4. Else:               if (fr[kAborted]) {                return              }               // 1. Set fr’s result to result.              fr[kResult] = result               // 2. Fire a progress event called load at the fr.              fireAProgressEvent('load', fr)            } catch (error) {              // 3. If package data threw an exception error:               // 1. Set fr’s error to error.              fr[kError] = error               // 2. Fire a progress event called error at fr.              fireAProgressEvent('error', fr)            }             // 5. If fr’s state is not "loading", fire a progress            //    event called loadend at the fr.            if (fr[kState] !== 'loading') {              fireAProgressEvent('loadend', fr)            }          })           break        }      } catch (error) {        if (fr[kAborted]) {          return        }         // 6. Otherwise, if chunkPromise is rejected with an        //    error error, queue a task to run the following        //    steps and abort this algorithm:        queueMicrotask(() => {          // 1. Set fr’s state to "done".          fr[kState] = 'done'           // 2. Set fr’s error to error.          fr[kError] = error           // 3. Fire a progress event called error at fr.          fireAProgressEvent('error', fr)           // 4. If fr’s state is not "loading", fire a progress          //    event called loadend at fr.          if (fr[kState] !== 'loading') {            fireAProgressEvent('loadend', fr)          }        })         break      }    }  })()} /** * @see https://w3c.github.io/FileAPI/#fire-a-progress-event * @see https://dom.spec.whatwg.org/#concept-event-fire * @param {string} e The name of the event * @param {import('./filereader').FileReader} reader */function fireAProgressEvent (e, reader) {  // The progress event e does not bubble. e.bubbles must be false  // The progress event e is NOT cancelable. e.cancelable must be false  const event = new ProgressEvent(e, {    bubbles: false,    cancelable: false  })   reader.dispatchEvent(event)} /** * @see https://w3c.github.io/FileAPI/#blob-package-data * @param {Uint8Array[]} bytes * @param {string} type * @param {string?} mimeType * @param {string?} encodingName */function packageData (bytes, type, mimeType, encodingName) {  // 1. A Blob has an associated package data algorithm, given  //    bytes, a type, a optional mimeType, and a optional  //    encodingName, which switches on type and runs the  //    associated steps:   switch (type) {    case 'DataURL': {      // 1. Return bytes as a DataURL [RFC2397] subject to      //    the considerations below:      //  * Use mimeType as part of the Data URL if it is      //    available in keeping with the Data URL      //    specification [RFC2397].      //  * If mimeType is not available return a Data URL      //    without a media-type. [RFC2397].       // https://datatracker.ietf.org/doc/html/rfc2397#section-3      // dataurl    := "data:" [ mediatype ] [ ";base64" ] "," data      // mediatype  := [ type "/" subtype ] *( ";" parameter )      // data       := *urlchar      // parameter  := attribute "=" value      let dataURL = 'data:'       const parsed = parseMIMEType(mimeType || 'application/octet-stream')       if (parsed !== 'failure') {        dataURL += serializeAMimeType(parsed)      }       dataURL += ';base64,'       const decoder = new StringDecoder('latin1')       for (const chunk of bytes) {        dataURL += btoa(decoder.write(chunk))      }       dataURL += btoa(decoder.end())       return dataURL    }    case 'Text': {      // 1. Let encoding be failure      let encoding = 'failure'       // 2. If the encodingName is present, set encoding to the      //    result of getting an encoding from encodingName.      if (encodingName) {        encoding = getEncoding(encodingName)      }       // 3. If encoding is failure, and mimeType is present:      if (encoding === 'failure' && mimeType) {        // 1. Let type be the result of parse a MIME type        //    given mimeType.        const type = parseMIMEType(mimeType)         // 2. If type is not failure, set encoding to the result        //    of getting an encoding from type’s parameters["charset"].        if (type !== 'failure') {          encoding = getEncoding(type.parameters.get('charset'))        }      }       // 4. If encoding is failure, then set encoding to UTF-8.      if (encoding === 'failure') {        encoding = 'UTF-8'      }       // 5. Decode bytes using fallback encoding encoding, and      //    return the result.      return decode(bytes, encoding)    }    case 'ArrayBuffer': {      // Return a new ArrayBuffer whose contents are bytes.      const sequence = combineByteSequences(bytes)       return sequence.buffer    }    case 'BinaryString': {      // Return bytes as a binary string, in which every byte      //  is represented by a code unit of equal value [0..255].      let binaryString = ''       const decoder = new StringDecoder('latin1')       for (const chunk of bytes) {        binaryString += decoder.write(chunk)      }       binaryString += decoder.end()       return binaryString    }  }} /** * @see https://encoding.spec.whatwg.org/#decode * @param {Uint8Array[]} ioQueue * @param {string} encoding */function decode (ioQueue, encoding) {  const bytes = combineByteSequences(ioQueue)   // 1. Let BOMEncoding be the result of BOM sniffing ioQueue.  const BOMEncoding = BOMSniffing(bytes)   let slice = 0   // 2. If BOMEncoding is non-null:  if (BOMEncoding !== null) {    // 1. Set encoding to BOMEncoding.    encoding = BOMEncoding     // 2. Read three bytes from ioQueue, if BOMEncoding is    //    UTF-8; otherwise read two bytes.    //    (Do nothing with those bytes.)    slice = BOMEncoding === 'UTF-8' ? 3 : 2  }   // 3. Process a queue with an instance of encoding’s  //    decoder, ioQueue, output, and "replacement".   // 4. Return output.   const sliced = bytes.slice(slice)  return new TextDecoder(encoding).decode(sliced)} /** * @see https://encoding.spec.whatwg.org/#bom-sniff * @param {Uint8Array} ioQueue */function BOMSniffing (ioQueue) {  // 1. Let BOM be the result of peeking 3 bytes from ioQueue,  //    converted to a byte sequence.  const [a, b, c] = ioQueue   // 2. For each of the rows in the table below, starting with  //    the first one and going down, if BOM starts with the  //    bytes given in the first column, then return the  //    encoding given in the cell in the second column of that  //    row. Otherwise, return null.  if (a === 0xEF && b === 0xBB && c === 0xBF) {    return 'UTF-8'  } else if (a === 0xFE && b === 0xFF) {    return 'UTF-16BE'  } else if (a === 0xFF && b === 0xFE) {    return 'UTF-16LE'  }   return null} /** * @param {Uint8Array[]} sequences */function combineByteSequences (sequences) {  const size = sequences.reduce((a, b) => {    return a + b.byteLength  }, 0)   let offset = 0   return sequences.reduce((a, b) => {    a.set(b, offset)    offset += b.byteLength    return a  }, new Uint8Array(size))} module.exports = {  staticPropertyDescriptors,  readOperation,  fireAProgressEvent}