diff --git a/packages/svelte/src/internal/server/index.js b/packages/svelte/src/internal/server/index.js index fc8798625c..1fca6070d7 100644 --- a/packages/svelte/src/internal/server/index.js +++ b/packages/svelte/src/internal/server/index.js @@ -94,7 +94,7 @@ function close(head, body, payload) { cleanup(); } - head += payload.global.head.title.value; + head += payload.global.head.get_title(); body = BLOCK_OPEN + body + BLOCK_CLOSE; // this inserts a fake boundary so hydration matches @@ -698,7 +698,7 @@ export function build_title(payload, children) { payload.compact({ start: i, fn: ({ head }) => { - payload.global.head.title = { path, value: head }; + payload.global.head.set_title(head, path); // since we can only ever render the title in this chunk, and title rendering is handled specially, // we can just ditch the results after we've saved them globally return { head: '', body: '' }; diff --git a/packages/svelte/src/internal/server/payload.js b/packages/svelte/src/internal/server/payload.js index 5dbb3c5a43..6f1485b3b3 100644 --- a/packages/svelte/src/internal/server/payload.js +++ b/packages/svelte/src/internal/server/payload.js @@ -397,27 +397,32 @@ export class TreeHeadState { */ #title = { path: [], value: '' }; - get title() { - return this.#title; + get_title() { + return this.#title.value; } - set title(value) { + /** + * Performs a depth-first (lexicographic) comparison using the path. Rejects sets + * from earlier than or equal to the current value. + * @param {string} value + * @param {number[]} path + */ + set_title(value, path) { // perform a depth-first (lexicographic) comparison using the path. Reject sets // from earlier than or equal to the current value. - const contender_path = value.path; const current_path = this.#title.path; - const max_len = Math.max(contender_path.length, current_path.length); + const max_len = Math.max(path.length, current_path.length); for (let i = 0; i < max_len; i++) { - const contender_segment = contender_path[i]; + const contender_segment = path[i]; const current_segment = current_path[i]; // contender shorter than current and all previous segments equal -> earlier if (contender_segment === undefined) return; // current shorter than contender and all previous segments equal -> contender is later if (current_segment === undefined || contender_segment > current_segment) { - this.#title.path = value.path; - this.#title.value = value.value; + this.#title.path = path; + this.#title.value = value; return; } if (contender_segment < current_segment) return; diff --git a/packages/svelte/src/internal/server/payload.test.ts b/packages/svelte/src/internal/server/payload.test.ts index 5b59a7832c..c0417af9bd 100644 --- a/packages/svelte/src/internal/server/payload.test.ts +++ b/packages/svelte/src/internal/server/payload.test.ts @@ -170,7 +170,7 @@ test('subsume replaces tree content and state from other', () => { $$payload.push('body'); }); b.global.css.add({ hash: 'h', code: 'c' }); - b.global.head.title = { path: [1], value: 'Title' }; + b.global.head.set_title('Title', [1]); b.local.select_value = 'B'; b.promises.initial = Promise.resolve(); @@ -192,7 +192,7 @@ test('subsume refuses to switch modes', () => { $$payload.push('body'); }); b.global.css.add({ hash: 'h', code: 'c' }); - b.global.head.title = { path: [1], value: 'Title' }; + b.global.head.set_title('Title', [1]); b.local.select_value = 'B'; b.promises.initial = Promise.resolve(); @@ -209,28 +209,28 @@ test('TreeState uid generator uses prefix', () => { test('TreeHeadState title ordering favors later lexicographic paths', () => { const head = new TreeHeadState(() => ''); - head.title = { path: [1], value: 'A' }; - assert.equal(head.title.value, 'A'); + head.set_title('A', [1]); + assert.equal(head.get_title(), 'A'); // equal path -> unchanged - head.title = { path: [1], value: 'B' }; - assert.equal(head.title.value, 'A'); + head.set_title('B', [1]); + assert.equal(head.get_title(), 'A'); // earlier -> unchanged - head.title = { path: [0, 9], value: 'C' }; - assert.equal(head.title.value, 'A'); + head.set_title('C', [0, 9]); + assert.equal(head.get_title(), 'A'); // later -> update - head.title = { path: [2], value: 'D' }; - assert.equal(head.title.value, 'D'); + head.set_title('D', [2]); + assert.equal(head.get_title(), 'D'); // longer but same prefix -> update - head.title = { path: [2, 0], value: 'E' }; - assert.equal(head.title.value, 'E'); + head.set_title('E', [2, 0]); + assert.equal(head.get_title(), 'E'); // shorter (earlier) than current with same prefix -> unchanged - head.title = { path: [2], value: 'F' }; - assert.equal(head.title.value, 'E'); + head.set_title('F', [2]); + assert.equal(head.get_title(), 'E'); }); test('push accepts async functions in async context', async () => {