Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
webidl.js696 linesDownload Raw Back to fetch
1'use strict'
2
3const { types, inspect } = require('node:util')
4const { markAsUncloneable } = require('node:worker_threads')
5const { toUSVString } = require('../../core/util')
6
7/** @type {import('../../../types/webidl').Webidl} */
8const webidl = {}
9webidl.converters = {}
10webidl.util = {}
11webidl.errors = {}
12
13webidl.errors.exception = function (message) {
14  return new TypeError(`${message.header}: ${message.message}`)
15}
16
17webidl.errors.conversionFailed = function (context) {
18  const plural = context.types.length === 1 ? '' : ' one of'
19  const message =
20    `${context.argument} could not be converted to` +
21    `${plural}: ${context.types.join(', ')}.`
22
23  return webidl.errors.exception({
24    header: context.prefix,
25    message
26  })
27}
28
29webidl.errors.invalidArgument = function (context) {
30  return webidl.errors.exception({
31    header: context.prefix,
32    message: `"${context.value}" is an invalid ${context.type}.`
33  })
34}
35
36// https://webidl.spec.whatwg.org/#implements
37webidl.brandCheck = function (V, I, opts) {
38  if (opts?.strict !== false) {
39    if (!(V instanceof I)) {
40      const err = new TypeError('Illegal invocation')
41      err.code = 'ERR_INVALID_THIS' // node compat.
42      throw err
43    }
44  } else {
45    if (V?.[Symbol.toStringTag] !== I.prototype[Symbol.toStringTag]) {
46      const err = new TypeError('Illegal invocation')
47      err.code = 'ERR_INVALID_THIS' // node compat.
48      throw err
49    }
50  }
51}
52
53webidl.argumentLengthCheck = function ({ length }, min, ctx) {
54  if (length < min) {
55    throw webidl.errors.exception({
56      message: `${min} argument${min !== 1 ? 's' : ''} required, ` +
57               `but${length ? ' only' : ''} ${length} found.`,
58      header: ctx
59    })
60  }
61}
62
63webidl.illegalConstructor = function () {
64  throw webidl.errors.exception({
65    header: 'TypeError',
66    message: 'Illegal constructor'
67  })
68}
69
70// https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values
71webidl.util.Type = function (V) {
72  switch (typeof V) {
73    case 'undefined': return 'Undefined'
74    case 'boolean': return 'Boolean'
75    case 'string': return 'String'
76    case 'symbol': return 'Symbol'
77    case 'number': return 'Number'
78    case 'bigint': return 'BigInt'
79    case 'function':
80    case 'object': {
81      if (V === null) {
82        return 'Null'
83      }
84
85      return 'Object'
86    }
87  }
88}
89
90webidl.util.markAsUncloneable = markAsUncloneable || (() => {})
91// https://webidl.spec.whatwg.org/#abstract-opdef-converttoint
92webidl.util.ConvertToInt = function (V, bitLength, signedness, opts) {
93  let upperBound
94  let lowerBound
95
96  // 1. If bitLength is 64, then:
97  if (bitLength === 64) {
98    // 1. Let upperBound be 2^53 − 1.
99    upperBound = Math.pow(2, 53) - 1
100
101    // 2. If signedness is "unsigned", then let lowerBound be 0.
102    if (signedness === 'unsigned') {
103      lowerBound = 0
104    } else {
105      // 3. Otherwise let lowerBound be −2^53 + 1.
106      lowerBound = Math.pow(-2, 53) + 1
107    }
108  } else if (signedness === 'unsigned') {
109    // 2. Otherwise, if signedness is "unsigned", then:
110
111    // 1. Let lowerBound be 0.
112    lowerBound = 0
113
114    // 2. Let upperBound be 2^bitLength − 1.
115    upperBound = Math.pow(2, bitLength) - 1
116  } else {
117    // 3. Otherwise:
118
119    // 1. Let lowerBound be -2^bitLength − 1.
120    lowerBound = Math.pow(-2, bitLength) - 1
121
122    // 2. Let upperBound be 2^bitLength − 1 − 1.
123    upperBound = Math.pow(2, bitLength - 1) - 1
124  }
125
126  // 4. Let x be ? ToNumber(V).
127  let x = Number(V)
128
129  // 5. If x is −0, then set x to +0.
130  if (x === 0) {
131    x = 0
132  }
133
134  // 6. If the conversion is to an IDL type associated
135  //    with the [EnforceRange] extended attribute, then:
136  if (opts?.enforceRange === true) {
137    // 1. If x is NaN, +∞, or −∞, then throw a TypeError.
138    if (
139      Number.isNaN(x) ||
140      x === Number.POSITIVE_INFINITY ||
141      x === Number.NEGATIVE_INFINITY
142    ) {
143      throw webidl.errors.exception({
144        header: 'Integer conversion',
145        message: `Could not convert ${webidl.util.Stringify(V)} to an integer.`
146      })
147    }
148
149    // 2. Set x to IntegerPart(x).
150    x = webidl.util.IntegerPart(x)
151
152    // 3. If x < lowerBound or x > upperBound, then
153    //    throw a TypeError.
154    if (x < lowerBound || x > upperBound) {
155      throw webidl.errors.exception({
156        header: 'Integer conversion',
157        message: `Value must be between ${lowerBound}-${upperBound}, got ${x}.`
158      })
159    }
160
161    // 4. Return x.
162    return x
163  }
164
165  // 7. If x is not NaN and the conversion is to an IDL
166  //    type associated with the [Clamp] extended
167  //    attribute, then:
168  if (!Number.isNaN(x) && opts?.clamp === true) {
169    // 1. Set x to min(max(x, lowerBound), upperBound).
170    x = Math.min(Math.max(x, lowerBound), upperBound)
171
172    // 2. Round x to the nearest integer, choosing the
173    //    even integer if it lies halfway between two,
174    //    and choosing +0 rather than −0.
175    if (Math.floor(x) % 2 === 0) {
176      x = Math.floor(x)
177    } else {
178      x = Math.ceil(x)
179    }
180
181    // 3. Return x.
182    return x
183  }
184
185  // 8. If x is NaN, +0, +∞, or −∞, then return +0.
186  if (
187    Number.isNaN(x) ||
188    (x === 0 && Object.is(0, x)) ||
189    x === Number.POSITIVE_INFINITY ||
190    x === Number.NEGATIVE_INFINITY
191  ) {
192    return 0
193  }
194
195  // 9. Set x to IntegerPart(x).
196  x = webidl.util.IntegerPart(x)
197
198  // 10. Set x to x modulo 2^bitLength.
199  x = x % Math.pow(2, bitLength)
200
201  // 11. If signedness is "signed" and x ≥ 2^bitLength − 1,
202  //    then return x − 2^bitLength.
203  if (signedness === 'signed' && x >= Math.pow(2, bitLength) - 1) {
204    return x - Math.pow(2, bitLength)
205  }
206
207  // 12. Otherwise, return x.
208  return x
209}
210
211// https://webidl.spec.whatwg.org/#abstract-opdef-integerpart
212webidl.util.IntegerPart = function (n) {
213  // 1. Let r be floor(abs(n)).
214  const r = Math.floor(Math.abs(n))
215
216  // 2. If n < 0, then return -1 × r.
217  if (n < 0) {
218    return -1 * r
219  }
220
221  // 3. Otherwise, return r.
222  return r
223}
224
225webidl.util.Stringify = function (V) {
226  const type = webidl.util.Type(V)
227
228  switch (type) {
229    case 'Symbol':
230      return `Symbol(${V.description})`
231    case 'Object':
232      return inspect(V)
233    case 'String':
234      return `"${V}"`
235    default:
236      return `${V}`
237  }
238}
239
240// https://webidl.spec.whatwg.org/#es-sequence
241webidl.sequenceConverter = function (converter) {
242  return (V, prefix, argument, Iterable) => {
243    // 1. If Type(V) is not Object, throw a TypeError.
244    if (webidl.util.Type(V) !== 'Object') {
245      throw webidl.errors.exception({
246        header: prefix,
247        message: `${argument} (${webidl.util.Stringify(V)}) is not iterable.`
248      })
249    }
250
251    // 2. Let method be ? GetMethod(V, @@iterator).
252    /** @type {Generator} */
253    const method = typeof Iterable === 'function' ? Iterable() : V?.[Symbol.iterator]?.()
254    const seq = []
255    let index = 0
256
257    // 3. If method is undefined, throw a TypeError.
258    if (
259      method === undefined ||
260      typeof method.next !== 'function'
261    ) {
262      throw webidl.errors.exception({
263        header: prefix,
264        message: `${argument} is not iterable.`
265      })
266    }
267
268    // https://webidl.spec.whatwg.org/#create-sequence-from-iterable
269    while (true) {
270      const { done, value } = method.next()
271
272      if (done) {
273        break
274      }
275
276      seq.push(converter(value, prefix, `${argument}[${index++}]`))
277    }
278
279    return seq
280  }
281}
282
283// https://webidl.spec.whatwg.org/#es-to-record
284webidl.recordConverter = function (keyConverter, valueConverter) {
285  return (O, prefix, argument) => {
286    // 1. If Type(O) is not Object, throw a TypeError.
287    if (webidl.util.Type(O) !== 'Object') {
288      throw webidl.errors.exception({
289        header: prefix,
290        message: `${argument} ("${webidl.util.Type(O)}") is not an Object.`
291      })
292    }
293
294    // 2. Let result be a new empty instance of record<K, V>.
295    const result = {}
296
297    if (!types.isProxy(O)) {
298      // 1. Let desc be ? O.[[GetOwnProperty]](key).
299      const keys = [...Object.getOwnPropertyNames(O), ...Object.getOwnPropertySymbols(O)]
300
301      for (const key of keys) {
302        // 1. Let typedKey be key converted to an IDL value of type K.
303        const typedKey = keyConverter(key, prefix, argument)
304
305        // 2. Let value be ? Get(O, key).
306        // 3. Let typedValue be value converted to an IDL value of type V.
307        const typedValue = valueConverter(O[key], prefix, argument)
308
309        // 4. Set result[typedKey] to typedValue.
310        result[typedKey] = typedValue
311      }
312
313      // 5. Return result.
314      return result
315    }
316
317    // 3. Let keys be ? O.[[OwnPropertyKeys]]().
318    const keys = Reflect.ownKeys(O)
319
320    // 4. For each key of keys.
321    for (const key of keys) {
322      // 1. Let desc be ? O.[[GetOwnProperty]](key).
323      const desc = Reflect.getOwnPropertyDescriptor(O, key)
324
325      // 2. If desc is not undefined and desc.[[Enumerable]] is true:
326      if (desc?.enumerable) {
327        // 1. Let typedKey be key converted to an IDL value of type K.
328        const typedKey = keyConverter(key, prefix, argument)
329
330        // 2. Let value be ? Get(O, key).
331        // 3. Let typedValue be value converted to an IDL value of type V.
332        const typedValue = valueConverter(O[key], prefix, argument)
333
334        // 4. Set result[typedKey] to typedValue.
335        result[typedKey] = typedValue
336      }
337    }
338
339    // 5. Return result.
340    return result
341  }
342}
343
344webidl.interfaceConverter = function (i) {
345  return (V, prefix, argument, opts) => {
346    if (opts?.strict !== false && !(V instanceof i)) {
347      throw webidl.errors.exception({
348        header: prefix,
349        message: `Expected ${argument} ("${webidl.util.Stringify(V)}") to be an instance of ${i.name}.`
350      })
351    }
352
353    return V
354  }
355}
356
357webidl.dictionaryConverter = function (converters) {
358  return (dictionary, prefix, argument) => {
359    const type = webidl.util.Type(dictionary)
360    const dict = {}
361
362    if (type === 'Null' || type === 'Undefined') {
363      return dict
364    } else if (type !== 'Object') {
365      throw webidl.errors.exception({
366        header: prefix,
367        message: `Expected ${dictionary} to be one of: Null, Undefined, Object.`
368      })
369    }
370
371    for (const options of converters) {
372      const { key, defaultValue, required, converter } = options
373
374      if (required === true) {
375        if (!Object.hasOwn(dictionary, key)) {
376          throw webidl.errors.exception({
377            header: prefix,
378            message: `Missing required key "${key}".`
379          })
380        }
381      }
382
383      let value = dictionary[key]
384      const hasDefault = Object.hasOwn(options, 'defaultValue')
385
386      // Only use defaultValue if value is undefined and
387      // a defaultValue options was provided.
388      if (hasDefault && value !== null) {
389        value ??= defaultValue()
390      }
391
392      // A key can be optional and have no default value.
393      // When this happens, do not perform a conversion,
394      // and do not assign the key a value.
395      if (required || hasDefault || value !== undefined) {
396        value = converter(value, prefix, `${argument}.${key}`)
397
398        if (
399          options.allowedValues &&
400          !options.allowedValues.includes(value)
401        ) {
402          throw webidl.errors.exception({
403            header: prefix,
404            message: `${value} is not an accepted type. Expected one of ${options.allowedValues.join(', ')}.`
405          })
406        }
407
408        dict[key] = value
409      }
410    }
411
412    return dict
413  }
414}
415
416webidl.nullableConverter = function (converter) {
417  return (V, prefix, argument) => {
418    if (V === null) {
419      return V
420    }
421
422    return converter(V, prefix, argument)
423  }
424}
425
426// https://webidl.spec.whatwg.org/#es-DOMString
427webidl.converters.DOMString = function (V, prefix, argument, opts) {
428  // 1. If V is null and the conversion is to an IDL type
429  //    associated with the [LegacyNullToEmptyString]
430  //    extended attribute, then return the DOMString value
431  //    that represents the empty string.
432  if (V === null && opts?.legacyNullToEmptyString) {
433    return ''
434  }
435
436  // 2. Let x be ? ToString(V).
437  if (typeof V === 'symbol') {
438    throw webidl.errors.exception({
439      header: prefix,
440      message: `${argument} is a symbol, which cannot be converted to a DOMString.`
441    })
442  }
443
444  // 3. Return the IDL DOMString value that represents the
445  //    same sequence of code units as the one the
446  //    ECMAScript String value x represents.
447  return String(V)
448}
449
450// https://webidl.spec.whatwg.org/#es-ByteString
451webidl.converters.ByteString = function (V, prefix, argument) {
452  // 1. Let x be ? ToString(V).
453  // Note: DOMString converter perform ? ToString(V)
454  const x = webidl.converters.DOMString(V, prefix, argument)
455
456  // 2. If the value of any element of x is greater than
457  //    255, then throw a TypeError.
458  for (let index = 0; index < x.length; index++) {
459    if (x.charCodeAt(index) > 255) {
460      throw new TypeError(
461        'Cannot convert argument to a ByteString because the character at ' +
462        `index ${index} has a value of ${x.charCodeAt(index)} which is greater than 255.`
463      )
464    }
465  }
466
467  // 3. Return an IDL ByteString value whose length is the
468  //    length of x, and where the value of each element is
469  //    the value of the corresponding element of x.
470  return x
471}
472
473// https://webidl.spec.whatwg.org/#es-USVString
474// TODO: rewrite this so we can control the errors thrown
475webidl.converters.USVString = toUSVString
476
477// https://webidl.spec.whatwg.org/#es-boolean
478webidl.converters.boolean = function (V) {
479  // 1. Let x be the result of computing ToBoolean(V).
480  const x = Boolean(V)
481
482  // 2. Return the IDL boolean value that is the one that represents
483  //    the same truth value as the ECMAScript Boolean value x.
484  return x
485}
486
487// https://webidl.spec.whatwg.org/#es-any
488webidl.converters.any = function (V) {
489  return V
490}
491
492// https://webidl.spec.whatwg.org/#es-long-long
493webidl.converters['long long'] = function (V, prefix, argument) {
494  // 1. Let x be ? ConvertToInt(V, 64, "signed").
495  const x = webidl.util.ConvertToInt(V, 64, 'signed', undefined, prefix, argument)
496
497  // 2. Return the IDL long long value that represents
498  //    the same numeric value as x.
499  return x
500}
501
502// https://webidl.spec.whatwg.org/#es-unsigned-long-long
503webidl.converters['unsigned long long'] = function (V, prefix, argument) {
504  // 1. Let x be ? ConvertToInt(V, 64, "unsigned").
505  const x = webidl.util.ConvertToInt(V, 64, 'unsigned', undefined, prefix, argument)
506
507  // 2. Return the IDL unsigned long long value that
508  //    represents the same numeric value as x.
509  return x
510}
511
512// https://webidl.spec.whatwg.org/#es-unsigned-long
513webidl.converters['unsigned long'] = function (V, prefix, argument) {
514  // 1. Let x be ? ConvertToInt(V, 32, "unsigned").
515  const x = webidl.util.ConvertToInt(V, 32, 'unsigned', undefined, prefix, argument)
516
517  // 2. Return the IDL unsigned long value that
518  //    represents the same numeric value as x.
519  return x
520}
521
522// https://webidl.spec.whatwg.org/#es-unsigned-short
523webidl.converters['unsigned short'] = function (V, prefix, argument, opts) {
524  // 1. Let x be ? ConvertToInt(V, 16, "unsigned").
525  const x = webidl.util.ConvertToInt(V, 16, 'unsigned', opts, prefix, argument)
526
527  // 2. Return the IDL unsigned short value that represents
528  //    the same numeric value as x.
529  return x
530}
531
532// https://webidl.spec.whatwg.org/#idl-ArrayBuffer
533webidl.converters.ArrayBuffer = function (V, prefix, argument, opts) {
534  // 1. If Type(V) is not Object, or V does not have an
535  //    [[ArrayBufferData]] internal slot, then throw a
536  //    TypeError.
537  // see: https://tc39.es/ecma262/#sec-properties-of-the-arraybuffer-instances
538  // see: https://tc39.es/ecma262/#sec-properties-of-the-sharedarraybuffer-instances
539  if (
540    webidl.util.Type(V) !== 'Object' ||
541    !types.isAnyArrayBuffer(V)
542  ) {
543    throw webidl.errors.conversionFailed({
544      prefix,
545      argument: `${argument} ("${webidl.util.Stringify(V)}")`,
546      types: ['ArrayBuffer']
547    })
548  }
549
550  // 2. If the conversion is not to an IDL type associated
551  //    with the [AllowShared] extended attribute, and
552  //    IsSharedArrayBuffer(V) is true, then throw a
553  //    TypeError.
554  if (opts?.allowShared === false && types.isSharedArrayBuffer(V)) {
555    throw webidl.errors.exception({
556      header: 'ArrayBuffer',
557      message: 'SharedArrayBuffer is not allowed.'
558    })
559  }
560
561  // 3. If the conversion is not to an IDL type associated
562  //    with the [AllowResizable] extended attribute, and
563  //    IsResizableArrayBuffer(V) is true, then throw a
564  //    TypeError.
565  if (V.resizable || V.growable) {
566    throw webidl.errors.exception({
567      header: 'ArrayBuffer',
568      message: 'Received a resizable ArrayBuffer.'
569    })
570  }
571
572  // 4. Return the IDL ArrayBuffer value that is a
573  //    reference to the same object as V.
574  return V
575}
576
577webidl.converters.TypedArray = function (V, T, prefix, name, opts) {
578  // 1. Let T be the IDL type V is being converted to.
579
580  // 2. If Type(V) is not Object, or V does not have a
581  //    [[TypedArrayName]] internal slot with a value
582  //    equal to T’s name, then throw a TypeError.
583  if (
584    webidl.util.Type(V) !== 'Object' ||
585    !types.isTypedArray(V) ||
586    V.constructor.name !== T.name
587  ) {
588    throw webidl.errors.conversionFailed({
589      prefix,
590      argument: `${name} ("${webidl.util.Stringify(V)}")`,
591      types: [T.name]
592    })
593  }
594
595  // 3. If the conversion is not to an IDL type associated
596  //    with the [AllowShared] extended attribute, and
597  //    IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is
598  //    true, then throw a TypeError.
599  if (opts?.allowShared === false && types.isSharedArrayBuffer(V.buffer)) {
600    throw webidl.errors.exception({
601      header: 'ArrayBuffer',
602      message: 'SharedArrayBuffer is not allowed.'
603    })
604  }
605
606  // 4. If the conversion is not to an IDL type associated
607  //    with the [AllowResizable] extended attribute, and
608  //    IsResizableArrayBuffer(V.[[ViewedArrayBuffer]]) is
609  //    true, then throw a TypeError.
610  if (V.buffer.resizable || V.buffer.growable) {
611    throw webidl.errors.exception({
612      header: 'ArrayBuffer',
613      message: 'Received a resizable ArrayBuffer.'
614    })
615  }
616
617  // 5. Return the IDL value of type T that is a reference
618  //    to the same object as V.
619  return V
620}
621
622webidl.converters.DataView = function (V, prefix, name, opts) {
623  // 1. If Type(V) is not Object, or V does not have a
624  //    [[DataView]] internal slot, then throw a TypeError.
625  if (webidl.util.Type(V) !== 'Object' || !types.isDataView(V)) {
626    throw webidl.errors.exception({
627      header: prefix,
628      message: `${name} is not a DataView.`
629    })
630  }
631
632  // 2. If the conversion is not to an IDL type associated
633  //    with the [AllowShared] extended attribute, and
634  //    IsSharedArrayBuffer(V.[[ViewedArrayBuffer]]) is true,
635  //    then throw a TypeError.
636  if (opts?.allowShared === false && types.isSharedArrayBuffer(V.buffer)) {
637    throw webidl.errors.exception({
638      header: 'ArrayBuffer',
639      message: 'SharedArrayBuffer is not allowed.'
640    })
641  }
642
643  // 3. If the conversion is not to an IDL type associated
644  //    with the [AllowResizable] extended attribute, and
645  //    IsResizableArrayBuffer(V.[[ViewedArrayBuffer]]) is
646  //    true, then throw a TypeError.
647  if (V.buffer.resizable || V.buffer.growable) {
648    throw webidl.errors.exception({
649      header: 'ArrayBuffer',
650      message: 'Received a resizable ArrayBuffer.'
651    })
652  }
653
654  // 4. Return the IDL DataView value that is a reference
655  //    to the same object as V.
656  return V
657}
658
659// https://webidl.spec.whatwg.org/#BufferSource
660webidl.converters.BufferSource = function (V, prefix, name, opts) {
661  if (types.isAnyArrayBuffer(V)) {
662    return webidl.converters.ArrayBuffer(V, prefix, name, { ...opts, allowShared: false })
663  }
664
665  if (types.isTypedArray(V)) {
666    return webidl.converters.TypedArray(V, V.constructor, prefix, name, { ...opts, allowShared: false })
667  }
668
669  if (types.isDataView(V)) {
670    return webidl.converters.DataView(V, prefix, name, { ...opts, allowShared: false })
671  }
672
673  throw webidl.errors.conversionFailed({
674    prefix,
675    argument: `${name} ("${webidl.util.Stringify(V)}")`,
676    types: ['BufferSource']
677  })
678}
679
680webidl.converters['sequence<ByteString>'] = webidl.sequenceConverter(
681  webidl.converters.ByteString
682)
683
684webidl.converters['sequence<sequence<ByteString>>'] = webidl.sequenceConverter(
685  webidl.converters['sequence<ByteString>']
686)
687
688webidl.converters['record<ByteString, ByteString>'] = webidl.recordConverter(
689  webidl.converters.ByteString,
690  webidl.converters.ByteString
691)
692
693module.exports = {
694  webidl
695}
696 
codekingpro/portable-devtools · Team Ai