Comparing version 5.0.0-next.184 to 5.0.0-next.185
@@ -5,3 +5,3 @@ { | ||
"license": "MIT", | ||
"version": "5.0.0-next.184", | ||
"version": "5.0.0-next.185", | ||
"type": "module", | ||
@@ -8,0 +8,0 @@ "types": "./types/index.d.ts", |
@@ -33,2 +33,3 @@ import * as acorn from 'acorn'; | ||
* @param {number} index | ||
* @returns {acorn.Expression & { leadingComments?: CommentWithLocation[]; trailingComments?: CommentWithLocation[]; }} | ||
*/ | ||
@@ -96,3 +97,3 @@ export function parse_expression_at(source, typescript, index) { | ||
walk(ast, null, { | ||
_(node, { next }) { | ||
_(node, { next, path }) { | ||
let comment; | ||
@@ -108,6 +109,9 @@ | ||
if (comments[0]) { | ||
const slice = source.slice(node.end, comments[0].start); | ||
const parent = path.at(-1); | ||
if (parent === undefined || node.end !== parent.end) { | ||
const slice = source.slice(node.end, comments[0].start); | ||
if (/^[,) \t]*$/.test(slice)) { | ||
node.trailingComments = [/** @type {CommentWithLocation} */ (comments.shift())]; | ||
if (/^[,) \t]*$/.test(slice)) { | ||
node.trailingComments = [/** @type {CommentWithLocation} */ (comments.shift())]; | ||
} | ||
} | ||
@@ -117,2 +121,5 @@ } | ||
}); | ||
if (comments.length > 0) { | ||
(ast.trailingComments ||= []).push(...comments.splice(0)); | ||
} | ||
} | ||
@@ -119,0 +126,0 @@ }; |
@@ -20,2 +20,6 @@ import { parse_expression_at } from '../acorn.js'; | ||
let index = /** @type {number} */ (node.end); | ||
if (node.trailingComments !== undefined && node.trailingComments.length > 0) { | ||
index = node.trailingComments.at(-1).end; | ||
} | ||
while (num_parens > 0) { | ||
@@ -22,0 +26,0 @@ const char = parser.template[index]; |
@@ -18,5 +18,10 @@ import read_pattern from '../read/context.js'; | ||
if (parser.eat('#')) return open(parser); | ||
if (parser.eat('/')) return close(parser); | ||
if (parser.eat(':')) return next(parser); | ||
if (parser.eat('@')) return special(parser); | ||
if (parser.match('/')) { | ||
if (!parser.match('/*') && !parser.match('//')) { | ||
parser.eat('/'); | ||
return close(parser); | ||
} | ||
} | ||
@@ -23,0 +28,0 @@ const expression = read_expression(parser); |
@@ -775,4 +775,3 @@ import is_reference from 'is-reference'; | ||
if ( | ||
binding !== null && | ||
binding.kind === 'normal' && | ||
binding?.kind === 'normal' && | ||
((binding.scope === state.instance_scope && binding.declaration_kind !== 'function') || | ||
@@ -802,18 +801,18 @@ binding.declaration_kind === 'import') | ||
binding.kind = 'derived'; | ||
} else { | ||
let idx = -1; | ||
let ancestor = path.at(idx); | ||
while (ancestor) { | ||
if (ancestor.type === 'EachBlock') { | ||
// Ensures that the array is reactive when only its entries are mutated | ||
// TODO: this doesn't seem correct. We should be checking at the points where | ||
// the identifier (the each expression) is used in a way that makes it reactive. | ||
// This just forces the collection identifier to always be reactive even if it's | ||
// not. | ||
if (ancestor.expression === (idx === -1 ? node : path.at(idx + 1))) { | ||
} | ||
} else if (binding?.kind === 'each' && binding.mutated) { | ||
// Ensure that the array is marked as reactive even when only its entries are mutated | ||
let i = path.length; | ||
while (i--) { | ||
const ancestor = path[i]; | ||
if ( | ||
ancestor.type === 'EachBlock' && | ||
state.analysis.template.scopes.get(ancestor)?.declarations.get(node.name) === binding | ||
) { | ||
for (const binding of ancestor.metadata.references) { | ||
if (binding.kind === 'normal') { | ||
binding.kind = 'state'; | ||
break; | ||
} | ||
} | ||
ancestor = path.at(--idx); | ||
break; | ||
} | ||
@@ -820,0 +819,0 @@ } |
@@ -291,3 +291,7 @@ /** @import { Context } from 'zimmerframe' */ | ||
is_text_first: | ||
(parent.type === 'Fragment' || parent.type === 'SnippetBlock') && | ||
(parent.type === 'Fragment' || | ||
parent.type === 'SnippetBlock' || | ||
parent.type === 'SvelteComponent' || | ||
parent.type === 'Component' || | ||
parent.type === 'SvelteSelf') && | ||
first && | ||
@@ -294,0 +298,0 @@ (first?.type === 'Text' || first?.type === 'ExpressionTag') |
@@ -6,3 +6,8 @@ import is_reference from 'is-reference'; | ||
import * as e from '../errors.js'; | ||
import { extract_identifiers, extract_identifiers_from_destructuring } from '../utils/ast.js'; | ||
import { | ||
extract_identifiers, | ||
extract_identifiers_from_destructuring, | ||
object, | ||
unwrap_pattern | ||
} from '../utils/ast.js'; | ||
import { JsKeywords, Runes } from './constants.js'; | ||
@@ -717,7 +722,10 @@ | ||
} else { | ||
extract_identifiers(node).forEach((identifier) => { | ||
const binding = scope.get(identifier.name); | ||
if (binding && identifier !== binding.node) { | ||
unwrap_pattern(node).forEach((node) => { | ||
let id = node.type === 'Identifier' ? node : object(node); | ||
if (id === null) return; | ||
const binding = scope.get(id.name); | ||
if (binding && id !== binding.node) { | ||
binding.mutated = true; | ||
binding.reassigned = true; | ||
binding.reassigned = node.type === 'Identifier'; | ||
} | ||
@@ -724,0 +732,0 @@ }); |
@@ -57,19 +57,25 @@ /** @import { Attribute, Text, ExpressionTag, SvelteNode } from '#compiler' */ | ||
/** | ||
* Extracts all identifiers from a pattern. | ||
* @param {ESTree.Pattern} param | ||
* @param {ESTree.Identifier[]} [nodes] | ||
* @returns {ESTree.Identifier[]} | ||
* Extracts all identifiers and member expressions from a pattern. | ||
* @param {ESTree.Pattern} pattern | ||
* @param {Array<ESTree.Identifier | ESTree.MemberExpression>} [nodes] | ||
* @returns {Array<ESTree.Identifier | ESTree.MemberExpression>} | ||
*/ | ||
export function extract_identifiers(param, nodes = []) { | ||
switch (param.type) { | ||
export function unwrap_pattern(pattern, nodes = []) { | ||
switch (pattern.type) { | ||
case 'Identifier': | ||
nodes.push(param); | ||
nodes.push(pattern); | ||
break; | ||
case 'MemberExpression': | ||
// member expressions can be part of an assignment pattern, but not a binding pattern | ||
// see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#binding_and_assignment | ||
nodes.push(pattern); | ||
break; | ||
case 'ObjectPattern': | ||
for (const prop of param.properties) { | ||
for (const prop of pattern.properties) { | ||
if (prop.type === 'RestElement') { | ||
extract_identifiers(prop.argument, nodes); | ||
unwrap_pattern(prop.argument, nodes); | ||
} else { | ||
extract_identifiers(prop.value, nodes); | ||
unwrap_pattern(prop.value, nodes); | ||
} | ||
@@ -81,4 +87,4 @@ } | ||
case 'ArrayPattern': | ||
for (const element of param.elements) { | ||
if (element) extract_identifiers(element, nodes); | ||
for (const element of pattern.elements) { | ||
if (element) unwrap_pattern(element, nodes); | ||
} | ||
@@ -89,7 +95,7 @@ | ||
case 'RestElement': | ||
extract_identifiers(param.argument, nodes); | ||
unwrap_pattern(pattern.argument, nodes); | ||
break; | ||
case 'AssignmentPattern': | ||
extract_identifiers(param.left, nodes); | ||
unwrap_pattern(pattern.left, nodes); | ||
break; | ||
@@ -102,2 +108,11 @@ } | ||
/** | ||
* Extracts all identifiers from a pattern. | ||
* @param {ESTree.Pattern} pattern | ||
* @returns {ESTree.Identifier[]} | ||
*/ | ||
export function extract_identifiers(pattern) { | ||
return unwrap_pattern(pattern, []).filter((node) => node.type === 'Identifier'); | ||
} | ||
/** | ||
* Extracts all identifiers and a stringified keypath from an expression. | ||
@@ -104,0 +119,0 @@ * @param {ESTree.Expression} expr |
@@ -54,2 +54,3 @@ /** @import { TemplateNode } from '#client' */ | ||
/** | ||
* Don't mark this as side-effect-free, hydration needs to walk all nodes | ||
* @template {Node} N | ||
@@ -59,3 +60,2 @@ * @param {N} node | ||
*/ | ||
/*#__NO_SIDE_EFFECTS__*/ | ||
export function child(node) { | ||
@@ -78,2 +78,3 @@ if (!hydrating) { | ||
/** | ||
* Don't mark this as side-effect-free, hydration needs to walk all nodes | ||
* @param {DocumentFragment | TemplateNode[]} fragment | ||
@@ -83,3 +84,2 @@ * @param {boolean} is_text | ||
*/ | ||
/*#__NO_SIDE_EFFECTS__*/ | ||
export function first_child(fragment, is_text) { | ||
@@ -110,2 +110,3 @@ if (!hydrating) { | ||
/** | ||
* Don't mark this as side-effect-free, hydration needs to walk all nodes | ||
* @template {Node} N | ||
@@ -116,3 +117,2 @@ * @param {N} node | ||
*/ | ||
/*#__NO_SIDE_EFFECTS__*/ | ||
export function sibling(node, is_text = false) { | ||
@@ -119,0 +119,0 @@ if (!hydrating) { |
@@ -210,3 +210,5 @@ /** @import { Effect, EffectNodes, TemplateNode } from '#client' */ | ||
/*#__NO_SIDE_EFFECTS__*/ | ||
/** | ||
* Don't mark this as side-effect-free, hydration needs to walk all nodes | ||
*/ | ||
export function text() { | ||
@@ -213,0 +215,0 @@ if (!hydrating) { |
@@ -168,3 +168,12 @@ /** @import { Source } from './types.js' */ | ||
if (is_function(p)) p = p(); | ||
if (typeof p === 'object' && p !== null && key in p) return get_descriptor(p, key); | ||
if (typeof p === 'object' && p !== null && key in p) { | ||
const descriptor = get_descriptor(p, key); | ||
if (descriptor && !descriptor.configurable) { | ||
// Prevent a "Non-configurability Report Error": The target is an array, it does | ||
// not actually contain this property. If it is now described as non-configurable, | ||
// the proxy throws a validation error. Setting it to true avoids that. | ||
descriptor.configurable = true; | ||
} | ||
return descriptor; | ||
} | ||
} | ||
@@ -171,0 +180,0 @@ }, |
@@ -9,3 +9,3 @@ // generated during release, do not modify | ||
*/ | ||
export const VERSION = '5.0.0-next.184'; | ||
export const VERSION = '5.0.0-next.185'; | ||
export const PUBLIC_VERSION = '5'; |
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
2138704
47008