2023-07-29 20:33:28 +02:00
'use strict' ;
var GetIntrinsic = require ( 'get-intrinsic' ) ;
var callBound = require ( 'call-bind/callBound' ) ;
var inspect = require ( 'object-inspect' ) ;
2024-08-26 08:36:01 +02:00
var $TypeError = require ( 'es-errors/type' ) ;
2023-07-29 20:33:28 +02:00
var $WeakMap = GetIntrinsic ( '%WeakMap%' , true ) ;
var $Map = GetIntrinsic ( '%Map%' , true ) ;
var $weakMapGet = callBound ( 'WeakMap.prototype.get' , true ) ;
var $weakMapSet = callBound ( 'WeakMap.prototype.set' , true ) ;
var $weakMapHas = callBound ( 'WeakMap.prototype.has' , true ) ;
var $mapGet = callBound ( 'Map.prototype.get' , true ) ;
var $mapSet = callBound ( 'Map.prototype.set' , true ) ;
var $mapHas = callBound ( 'Map.prototype.has' , true ) ;
/ *
2024-08-26 08:36:01 +02:00
* This function traverses the list returning the node corresponding to the given key .
*
* That node is also moved to the head of the list , so that if it 's accessed again we don' t need to traverse the whole list . By doing so , all the recently used nodes can be accessed relatively quickly .
* /
/** @type {import('.').listGetNode} */
2023-07-29 20:33:28 +02:00
var listGetNode = function ( list , key ) { // eslint-disable-line consistent-return
2024-08-26 08:36:01 +02:00
/** @type {typeof list | NonNullable<(typeof list)['next']>} */
var prev = list ;
/** @type {(typeof list)['next']} */
var curr ;
for ( ; ( curr = prev . next ) !== null ; prev = curr ) {
2023-07-29 20:33:28 +02:00
if ( curr . key === key ) {
prev . next = curr . next ;
2024-08-26 08:36:01 +02:00
// eslint-disable-next-line no-extra-parens
curr . next = /** @type {NonNullable<typeof list.next>} */ ( list . next ) ;
2023-07-29 20:33:28 +02:00
list . next = curr ; // eslint-disable-line no-param-reassign
return curr ;
}
}
} ;
2024-08-26 08:36:01 +02:00
/** @type {import('.').listGet} */
2023-07-29 20:33:28 +02:00
var listGet = function ( objects , key ) {
var node = listGetNode ( objects , key ) ;
return node && node . value ;
} ;
2024-08-26 08:36:01 +02:00
/** @type {import('.').listSet} */
2023-07-29 20:33:28 +02:00
var listSet = function ( objects , key , value ) {
var node = listGetNode ( objects , key ) ;
if ( node ) {
node . value = value ;
} else {
// Prepend the new node to the beginning of the list
2024-08-26 08:36:01 +02:00
objects . next = /** @type {import('.').ListNode<typeof value>} */ ( { // eslint-disable-line no-param-reassign, no-extra-parens
2023-07-29 20:33:28 +02:00
key : key ,
next : objects . next ,
value : value
2024-08-26 08:36:01 +02:00
} ) ;
2023-07-29 20:33:28 +02:00
}
} ;
2024-08-26 08:36:01 +02:00
/** @type {import('.').listHas} */
2023-07-29 20:33:28 +02:00
var listHas = function ( objects , key ) {
return ! ! listGetNode ( objects , key ) ;
} ;
2024-08-26 08:36:01 +02:00
/** @type {import('.')} */
2023-07-29 20:33:28 +02:00
module . exports = function getSideChannel ( ) {
2024-08-26 08:36:01 +02:00
/** @type {WeakMap<object, unknown>} */ var $wm ;
/** @type {Map<object, unknown>} */ var $m ;
/** @type {import('.').RootNode<unknown>} */ var $o ;
/** @type {import('.').Channel} */
2023-07-29 20:33:28 +02:00
var channel = {
assert : function ( key ) {
if ( ! channel . has ( key ) ) {
throw new $TypeError ( 'Side channel does not contain ' + inspect ( key ) ) ;
}
} ,
get : function ( key ) { // eslint-disable-line consistent-return
if ( $WeakMap && key && ( typeof key === 'object' || typeof key === 'function' ) ) {
if ( $wm ) {
return $weakMapGet ( $wm , key ) ;
}
} else if ( $Map ) {
if ( $m ) {
return $mapGet ( $m , key ) ;
}
} else {
if ( $o ) { // eslint-disable-line no-lonely-if
return listGet ( $o , key ) ;
}
}
} ,
has : function ( key ) {
if ( $WeakMap && key && ( typeof key === 'object' || typeof key === 'function' ) ) {
if ( $wm ) {
return $weakMapHas ( $wm , key ) ;
}
} else if ( $Map ) {
if ( $m ) {
return $mapHas ( $m , key ) ;
}
} else {
if ( $o ) { // eslint-disable-line no-lonely-if
return listHas ( $o , key ) ;
}
}
return false ;
} ,
set : function ( key , value ) {
if ( $WeakMap && key && ( typeof key === 'object' || typeof key === 'function' ) ) {
if ( ! $wm ) {
$wm = new $WeakMap ( ) ;
}
$weakMapSet ( $wm , key , value ) ;
} else if ( $Map ) {
if ( ! $m ) {
$m = new $Map ( ) ;
}
$mapSet ( $m , key , value ) ;
} else {
if ( ! $o ) {
2024-08-26 08:36:01 +02:00
// Initialize the linked list as an empty node, so that we don't have to special-case handling of the first node: we can always refer to it as (previous node).next, instead of something like (list).head
2023-07-29 20:33:28 +02:00
$o = { key : { } , next : null } ;
}
listSet ( $o , key , value ) ;
}
}
} ;
return channel ;
} ;