@ -4,24 +4,25 @@
/** @import { Scope } from '../../../scope' */
/** @import { NodeLike } from '../../../../errors.js' */
import * as e from '../../../../errors.js' ;
import { extract _identifiers } from '../../../../utils/ast.js' ;
import { extract _identifiers , get _parent } from '../../../../utils/ast.js' ;
import * as w from '../../../../warnings.js' ;
import * as b from '#compiler/builders' ;
import { get _rune } from '../../../scope.js' ;
import { get _name } from '../../../nodes.js' ;
/ * *
* @ param { AssignmentExpression | UpdateExpression | AST . BindDirective } node
* @ param { Pattern | Expression } argument
* @ param { AnalysisState} state
* @ param { Context} context
* /
export function validate _assignment ( node , argument , state ) {
validate _no _const _assignment ( node , argument , state. scope , node . type === 'BindDirective' ) ;
export function validate _assignment ( node , argument , context ) {
validate _no _const _assignment ( node , argument , context. state. scope , node . type === 'BindDirective' ) ;
if ( argument . type === 'Identifier' ) {
const binding = state. scope . get ( argument . name ) ;
const binding = context. state. scope . get ( argument . name ) ;
if ( state. analysis . runes ) {
if ( binding ? . node === state. analysis . props _id ) {
if ( context. state. analysis . runes ) {
if ( binding ? . node === context. state. analysis . props _id ) {
e . constant _assignment ( node , '$props.id()' ) ;
}
@ -34,6 +35,41 @@ export function validate_assignment(node, argument, state) {
e . snippet _parameter _assignment ( node ) ;
}
}
if ( argument . type === 'MemberExpression' && argument . object . type === 'ThisExpression' ) {
const name =
argument . computed && argument . property . type !== 'Literal'
? null
: get _name ( argument . property ) ;
const field =
name !== null &&
context . state . state _fields &&
Object . hasOwn ( context . state . state _fields , name ) &&
context . state . state _fields [ name ] ;
// check we're not assigning to a state field before its declaration in the constructor
if ( field && field . node . type === 'AssignmentExpression' && node !== field . node ) {
let i = context . path . length ;
while ( i -- ) {
const parent = context . path [ i ] ;
if (
parent . type === 'FunctionDeclaration' ||
parent . type === 'FunctionExpression' ||
parent . type === 'ArrowFunctionExpression'
) {
const grandparent = get _parent ( context . path , i - 1 ) ;
if ( grandparent . type === 'MethodDefinition' && grandparent . kind === 'constructor' ) {
e . state _field _invalid _assignment ( node ) ;
}
break ;
}
}
}
}
}
/ * *