this repo has no description
at main 291 lines 7.3 kB view raw
1/** @returns {void} */ 2export function noop() {} 3 4export const identity = (x) => x; 5 6/** 7 * @template T 8 * @template S 9 * @param {T} tar 10 * @param {S} src 11 * @returns {T & S} 12 */ 13export function assign(tar, src) { 14 // @ts-ignore 15 for (const k in src) tar[k] = src[k]; 16 return /** @type {T & S} */ (tar); 17} 18 19// Adapted from https://github.com/then/is-promise/blob/master/index.js 20// Distributed under MIT License https://github.com/then/is-promise/blob/master/LICENSE 21/** 22 * @param {any} value 23 * @returns {value is PromiseLike<any>} 24 */ 25export function is_promise(value) { 26 return ( 27 !!value && 28 (typeof value === 'object' || typeof value === 'function') && 29 typeof (/** @type {any} */ (value).then) === 'function' 30 ); 31} 32 33/** @returns {void} */ 34export function add_location(element, file, line, column, char) { 35 element.__svelte_meta = { 36 loc: { file, line, column, char } 37 }; 38} 39 40export function run(fn) { 41 return fn(); 42} 43 44export function blank_object() { 45 return Object.create(null); 46} 47 48/** 49 * @param {Function[]} fns 50 * @returns {void} 51 */ 52export function run_all(fns) { 53 fns.forEach(run); 54} 55 56/** 57 * @param {any} thing 58 * @returns {thing is Function} 59 */ 60export function is_function(thing) { 61 return typeof thing === 'function'; 62} 63 64/** @returns {boolean} */ 65export function safe_not_equal(a, b) { 66 return a != a ? b == b : a !== b || (a && typeof a === 'object') || typeof a === 'function'; 67} 68 69let src_url_equal_anchor; 70 71/** 72 * @param {string} element_src 73 * @param {string} url 74 * @returns {boolean} 75 */ 76export function src_url_equal(element_src, url) { 77 if (element_src === url) return true; 78 if (!src_url_equal_anchor) { 79 src_url_equal_anchor = document.createElement('a'); 80 } 81 // This is actually faster than doing URL(..).href 82 src_url_equal_anchor.href = url; 83 return element_src === src_url_equal_anchor.href; 84} 85 86/** @param {string} srcset */ 87function split_srcset(srcset) { 88 return srcset.split(',').map((src) => src.trim().split(' ').filter(Boolean)); 89} 90 91/** 92 * @param {HTMLSourceElement | HTMLImageElement} element_srcset 93 * @param {string | undefined | null} srcset 94 * @returns {boolean} 95 */ 96export function srcset_url_equal(element_srcset, srcset) { 97 const element_urls = split_srcset(element_srcset.srcset); 98 const urls = split_srcset(srcset || ''); 99 100 return ( 101 urls.length === element_urls.length && 102 urls.every( 103 ([url, width], i) => 104 width === element_urls[i][1] && 105 // We need to test both ways because Vite will create an a full URL with 106 // `new URL(asset, import.meta.url).href` for the client when `base: './'`, and the 107 // relative URLs inside srcset are not automatically resolved to absolute URLs by 108 // browsers (in contrast to img.src). This means both SSR and DOM code could 109 // contain relative or absolute URLs. 110 (src_url_equal(element_urls[i][0], url) || src_url_equal(url, element_urls[i][0])) 111 ) 112 ); 113} 114 115/** @returns {boolean} */ 116export function not_equal(a, b) { 117 return a != a ? b == b : a !== b; 118} 119 120/** @returns {boolean} */ 121export function is_empty(obj) { 122 return Object.keys(obj).length === 0; 123} 124 125/** @returns {void} */ 126export function validate_store(store, name) { 127 if (store != null && typeof store.subscribe !== 'function') { 128 throw new Error(`'${name}' is not a store with a 'subscribe' method`); 129 } 130} 131 132export function subscribe(store, ...callbacks) { 133 if (store == null) { 134 for (const callback of callbacks) { 135 callback(undefined); 136 } 137 return noop; 138 } 139 const unsub = store.subscribe(...callbacks); 140 return unsub.unsubscribe ? () => unsub.unsubscribe() : unsub; 141} 142 143/** 144 * Get the current value from a store by subscribing and immediately unsubscribing. 145 * 146 * https://svelte.dev/docs/svelte-store#get 147 * @template T 148 * @param {import('../store/public.js').Readable<T>} store 149 * @returns {T} 150 */ 151export function get_store_value(store) { 152 let value; 153 subscribe(store, (_) => (value = _))(); 154 return value; 155} 156 157/** @returns {void} */ 158export function component_subscribe(component, store, callback) { 159 component.$$.on_destroy.push(subscribe(store, callback)); 160} 161 162export function create_slot(definition, ctx, $$scope, fn) { 163 if (definition) { 164 const slot_ctx = get_slot_context(definition, ctx, $$scope, fn); 165 return definition[0](slot_ctx); 166 } 167} 168 169function get_slot_context(definition, ctx, $$scope, fn) { 170 return definition[1] && fn ? assign($$scope.ctx.slice(), definition[1](fn(ctx))) : $$scope.ctx; 171} 172 173export function get_slot_changes(definition, $$scope, dirty, fn) { 174 if (definition[2] && fn) { 175 const lets = definition[2](fn(dirty)); 176 if ($$scope.dirty === undefined) { 177 return lets; 178 } 179 if (typeof lets === 'object') { 180 const merged = []; 181 const len = Math.max($$scope.dirty.length, lets.length); 182 for (let i = 0; i < len; i += 1) { 183 merged[i] = $$scope.dirty[i] | lets[i]; 184 } 185 return merged; 186 } 187 return $$scope.dirty | lets; 188 } 189 return $$scope.dirty; 190} 191 192/** @returns {void} */ 193export function update_slot_base( 194 slot, 195 slot_definition, 196 ctx, 197 $$scope, 198 slot_changes, 199 get_slot_context_fn 200) { 201 if (slot_changes) { 202 const slot_context = get_slot_context(slot_definition, ctx, $$scope, get_slot_context_fn); 203 slot.p(slot_context, slot_changes); 204 } 205} 206 207/** @returns {void} */ 208export function update_slot( 209 slot, 210 slot_definition, 211 ctx, 212 $$scope, 213 dirty, 214 get_slot_changes_fn, 215 get_slot_context_fn 216) { 217 const slot_changes = get_slot_changes(slot_definition, $$scope, dirty, get_slot_changes_fn); 218 update_slot_base(slot, slot_definition, ctx, $$scope, slot_changes, get_slot_context_fn); 219} 220 221/** @returns {any[] | -1} */ 222export function get_all_dirty_from_scope($$scope) { 223 if ($$scope.ctx.length > 32) { 224 const dirty = []; 225 const length = $$scope.ctx.length / 32; 226 for (let i = 0; i < length; i++) { 227 dirty[i] = -1; 228 } 229 return dirty; 230 } 231 return -1; 232} 233 234/** @returns {{}} */ 235export function exclude_internal_props(props) { 236 const result = {}; 237 for (const k in props) if (k[0] !== '$') result[k] = props[k]; 238 return result; 239} 240 241/** @returns {{}} */ 242export function compute_rest_props(props, keys) { 243 const rest = {}; 244 keys = new Set(keys); 245 for (const k in props) if (!keys.has(k) && k[0] !== '$') rest[k] = props[k]; 246 return rest; 247} 248 249/** @returns {{}} */ 250export function compute_slots(slots) { 251 const result = {}; 252 for (const key in slots) { 253 result[key] = true; 254 } 255 return result; 256} 257 258/** @returns {(this: any, ...args: any[]) => void} */ 259export function once(fn) { 260 let ran = false; 261 return function (...args) { 262 if (ran) return; 263 ran = true; 264 fn.call(this, ...args); 265 }; 266} 267 268export function null_to_empty(value) { 269 return value == null ? '' : value; 270} 271 272export function set_store_value(store, ret, value) { 273 store.set(value); 274 return ret; 275} 276 277export const has_prop = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop); 278 279export function action_destroyer(action_result) { 280 return action_result && is_function(action_result.destroy) ? action_result.destroy : noop; 281} 282 283/** @param {number | string} value 284 * @returns {[number, string]} 285 */ 286export function split_css_unit(value) { 287 const split = typeof value === 'string' && value.match(/^\s*(-?[\d.]+)([^\s]*)\s*$/); 288 return split ? [parseFloat(split[1]), split[2] || 'px'] : [/** @type {number} */ (value), 'px']; 289} 290 291export const contenteditable_truthy_values = ['', true, 1, 'true', 'contenteditable'];