svelte 5.39.5 → 5.39.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compiler/index.js +1 -1
- package/package.json +2 -2
- package/src/compiler/phases/2-analyze/visitors/shared/a11y/index.js +4 -1
- package/src/compiler/phases/3-transform/client/visitors/TitleElement.js +12 -1
- package/src/compiler/phases/3-transform/server/visitors/RegularElement.js +30 -41
- package/src/compiler/phases/3-transform/server/visitors/shared/component.js +6 -1
- package/src/compiler/phases/3-transform/server/visitors/shared/element.js +86 -22
- package/src/compiler/warnings.js +2 -2
- package/src/internal/client/dom/blocks/await.js +2 -2
- package/src/internal/client/dom/elements/attributes.js +2 -2
- package/src/internal/client/dom/task.js +1 -35
- package/src/internal/client/reactivity/async.js +0 -1
- package/src/internal/client/reactivity/batch.js +140 -103
- package/src/internal/client/reactivity/deriveds.js +26 -24
- package/src/internal/client/render.js +1 -1
- package/src/internal/client/runtime.js +7 -1
- package/src/internal/server/renderer.js +15 -4
- package/src/version.js +1 -1
- package/types/index.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "svelte",
|
|
3
3
|
"description": "Cybernetically enhanced web apps",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "5.39.
|
|
5
|
+
"version": "5.39.7",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"types": "./types/index.d.ts",
|
|
8
8
|
"engines": {
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
"@types/aria-query": "^5.0.4",
|
|
148
148
|
"@types/node": "^20.11.5",
|
|
149
149
|
"dts-buddy": "^0.5.5",
|
|
150
|
-
"esbuild": "^0.
|
|
150
|
+
"esbuild": "^0.25.10",
|
|
151
151
|
"rollup": "^4.22.4",
|
|
152
152
|
"source-map": "^0.7.4",
|
|
153
153
|
"tinyglobby": "^0.2.12",
|
|
@@ -382,7 +382,10 @@ export function check_element(node, context) {
|
|
|
382
382
|
}
|
|
383
383
|
|
|
384
384
|
// element-specific checks
|
|
385
|
-
const is_labelled =
|
|
385
|
+
const is_labelled =
|
|
386
|
+
attribute_map.has('aria-label') ||
|
|
387
|
+
attribute_map.has('aria-labelledby') ||
|
|
388
|
+
attribute_map.has('title');
|
|
386
389
|
|
|
387
390
|
switch (node.name) {
|
|
388
391
|
case 'a':
|
|
@@ -12,8 +12,19 @@ export function TitleElement(node, context) {
|
|
|
12
12
|
/** @type {any} */ (node.fragment.nodes),
|
|
13
13
|
context
|
|
14
14
|
);
|
|
15
|
+
const evaluated = context.state.scope.evaluate(value);
|
|
15
16
|
|
|
16
|
-
const statement = b.stmt(
|
|
17
|
+
const statement = b.stmt(
|
|
18
|
+
b.assignment(
|
|
19
|
+
'=',
|
|
20
|
+
b.id('$.document.title'),
|
|
21
|
+
evaluated.is_known
|
|
22
|
+
? b.literal(evaluated.value)
|
|
23
|
+
: evaluated.is_defined
|
|
24
|
+
? value
|
|
25
|
+
: b.logical('??', value, b.literal(''))
|
|
26
|
+
)
|
|
27
|
+
);
|
|
17
28
|
|
|
18
29
|
if (has_state) {
|
|
19
30
|
context.state.update.push(statement);
|
|
@@ -7,11 +7,10 @@ import { is_void } from '../../../../../utils.js';
|
|
|
7
7
|
import { dev, locator } from '../../../../state.js';
|
|
8
8
|
import * as b from '#compiler/builders';
|
|
9
9
|
import { clean_nodes, determine_namespace_for_children } from '../../utils.js';
|
|
10
|
-
import { build_element_attributes,
|
|
10
|
+
import { build_element_attributes, prepare_element_spread_object } from './shared/element.js';
|
|
11
11
|
import {
|
|
12
12
|
process_children,
|
|
13
13
|
build_template,
|
|
14
|
-
build_attribute_value,
|
|
15
14
|
create_child_block,
|
|
16
15
|
PromiseOptimiser
|
|
17
16
|
} from './shared/utils.js';
|
|
@@ -37,9 +36,27 @@ export function RegularElement(node, context) {
|
|
|
37
36
|
|
|
38
37
|
const optimiser = new PromiseOptimiser();
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
// If this element needs special handling (like <select value> / <option>),
|
|
40
|
+
// avoid calling build_element_attributes here to prevent evaluating/awaiting
|
|
41
|
+
// attribute expressions twice. We'll handle attributes in the special branch.
|
|
42
|
+
const is_select_special =
|
|
43
|
+
node.name === 'select' &&
|
|
44
|
+
node.attributes.some(
|
|
45
|
+
(attribute) =>
|
|
46
|
+
((attribute.type === 'Attribute' || attribute.type === 'BindDirective') &&
|
|
47
|
+
attribute.name === 'value') ||
|
|
48
|
+
attribute.type === 'SpreadAttribute'
|
|
49
|
+
);
|
|
50
|
+
const is_option_special = node.name === 'option';
|
|
51
|
+
const is_special = is_select_special || is_option_special;
|
|
52
|
+
|
|
53
|
+
let body = /** @type {Expression | null} */ (null);
|
|
54
|
+
if (!is_special) {
|
|
55
|
+
// only open the tag in the non-special path
|
|
56
|
+
state.template.push(b.literal(`<${node.name}`));
|
|
57
|
+
body = build_element_attributes(node, { ...context, state }, optimiser.transform);
|
|
58
|
+
state.template.push(b.literal(node_is_void ? '/>' : '>')); // add `/>` for XHTML compliance
|
|
59
|
+
}
|
|
43
60
|
|
|
44
61
|
if ((node.name === 'script' || node.name === 'style') && node.fragment.nodes.length === 1) {
|
|
45
62
|
state.template.push(
|
|
@@ -95,27 +112,7 @@ export function RegularElement(node, context) {
|
|
|
95
112
|
);
|
|
96
113
|
}
|
|
97
114
|
|
|
98
|
-
if (
|
|
99
|
-
node.name === 'select' &&
|
|
100
|
-
node.attributes.some(
|
|
101
|
-
(attribute) =>
|
|
102
|
-
((attribute.type === 'Attribute' || attribute.type === 'BindDirective') &&
|
|
103
|
-
attribute.name === 'value') ||
|
|
104
|
-
attribute.type === 'SpreadAttribute'
|
|
105
|
-
)
|
|
106
|
-
) {
|
|
107
|
-
const attributes = build_spread_object(
|
|
108
|
-
node,
|
|
109
|
-
node.attributes.filter(
|
|
110
|
-
(attribute) =>
|
|
111
|
-
attribute.type === 'Attribute' ||
|
|
112
|
-
attribute.type === 'BindDirective' ||
|
|
113
|
-
attribute.type === 'SpreadAttribute'
|
|
114
|
-
),
|
|
115
|
-
context,
|
|
116
|
-
optimiser.transform
|
|
117
|
-
);
|
|
118
|
-
|
|
115
|
+
if (is_select_special) {
|
|
119
116
|
const inner_state = { ...state, template: [], init: [] };
|
|
120
117
|
process_children(trimmed, { ...context, state: inner_state });
|
|
121
118
|
|
|
@@ -124,7 +121,9 @@ export function RegularElement(node, context) {
|
|
|
124
121
|
b.block([...state.init, ...build_template(inner_state.template)])
|
|
125
122
|
);
|
|
126
123
|
|
|
127
|
-
const
|
|
124
|
+
const [attributes, ...rest] = prepare_element_spread_object(node, context, optimiser.transform);
|
|
125
|
+
|
|
126
|
+
const statement = b.stmt(b.call('$$renderer.select', attributes, fn, ...rest));
|
|
128
127
|
|
|
129
128
|
if (optimiser.expressions.length > 0) {
|
|
130
129
|
context.state.template.push(
|
|
@@ -137,19 +136,7 @@ export function RegularElement(node, context) {
|
|
|
137
136
|
return;
|
|
138
137
|
}
|
|
139
138
|
|
|
140
|
-
if (
|
|
141
|
-
const attributes = build_spread_object(
|
|
142
|
-
node,
|
|
143
|
-
node.attributes.filter(
|
|
144
|
-
(attribute) =>
|
|
145
|
-
attribute.type === 'Attribute' ||
|
|
146
|
-
attribute.type === 'BindDirective' ||
|
|
147
|
-
attribute.type === 'SpreadAttribute'
|
|
148
|
-
),
|
|
149
|
-
context,
|
|
150
|
-
optimiser.transform
|
|
151
|
-
);
|
|
152
|
-
|
|
139
|
+
if (is_option_special) {
|
|
153
140
|
let body;
|
|
154
141
|
|
|
155
142
|
if (node.metadata.synthetic_value_node) {
|
|
@@ -167,7 +154,9 @@ export function RegularElement(node, context) {
|
|
|
167
154
|
);
|
|
168
155
|
}
|
|
169
156
|
|
|
170
|
-
const
|
|
157
|
+
const [attributes, ...rest] = prepare_element_spread_object(node, context, optimiser.transform);
|
|
158
|
+
|
|
159
|
+
const statement = b.stmt(b.call('$$renderer.option', attributes, body, ...rest));
|
|
171
160
|
|
|
172
161
|
if (optimiser.expressions.length > 0) {
|
|
173
162
|
context.state.template.push(
|
|
@@ -242,7 +242,12 @@ export function build_inline_component(node, expression, context) {
|
|
|
242
242
|
params.push(pattern);
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
const slot_fn = b.arrow(
|
|
245
|
+
const slot_fn = b.arrow(
|
|
246
|
+
params,
|
|
247
|
+
node.fragment.metadata.has_await
|
|
248
|
+
? b.block([create_async_block(b.block(block.body))])
|
|
249
|
+
: b.block(block.body)
|
|
250
|
+
);
|
|
246
251
|
|
|
247
252
|
if (slot_name === 'default' && !has_children_prop) {
|
|
248
253
|
if (
|
|
@@ -358,39 +358,108 @@ function build_element_spread_attributes(
|
|
|
358
358
|
context,
|
|
359
359
|
transform
|
|
360
360
|
) {
|
|
361
|
+
const args = prepare_element_spread(
|
|
362
|
+
element,
|
|
363
|
+
/** @type {Array<AST.Attribute | AST.SpreadAttribute | AST.BindDirective>} */ (attributes),
|
|
364
|
+
style_directives,
|
|
365
|
+
class_directives,
|
|
366
|
+
context,
|
|
367
|
+
transform
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
let call = b.call('$.attributes', ...args);
|
|
371
|
+
|
|
372
|
+
context.state.template.push(call);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Prepare args for $.attributes(...): compute object, css_hash, classes, styles and flags.
|
|
377
|
+
* @param {AST.RegularElement | AST.SvelteElement} element
|
|
378
|
+
* @param {ComponentContext} context
|
|
379
|
+
* @param {(expression: Expression, metadata: ExpressionMetadata) => Expression} transform
|
|
380
|
+
* @returns {[ObjectExpression,Literal | undefined, ObjectExpression | undefined, ObjectExpression | undefined, Literal | undefined]}
|
|
381
|
+
*/
|
|
382
|
+
export function prepare_element_spread_object(element, context, transform) {
|
|
383
|
+
/** @type {Array<AST.Attribute | AST.SpreadAttribute | AST.BindDirective>} */
|
|
384
|
+
const select_attributes = [];
|
|
385
|
+
/** @type {AST.ClassDirective[]} */
|
|
386
|
+
const class_directives = [];
|
|
387
|
+
/** @type {AST.StyleDirective[]} */
|
|
388
|
+
const style_directives = [];
|
|
389
|
+
|
|
390
|
+
for (const attribute of element.attributes) {
|
|
391
|
+
if (
|
|
392
|
+
attribute.type === 'Attribute' ||
|
|
393
|
+
attribute.type === 'BindDirective' ||
|
|
394
|
+
attribute.type === 'SpreadAttribute'
|
|
395
|
+
) {
|
|
396
|
+
select_attributes.push(attribute);
|
|
397
|
+
} else if (attribute.type === 'ClassDirective') {
|
|
398
|
+
class_directives.push(attribute);
|
|
399
|
+
} else if (attribute.type === 'StyleDirective') {
|
|
400
|
+
style_directives.push(attribute);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return prepare_element_spread(
|
|
405
|
+
element,
|
|
406
|
+
select_attributes,
|
|
407
|
+
style_directives,
|
|
408
|
+
class_directives,
|
|
409
|
+
context,
|
|
410
|
+
transform
|
|
411
|
+
);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Prepare args for $.attributes(...): compute object, css_hash, classes, styles and flags.
|
|
416
|
+
* @param {AST.RegularElement | AST.SvelteElement} element
|
|
417
|
+
* @param {Array<AST.Attribute | AST.SpreadAttribute | AST.BindDirective>} attributes
|
|
418
|
+
* @param {AST.StyleDirective[]} style_directives
|
|
419
|
+
* @param {AST.ClassDirective[]} class_directives
|
|
420
|
+
* @param {ComponentContext} context
|
|
421
|
+
* @param {(expression: Expression, metadata: ExpressionMetadata) => Expression} transform
|
|
422
|
+
* @returns {[ObjectExpression,Literal | undefined, ObjectExpression | undefined, ObjectExpression | undefined, Literal | undefined]}
|
|
423
|
+
*/
|
|
424
|
+
export function prepare_element_spread(
|
|
425
|
+
element,
|
|
426
|
+
attributes,
|
|
427
|
+
style_directives,
|
|
428
|
+
class_directives,
|
|
429
|
+
context,
|
|
430
|
+
transform
|
|
431
|
+
) {
|
|
432
|
+
/** @type {ObjectExpression | undefined} */
|
|
361
433
|
let classes;
|
|
434
|
+
/** @type {ObjectExpression | undefined} */
|
|
362
435
|
let styles;
|
|
363
436
|
let flags = 0;
|
|
364
437
|
|
|
365
|
-
let has_await = false;
|
|
366
|
-
|
|
367
438
|
if (class_directives.length) {
|
|
368
|
-
const properties = class_directives.map((directive) =>
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
return b.init(
|
|
439
|
+
const properties = class_directives.map((directive) =>
|
|
440
|
+
b.init(
|
|
372
441
|
directive.name,
|
|
373
442
|
directive.expression.type === 'Identifier' && directive.expression.name === directive.name
|
|
374
443
|
? b.id(directive.name)
|
|
375
|
-
:
|
|
376
|
-
|
|
377
|
-
|
|
444
|
+
: transform(
|
|
445
|
+
/** @type {Expression} */ (context.visit(directive.expression)),
|
|
446
|
+
directive.metadata.expression
|
|
447
|
+
)
|
|
448
|
+
)
|
|
449
|
+
);
|
|
378
450
|
|
|
379
451
|
classes = b.object(properties);
|
|
380
452
|
}
|
|
381
453
|
|
|
382
454
|
if (style_directives.length > 0) {
|
|
383
|
-
const properties = style_directives.map((directive) =>
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
return b.init(
|
|
455
|
+
const properties = style_directives.map((directive) =>
|
|
456
|
+
b.init(
|
|
387
457
|
directive.name,
|
|
388
458
|
directive.value === true
|
|
389
459
|
? b.id(directive.name)
|
|
390
460
|
: build_attribute_value(directive.value, context, transform, true)
|
|
391
|
-
)
|
|
392
|
-
|
|
393
|
-
|
|
461
|
+
)
|
|
462
|
+
);
|
|
394
463
|
styles = b.object(properties);
|
|
395
464
|
}
|
|
396
465
|
|
|
@@ -403,17 +472,12 @@ function build_element_spread_attributes(
|
|
|
403
472
|
}
|
|
404
473
|
|
|
405
474
|
const object = build_spread_object(element, attributes, context, transform);
|
|
406
|
-
|
|
407
475
|
const css_hash =
|
|
408
476
|
element.metadata.scoped && context.state.analysis.css.hash
|
|
409
477
|
? b.literal(context.state.analysis.css.hash)
|
|
410
478
|
: undefined;
|
|
411
479
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
let call = b.call('$.attributes', ...args);
|
|
415
|
-
|
|
416
|
-
context.state.template.push(call);
|
|
480
|
+
return [object, css_hash, classes, styles, flags ? b.literal(flags) : undefined];
|
|
417
481
|
}
|
|
418
482
|
|
|
419
483
|
/**
|
package/src/compiler/warnings.js
CHANGED
|
@@ -174,11 +174,11 @@ export function a11y_click_events_have_key_events(node) {
|
|
|
174
174
|
}
|
|
175
175
|
|
|
176
176
|
/**
|
|
177
|
-
* Buttons and links should either contain text or have an `aria-label
|
|
177
|
+
* Buttons and links should either contain text or have an `aria-label`, `aria-labelledby` or `title` attribute
|
|
178
178
|
* @param {null | NodeLike} node
|
|
179
179
|
*/
|
|
180
180
|
export function a11y_consider_explicit_label(node) {
|
|
181
|
-
w(node, 'a11y_consider_explicit_label', `Buttons and links should either contain text or have an \`aria-label
|
|
181
|
+
w(node, 'a11y_consider_explicit_label', `Buttons and links should either contain text or have an \`aria-label\`, \`aria-labelledby\` or \`title\` attribute\nhttps://svelte.dev/e/a11y_consider_explicit_label`);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
/**
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
set_dev_current_component_function,
|
|
23
23
|
set_dev_stack
|
|
24
24
|
} from '../../context.js';
|
|
25
|
-
import { flushSync } from '../../reactivity/batch.js';
|
|
25
|
+
import { flushSync, is_flushing_sync } from '../../reactivity/batch.js';
|
|
26
26
|
|
|
27
27
|
const PENDING = 0;
|
|
28
28
|
const THEN = 1;
|
|
@@ -126,7 +126,7 @@ export function await_block(node, get_input, pending_fn, then_fn, catch_fn) {
|
|
|
126
126
|
|
|
127
127
|
// without this, the DOM does not update until two ticks after the promise
|
|
128
128
|
// resolves, which is unexpected behaviour (and somewhat irksome to test)
|
|
129
|
-
flushSync();
|
|
129
|
+
if (!is_flushing_sync) flushSync();
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
}
|
|
@@ -6,7 +6,7 @@ import { create_event, delegate } from './events.js';
|
|
|
6
6
|
import { add_form_reset_listener, autofocus } from './misc.js';
|
|
7
7
|
import * as w from '../../warnings.js';
|
|
8
8
|
import { LOADING_ATTR_SYMBOL } from '#client/constants';
|
|
9
|
-
import {
|
|
9
|
+
import { queue_micro_task } from '../task.js';
|
|
10
10
|
import { is_capture_event, is_delegated, normalize_attribute } from '../../../../utils.js';
|
|
11
11
|
import {
|
|
12
12
|
active_effect,
|
|
@@ -65,7 +65,7 @@ export function remove_input_defaults(input) {
|
|
|
65
65
|
|
|
66
66
|
// @ts-expect-error
|
|
67
67
|
input.__on_r = remove_defaults;
|
|
68
|
-
|
|
68
|
+
queue_micro_task(remove_defaults);
|
|
69
69
|
add_form_reset_listener();
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -1,34 +1,15 @@
|
|
|
1
1
|
import { run_all } from '../../shared/utils.js';
|
|
2
2
|
import { is_flushing_sync } from '../reactivity/batch.js';
|
|
3
3
|
|
|
4
|
-
// Fallback for when requestIdleCallback is not available
|
|
5
|
-
const request_idle_callback =
|
|
6
|
-
typeof requestIdleCallback === 'undefined'
|
|
7
|
-
? (/** @type {() => void} */ cb) => setTimeout(cb, 1)
|
|
8
|
-
: requestIdleCallback;
|
|
9
|
-
|
|
10
4
|
/** @type {Array<() => void>} */
|
|
11
5
|
let micro_tasks = [];
|
|
12
6
|
|
|
13
|
-
/** @type {Array<() => void>} */
|
|
14
|
-
let idle_tasks = [];
|
|
15
|
-
|
|
16
7
|
function run_micro_tasks() {
|
|
17
8
|
var tasks = micro_tasks;
|
|
18
9
|
micro_tasks = [];
|
|
19
10
|
run_all(tasks);
|
|
20
11
|
}
|
|
21
12
|
|
|
22
|
-
function run_idle_tasks() {
|
|
23
|
-
var tasks = idle_tasks;
|
|
24
|
-
idle_tasks = [];
|
|
25
|
-
run_all(tasks);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function has_pending_tasks() {
|
|
29
|
-
return micro_tasks.length > 0 || idle_tasks.length > 0;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
13
|
/**
|
|
33
14
|
* @param {() => void} fn
|
|
34
15
|
*/
|
|
@@ -51,26 +32,11 @@ export function queue_micro_task(fn) {
|
|
|
51
32
|
micro_tasks.push(fn);
|
|
52
33
|
}
|
|
53
34
|
|
|
54
|
-
/**
|
|
55
|
-
* @param {() => void} fn
|
|
56
|
-
*/
|
|
57
|
-
export function queue_idle_task(fn) {
|
|
58
|
-
if (idle_tasks.length === 0) {
|
|
59
|
-
request_idle_callback(run_idle_tasks);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
idle_tasks.push(fn);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
35
|
/**
|
|
66
36
|
* Synchronously run any queued tasks.
|
|
67
37
|
*/
|
|
68
38
|
export function flush_tasks() {
|
|
69
|
-
|
|
39
|
+
while (micro_tasks.length > 0) {
|
|
70
40
|
run_micro_tasks();
|
|
71
41
|
}
|
|
72
|
-
|
|
73
|
-
if (idle_tasks.length > 0) {
|
|
74
|
-
run_idle_tasks();
|
|
75
|
-
}
|
|
76
42
|
}
|