Comparing version 5.0.0-next.133 to 5.0.0-next.134
@@ -5,3 +5,3 @@ { | ||
"license": "MIT", | ||
"version": "5.0.0-next.133", | ||
"version": "5.0.0-next.134", | ||
"type": "module", | ||
@@ -8,0 +8,0 @@ "types": "./types/index.d.ts", |
@@ -66,2 +66,23 @@ declare module '*.svelte' { | ||
/** | ||
* Compare two values, one or both of which is a reactive `$state(...)` proxy. | ||
* | ||
* Example: | ||
* ```ts | ||
* <script> | ||
* let foo = $state({}); | ||
* let bar = {}; | ||
* | ||
* foo.bar = bar; | ||
* | ||
* console.log(foo.bar === bar); // false — `foo.bar` is a reactive proxy | ||
* console.log($state.is(foo.bar, bar)); // true | ||
* </script> | ||
* ``` | ||
* | ||
* https://svelte-5-preview.vercel.app/docs/runes#$state.is | ||
* | ||
*/ | ||
export function is(a: any, b: any): boolean; | ||
// prevent intellisense from being unhelpful | ||
@@ -68,0 +89,0 @@ /** @deprecated */ |
@@ -202,2 +202,11 @@ /* This file is generated by scripts/process-messages/index.js. Do not edit! */ | ||
/** | ||
* Imports of `svelte/internal/*` are forbidden. It contains private runtime code which is subject to change without notice. If you're importing from `svelte/internal/*` to work around a limitation of Svelte, please open an issue at https://github.com/sveltejs/svelte and explain your use case | ||
* @param {null | number | NodeLike} node | ||
* @returns {never} | ||
*/ | ||
export function import_svelte_internal_forbidden(node) { | ||
e(node, "import_svelte_internal_forbidden", "Imports of `svelte/internal/*` are forbidden. It contains private runtime code which is subject to change without notice. If you're importing from `svelte/internal/*` to work around a limitation of Svelte, please open an issue at https://github.com/sveltejs/svelte and explain your use case"); | ||
} | ||
/** | ||
* Cannot use `export let` in runes mode — use `$props()` instead | ||
@@ -1081,2 +1090,12 @@ * @param {null | number | NodeLike} node | ||
/** | ||
* This snippet is shadowing the prop `%prop%` with the same name | ||
* @param {null | number | NodeLike} node | ||
* @param {string} prop | ||
* @returns {never} | ||
*/ | ||
export function snippet_shadowing_prop(node, prop) { | ||
e(node, "snippet_shadowing_prop", `This snippet is shadowing the prop \`${prop}\` with the same name`); | ||
} | ||
/** | ||
* `style:` directive can only use the `important` modifier | ||
@@ -1083,0 +1102,0 @@ * @param {null | number | NodeLike} node |
@@ -1113,3 +1113,3 @@ import is_reference from 'is-reference'; | ||
...extract_svelte_ignore( | ||
prev.start + 2 /* '//'.length */, | ||
prev.start + 4 /* '<!--'.length */, | ||
prev.data, | ||
@@ -1137,3 +1137,3 @@ state.analysis.runes | ||
...extract_svelte_ignore( | ||
comment.start + 4 /* '<!--'.length */, | ||
comment.start + 2 /* '//'.length */, | ||
comment.value, | ||
@@ -1140,0 +1140,0 @@ state.analysis.runes |
@@ -627,8 +627,20 @@ import is_reference from 'is-reference'; | ||
if (node.expression.name !== 'children') return; | ||
const { path } = context; | ||
const parent = path.at(-2); | ||
if (!parent) return; | ||
if ( | ||
parent.type === 'Component' && | ||
parent.attributes.some( | ||
(attribute) => | ||
(attribute.type === 'Attribute' || attribute.type === 'BindDirective') && | ||
attribute.name === node.expression.name | ||
) | ||
) { | ||
e.snippet_shadowing_prop(node, node.expression.name); | ||
} | ||
if (node.expression.name !== 'children') return; | ||
if ( | ||
parent.type === 'Component' || | ||
@@ -869,2 +881,8 @@ parent.type === 'SvelteComponent' || | ||
} | ||
if (rune === '$state.is') { | ||
if (node.arguments.length !== 2) { | ||
e.rune_invalid_arguments_length(node, rune, 'exactly two arguments'); | ||
} | ||
} | ||
} | ||
@@ -892,2 +910,7 @@ | ||
export const validation_runes_js = { | ||
ImportDeclaration(node) { | ||
if (typeof node.source.value === 'string' && node.source.value.startsWith('svelte/internal')) { | ||
e.import_svelte_internal_forbidden(node); | ||
} | ||
}, | ||
ExportSpecifier(node, { state }) { | ||
@@ -1065,2 +1088,7 @@ validate_export(node, state.scope, node.local.name); | ||
export const validation_runes = merge(validation, a11y_validators, { | ||
ImportDeclaration(node) { | ||
if (typeof node.source.value === 'string' && node.source.value.startsWith('svelte/internal')) { | ||
e.import_svelte_internal_forbidden(node); | ||
} | ||
}, | ||
Identifier(node, { path, state }) { | ||
@@ -1067,0 +1095,0 @@ let i = path.length; |
@@ -212,3 +212,4 @@ import { get_rune } from '../../../scope.js'; | ||
rune === '$inspect' || | ||
rune === '$state.snapshot' | ||
rune === '$state.snapshot' || | ||
rune === '$state.is' | ||
) { | ||
@@ -434,2 +435,10 @@ if (init != null && is_hoistable_function(init)) { | ||
if (rune === '$state.is') { | ||
return b.call( | ||
'$.is', | ||
/** @type {import('estree').Expression} */ (context.visit(node.arguments[0])), | ||
/** @type {import('estree').Expression} */ (context.visit(node.arguments[1])) | ||
); | ||
} | ||
if (rune === '$effect.root') { | ||
@@ -447,2 +456,27 @@ const args = /** @type {import('estree').Expression[]} */ ( | ||
context.next(); | ||
}, | ||
BinaryExpression(node, { state, visit, next }) { | ||
const operator = node.operator; | ||
if (state.options.dev) { | ||
if (operator === '===' || operator === '!==') { | ||
return b.call( | ||
'$.strict_equals', | ||
/** @type {import('estree').Expression} */ (visit(node.left)), | ||
/** @type {import('estree').Expression} */ (visit(node.right)), | ||
operator === '!==' && b.literal(false) | ||
); | ||
} | ||
if (operator === '==' || operator === '!=') { | ||
return b.call( | ||
'$.equals', | ||
/** @type {import('estree').Expression} */ (visit(node.left)), | ||
/** @type {import('estree').Expression} */ (visit(node.right)), | ||
operator === '!=' && b.literal(false) | ||
); | ||
} | ||
} | ||
next(); | ||
} | ||
@@ -449,0 +483,0 @@ }; |
@@ -35,2 +35,3 @@ import { AttributeAliases, DOMBooleanAttributes } from '../../constants.js'; | ||
'$state.snapshot', | ||
'$state.is', | ||
'$props', | ||
@@ -37,0 +38,0 @@ '$bindable', |
@@ -20,1 +20,2 @@ export const DERIVED = 1 << 1; | ||
export const STATE_SYMBOL = Symbol('$state'); | ||
export const LOADING_ATTR_SYMBOL = Symbol(''); |
@@ -9,2 +9,3 @@ import { DEV } from 'esm-env'; | ||
import * as w from '../../warnings.js'; | ||
import { LOADING_ATTR_SYMBOL } from '../../constants.js'; | ||
@@ -55,2 +56,7 @@ /** | ||
if (attribute === 'loading') { | ||
// @ts-expect-error | ||
element[LOADING_ATTR_SYMBOL] = value; | ||
} | ||
if (value === null) { | ||
@@ -350,6 +356,11 @@ element.removeAttribute(attribute); | ||
var src = element.src; | ||
element.removeAttribute('loading'); | ||
// @ts-expect-error | ||
element[LOADING_ATTR_SYMBOL] = null; | ||
element.loading = 'eager'; | ||
element.removeAttribute('src'); | ||
requestAnimationFrame(() => { | ||
element.loading = 'lazy'; | ||
// @ts-expect-error | ||
if (element[LOADING_ATTR_SYMBOL] !== 'eager') { | ||
element.loading = 'lazy'; | ||
} | ||
element.src = src; | ||
@@ -356,0 +367,0 @@ }); |
@@ -6,2 +6,3 @@ import { DEV } from 'esm-env'; | ||
import * as e from '../../../errors.js'; | ||
import { get_proxied_value, is } from '../../../proxy.js'; | ||
@@ -99,6 +100,6 @@ /** | ||
// @ts-ignore | ||
input.checked = value.includes(input.__value); | ||
input.checked = get_proxied_value(value).includes(get_proxied_value(input.__value)); | ||
} else { | ||
// @ts-ignore | ||
input.checked = input.__value === value; | ||
input.checked = is(input.__value, value); | ||
} | ||
@@ -105,0 +106,0 @@ }); |
import { effect } from '../../../reactivity/effects.js'; | ||
import { listen_to_event_and_reset_event } from './shared.js'; | ||
import { untrack } from '../../../runtime.js'; | ||
import { is } from '../../../proxy.js'; | ||
@@ -19,3 +20,3 @@ /** | ||
var option_value = get_option_value(option); | ||
if (option_value === value) { | ||
if (is(option_value, value)) { | ||
option.selected = true; | ||
@@ -22,0 +23,0 @@ return; |
@@ -36,5 +36,3 @@ import { render_effect } from '../../../reactivity/effects.js'; | ||
latest_value = get_value(); | ||
if (latest_value === undefined) return; | ||
if (!scrolling) { | ||
if (!scrolling && latest_value != null) { | ||
scrolling = true; | ||
@@ -41,0 +39,0 @@ clearTimeout(timeout); |
@@ -112,4 +112,5 @@ import { createClassComponent } from '../../../../legacy/legacy-client.js'; | ||
if (name in existing_slots) { | ||
if (name === 'default') { | ||
if (name === 'default' && !this.$$d.children) { | ||
this.$$d.children = create_slot(name); | ||
$$slots.default = true; | ||
} else { | ||
@@ -116,0 +117,0 @@ $$slots[name] = create_slot(name); |
@@ -13,21 +13,8 @@ import { noop } from '../../../shared/utils.js'; | ||
/** | ||
* @template T | ||
* @param {string} type | ||
* @param {T} [detail] | ||
* @param {any}params_0 | ||
* @returns {Event} | ||
*/ | ||
function custom_event(type, detail, { bubbles = false, cancelable = false } = {}) { | ||
const e = document.createEvent('CustomEvent'); | ||
e.initCustomEvent(type, bubbles, cancelable, detail); | ||
return e; | ||
} | ||
/** | ||
* @param {Element} dom | ||
* @param {Element} element | ||
* @param {'introstart' | 'introend' | 'outrostart' | 'outroend'} type | ||
* @returns {void} | ||
*/ | ||
function dispatch_event(dom, type) { | ||
dom.dispatchEvent(custom_event(type)); | ||
function dispatch_event(element, type) { | ||
element.dispatchEvent(new CustomEvent(type)); | ||
} | ||
@@ -34,0 +21,0 @@ |
@@ -69,1 +69,13 @@ import { set, source } from '../../reactivity/sources.js'; | ||
} | ||
/** | ||
* @param {Record<string, any>} $$props | ||
*/ | ||
export function default_slot($$props) { | ||
var children = $$props.$$slots?.default; | ||
if (children === true) { | ||
return $$props.children; | ||
} else { | ||
return children; | ||
} | ||
} |
import { hydrate_anchor, hydrate_nodes, hydrating } from './hydration.js'; | ||
import { get_descriptor } from '../utils.js'; | ||
import { DEV } from 'esm-env'; | ||
import { init_array_prototype_warnings } from '../dev/equality.js'; | ||
@@ -77,2 +78,4 @@ // We cache the Node and Element prototype methods, so that we can avoid doing | ||
element_prototype.__svelte_meta = null; | ||
init_array_prototype_warnings(); | ||
} | ||
@@ -79,0 +82,0 @@ |
@@ -75,3 +75,4 @@ export { add_locations } from './dev/elements.js'; | ||
reactive_import, | ||
update_legacy_props | ||
update_legacy_props, | ||
default_slot | ||
} from './dom/legacy/misc.js'; | ||
@@ -147,3 +148,3 @@ export { | ||
export { raf } from './timing.js'; | ||
export { proxy, snapshot } from './proxy.js'; | ||
export { proxy, snapshot, is } from './proxy.js'; | ||
export { create_custom_element } from './dom/elements/custom-element.js'; | ||
@@ -159,3 +160,2 @@ export { | ||
export { | ||
add_snippet_symbol, | ||
validate_component, | ||
@@ -167,1 +167,2 @@ validate_dynamic_element_tag, | ||
} from '../shared/validate.js'; | ||
export { strict_equals, equals } from './dev/equality.js'; |
@@ -340,1 +340,22 @@ import { DEV } from 'esm-env'; | ||
} | ||
/** | ||
* @param {any} value | ||
*/ | ||
export function get_proxied_value(value) { | ||
if (value !== null && typeof value === 'object' && STATE_SYMBOL in value) { | ||
var metadata = value[STATE_SYMBOL]; | ||
if (metadata) { | ||
return metadata.p; | ||
} | ||
} | ||
return value; | ||
} | ||
/** | ||
* @param {any} a | ||
* @param {any} b | ||
*/ | ||
export function is(a, b) { | ||
return Object.is(get_proxied_value(a), get_proxied_value(b)); | ||
} |
@@ -74,2 +74,15 @@ /* This file is generated by scripts/process-messages/index.js. Do not edit! */ | ||
} | ||
} | ||
/** | ||
* Reactive `$state(...)` proxies and the values they proxy have different identities. Because of this, comparisons with `%operator%` will produce unexpected results. Consider using `$state.is(a, b)` instead | ||
* @param {string} operator | ||
*/ | ||
export function state_proxy_equality_mismatch(operator) { | ||
if (DEV) { | ||
console.warn(`%c[svelte] ${"state_proxy_equality_mismatch"}\n%c${`Reactive \`$state(...)\` proxies and the values they proxy have different identities. Because of this, comparisons with \`${operator}\` will produce unexpected results. Consider using \`$state.is(a, b)\` instead`}`, bold, normal); | ||
} else { | ||
// TODO print a link to the documentation | ||
console.warn("state_proxy_equality_mismatch"); | ||
} | ||
} |
@@ -56,4 +56,11 @@ import { DEV } from 'esm-env'; | ||
export function push() { | ||
/** | ||
* @param {Function} [fn] | ||
*/ | ||
export function push(fn) { | ||
current_component = { p: current_component, c: null, d: null }; | ||
if (DEV) { | ||
// component function | ||
current_component.function = fn; | ||
} | ||
} | ||
@@ -60,0 +67,0 @@ |
import { is_promise, noop } from '../shared/utils.js'; | ||
import { subscribe_to_store } from '../../store/utils.js'; | ||
import { | ||
UNINITIALIZED, | ||
DOMBooleanAttributes, | ||
RawTextElements, | ||
disallowed_paragraph_contents, | ||
interactive_elements, | ||
is_tag_valid_with_parent | ||
} from '../../constants.js'; | ||
import { UNINITIALIZED, DOMBooleanAttributes, RawTextElements } from '../../constants.js'; | ||
import { escape_html } from '../../escaping.js'; | ||
@@ -19,9 +12,2 @@ import { DEV } from 'esm-env'; | ||
* @typedef {{ | ||
* tag: string; | ||
* parent: null | Element; | ||
* }} Element | ||
*/ | ||
/** | ||
* @typedef {{ | ||
* head: string; | ||
@@ -32,14 +18,2 @@ * html: string; | ||
/** | ||
* @typedef {{ | ||
* out: string; | ||
* anchor: number; | ||
* head: { | ||
* title: string; | ||
* out: string; | ||
* anchor: number; | ||
* }; | ||
* }} Payload | ||
*/ | ||
// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 | ||
@@ -69,8 +43,3 @@ // https://infra.spec.whatwg.org/#noncharacter | ||
/** | ||
* @type {Element | null} | ||
*/ | ||
let current_element = null; | ||
/** @returns {Payload} */ | ||
/** @returns {import('#server').Payload} */ | ||
function create_payload() { | ||
@@ -81,4 +50,4 @@ return { out: '', head: { title: '', out: '', anchor: 0 }, anchor: 0 }; | ||
/** | ||
* @param {Payload} to_copy | ||
* @returns {Payload} | ||
* @param {import('#server').Payload} to_copy | ||
* @returns {import('#server').Payload} | ||
*/ | ||
@@ -94,4 +63,4 @@ export function copy_payload(to_copy) { | ||
* Assigns second payload to first | ||
* @param {Payload} p1 | ||
* @param {Payload} p2 | ||
* @param {import('#server').Payload} p1 | ||
* @param {import('#server').Payload} p2 | ||
* @returns {void} | ||
@@ -106,56 +75,4 @@ */ | ||
/** | ||
* @param {Payload} payload | ||
* @param {string} message | ||
*/ | ||
function error_on_client(payload, message) { | ||
message = | ||
`Svelte SSR validation error:\n\n${message}\n\n` + | ||
'Ensure your components render valid HTML as the browser will try to repair invalid HTML, ' + | ||
'which may result in content being shifted around and will likely result in a hydration mismatch.'; | ||
// eslint-disable-next-line no-console | ||
console.error(message); | ||
payload.head.out += `<script>console.error(\`${message}\`)</script>`; | ||
} | ||
/** | ||
* @param {import('#server').Payload} payload | ||
* @param {string} tag | ||
* @param {Payload} payload | ||
*/ | ||
export function push_element(tag, payload) { | ||
if (current_element !== null && !is_tag_valid_with_parent(tag, current_element.tag)) { | ||
error_on_client(payload, `<${tag}> is invalid inside <${current_element.tag}>`); | ||
} | ||
if (interactive_elements.has(tag)) { | ||
let element = current_element; | ||
while (element !== null) { | ||
if (interactive_elements.has(element.tag)) { | ||
error_on_client(payload, `<${tag}> is invalid inside <${element.tag}>`); | ||
} | ||
element = element.parent; | ||
} | ||
} | ||
if (disallowed_paragraph_contents.includes(tag)) { | ||
let element = current_element; | ||
while (element !== null) { | ||
if (element.tag === 'p') { | ||
error_on_client(payload, `<${tag}> is invalid inside <p>`); | ||
} | ||
element = element.parent; | ||
} | ||
} | ||
current_element = { | ||
tag, | ||
parent: current_element | ||
}; | ||
} | ||
export function pop_element() { | ||
if (current_element !== null) { | ||
current_element = current_element.parent; | ||
} | ||
} | ||
/** | ||
* @param {Payload} payload | ||
* @param {string} tag | ||
* @param {() => void} attributes_fn | ||
@@ -223,4 +140,4 @@ * @param {() => void} children_fn | ||
/** | ||
* @param {Payload} payload | ||
* @param {(head_payload: Payload['head']) => void} fn | ||
* @param {import('#server').Payload} payload | ||
* @param {(head_payload: import('#server').Payload['head']) => void} fn | ||
* @returns {void} | ||
@@ -249,3 +166,3 @@ */ | ||
/** | ||
* @param {Payload} payload | ||
* @param {import('#server').Payload} payload | ||
* @param {boolean} is_html | ||
@@ -287,4 +204,5 @@ * @param {Record<string, string>} props | ||
for (key in obj) { | ||
// omit functions | ||
if (typeof obj[key] !== 'function') { | ||
// omit functions and internal svelte properties | ||
const prefix = key[0] + key[1]; // this is faster than key.slice(0, 2) | ||
if (typeof obj[key] !== 'function' && prefix !== '$$') { | ||
merged_attrs[key] = obj[key]; | ||
@@ -509,4 +427,4 @@ } | ||
/** | ||
* @param {Payload} payload | ||
* @param {void | ((payload: Payload, props: Record<string, unknown>) => void)} slot_fn | ||
* @param {import('#server').Payload} payload | ||
* @param {void | ((payload: import('#server').Payload, props: Record<string, unknown>) => void)} slot_fn | ||
* @param {Record<string, unknown>} slot_props | ||
@@ -634,2 +552,4 @@ * @param {null | (() => void)} fallback_fn | ||
export { push_element, pop_element } from './dev.js'; | ||
export { | ||
@@ -644,1 +564,3 @@ add_snippet_symbol, | ||
export { escape_html as escape }; | ||
export { default_slot } from '../client/dom/legacy/misc.js'; |
@@ -8,2 +8,16 @@ export interface Component { | ||
d: null | Array<() => void>; | ||
/** | ||
* dev mode only: the component function | ||
*/ | ||
function?: any; | ||
} | ||
export interface Payload { | ||
out: string; | ||
anchor: number; | ||
head: { | ||
title: string; | ||
out: string; | ||
anchor: number; | ||
}; | ||
} |
@@ -9,3 +9,3 @@ // generated during release, do not modify | ||
*/ | ||
export const VERSION = '5.0.0-next.133'; | ||
export const VERSION = '5.0.0-next.134'; | ||
export const PUBLIC_VERSION = '5'; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2084329
207
45652