Skip to content

Commit 8179c6a

Browse files
tests
1 parent 5adb3f1 commit 8179c6a

File tree

4 files changed

+58
-3
lines changed

4 files changed

+58
-3
lines changed
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
export { get_hydratable_value as getHydratableValue } from '../internal/client/hydratable.js';
1+
export {
2+
get_hydratable_value as getHydratableValue,
3+
has_hydratable_value as hasHydratableValue
4+
} from '../internal/client/hydratable.js';

packages/svelte/src/internal/client/hydratable.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,21 @@ export function get_hydratable_value(key, options = {}) {
4949
return parse(val, options.parse);
5050
}
5151

52+
/**
53+
* @param {string} key
54+
* @returns {boolean}
55+
*/
56+
export function has_hydratable_value(key) {
57+
if (!hydrating) {
58+
return false;
59+
}
60+
var store = window.__svelte?.h;
61+
if (store === undefined) {
62+
throw new Error('TODO this should be impossible?');
63+
}
64+
return store.has(key);
65+
}
66+
5267
/**
5368
* @template T
5469
* @param {string} val

packages/svelte/src/internal/server/renderer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ export class SSRState {
665665
}
666666
}
667667

668-
class MemoizedUneval {
668+
export class MemoizedUneval {
669669
/** @type {Map<unknown, { value?: string }>} */
670670
#cache = new Map();
671671

packages/svelte/src/internal/server/renderer.test.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { afterAll, beforeAll, describe, expect, test } from 'vitest';
2-
import { Renderer, SSRState } from './renderer.js';
2+
import { MemoizedUneval, Renderer, SSRState } from './renderer.js';
33
import type { Component } from 'svelte';
44
import { disable_async_mode_flag, enable_async_mode_flag } from '../flags/index.js';
5+
import { uneval } from 'devalue';
56

67
test('collects synchronous body content by default', () => {
78
const component = (renderer: Renderer) => {
@@ -355,3 +356,39 @@ describe('async', () => {
355356
expect(destroyed).toEqual(['c', 'e', 'a', 'b', 'b*', 'd']);
356357
});
357358
});
359+
360+
describe('MemoizedDevalue', () => {
361+
test.each([
362+
1,
363+
'general kenobi',
364+
{ foo: 'bar' },
365+
[1, 2],
366+
null,
367+
undefined,
368+
new Map([[1, '2']])
369+
] as const)('has same behavior as unmemoized devalue for %s', (input) => {
370+
expect(new MemoizedUneval().uneval(input)).toBe(uneval(input));
371+
});
372+
373+
test('caches results', () => {
374+
const memoized = new MemoizedUneval();
375+
let calls = 0;
376+
377+
const input = {
378+
get only_once() {
379+
calls++;
380+
return 42;
381+
}
382+
};
383+
384+
const first = memoized.uneval(input);
385+
const max_calls = calls;
386+
const second = memoized.uneval(input);
387+
memoized.uneval(input);
388+
389+
expect(first).toBe(second);
390+
// for reasons I don't quite comprehend, it does get called twice, but both calls happen in the first
391+
// serialization, and don't increase afterwards
392+
expect(calls).toBe(max_calls);
393+
});
394+
});

0 commit comments

Comments
 (0)