@oddo/lang 0.0.11 → 0.0.13

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/dist/index.js CHANGED
@@ -179,6 +179,9 @@ var UnsignedRightShiftColonEqual = _chevrotain.createToken.call(void 0, { name:
179
179
  var AndColonEqual = _chevrotain.createToken.call(void 0, { name: "AndColonEqual", pattern: /&:=/ });
180
180
  var CaretColonEqual = _chevrotain.createToken.call(void 0, { name: "CaretColonEqual", pattern: /\^:=/ });
181
181
  var OrColonEqual = _chevrotain.createToken.call(void 0, { name: "OrColonEqual", pattern: /\|:=/ });
182
+ var AndAndColonEqual = _chevrotain.createToken.call(void 0, { name: "AndAndColonEqual", pattern: /&&:=/ });
183
+ var OrOrColonEqual = _chevrotain.createToken.call(void 0, { name: "OrOrColonEqual", pattern: /\|\|:=/ });
184
+ var QuestionQuestionColonEqual = _chevrotain.createToken.call(void 0, { name: "QuestionQuestionColonEqual", pattern: /\?\?:=/ });
182
185
  var Equal = _chevrotain.createToken.call(void 0, { name: "Equal", pattern: /=/ });
183
186
  var LeftParen = _chevrotain.createToken.call(void 0, { name: "LeftParen", pattern: /\(/ });
184
187
  var RightParen = _chevrotain.createToken.call(void 0, { name: "RightParen", pattern: /\)/ });
@@ -271,6 +274,12 @@ var allTokens = [
271
274
  // |:= must come before |
272
275
  CaretColonEqual,
273
276
  // ^:= must come before ^
277
+ AndAndColonEqual,
278
+ // &&:= must come before &&
279
+ OrOrColonEqual,
280
+ // ||:= must come before ||
281
+ QuestionQuestionColonEqual,
282
+ // ??:= must come before ??
274
283
  EqualEqual,
275
284
  BangEqual,
276
285
  LessThanEqual,
@@ -399,6 +408,9 @@ var OddoParser = class extends _chevrotain.CstParser {
399
408
  AndColonEqual,
400
409
  CaretColonEqual,
401
410
  OrColonEqual,
411
+ AndAndColonEqual,
412
+ OrOrColonEqual,
413
+ QuestionQuestionColonEqual,
402
414
  Equal,
403
415
  // Punctuation
404
416
  LeftParen,
@@ -811,7 +823,10 @@ var OddoParser = class extends _chevrotain.CstParser {
811
823
  { ALT: () => this.CONSUME(UnsignedRightShiftColonEqual) },
812
824
  { ALT: () => this.CONSUME(AndColonEqual) },
813
825
  { ALT: () => this.CONSUME(CaretColonEqual) },
814
- { ALT: () => this.CONSUME(OrColonEqual) }
826
+ { ALT: () => this.CONSUME(OrColonEqual) },
827
+ { ALT: () => this.CONSUME(AndAndColonEqual) },
828
+ { ALT: () => this.CONSUME(OrOrColonEqual) },
829
+ { ALT: () => this.CONSUME(QuestionQuestionColonEqual) }
815
830
  ]);
816
831
  this.SUBRULE1(this.assignment);
817
832
  });
@@ -1709,6 +1724,9 @@ var OddoParser = class extends _chevrotain.CstParser {
1709
1724
  { ALT: () => this.CONSUME(AndColonEqual) },
1710
1725
  { ALT: () => this.CONSUME(OrColonEqual) },
1711
1726
  { ALT: () => this.CONSUME(CaretColonEqual) },
1727
+ { ALT: () => this.CONSUME(AndAndColonEqual) },
1728
+ { ALT: () => this.CONSUME(OrOrColonEqual) },
1729
+ { ALT: () => this.CONSUME(QuestionQuestionColonEqual) },
1712
1730
  { ALT: () => this.CONSUME(EqualEqual) },
1713
1731
  { ALT: () => this.CONSUME(BangEqual) },
1714
1732
  { ALT: () => this.CONSUME(LessThanEqual) },
@@ -2372,10 +2390,10 @@ function convertObjectDestructuringList(cst) {
2372
2390
  return properties;
2373
2391
  }
2374
2392
  function convertAssignment(cst) {
2375
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B;
2393
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H;
2376
2394
  const destructuringPattern = getFirstChild(cst, "destructuringPattern");
2377
2395
  if (destructuringPattern) {
2378
- const opToken2 = ((_a = cst.children.Equal) == null ? void 0 : _a[0]) || ((_b = cst.children.ColonEqual) == null ? void 0 : _b[0]) || ((_c = cst.children.PlusColonEqual) == null ? void 0 : _c[0]) || ((_d = cst.children.MinusColonEqual) == null ? void 0 : _d[0]) || ((_e = cst.children.StarColonEqual) == null ? void 0 : _e[0]) || ((_f = cst.children.SlashColonEqual) == null ? void 0 : _f[0]) || ((_g = cst.children.PercentColonEqual) == null ? void 0 : _g[0]) || ((_h = cst.children.StarStarColonEqual) == null ? void 0 : _h[0]) || ((_i = cst.children.LeftShiftColonEqual) == null ? void 0 : _i[0]) || ((_j = cst.children.RightShiftColonEqual) == null ? void 0 : _j[0]) || ((_k = cst.children.UnsignedRightShiftColonEqual) == null ? void 0 : _k[0]) || ((_l = cst.children.AndColonEqual) == null ? void 0 : _l[0]) || ((_m = cst.children.CaretColonEqual) == null ? void 0 : _m[0]) || ((_n = cst.children.OrColonEqual) == null ? void 0 : _n[0]);
2396
+ const opToken2 = ((_a = cst.children.Equal) == null ? void 0 : _a[0]) || ((_b = cst.children.ColonEqual) == null ? void 0 : _b[0]) || ((_c = cst.children.PlusColonEqual) == null ? void 0 : _c[0]) || ((_d = cst.children.MinusColonEqual) == null ? void 0 : _d[0]) || ((_e = cst.children.StarColonEqual) == null ? void 0 : _e[0]) || ((_f = cst.children.SlashColonEqual) == null ? void 0 : _f[0]) || ((_g = cst.children.PercentColonEqual) == null ? void 0 : _g[0]) || ((_h = cst.children.StarStarColonEqual) == null ? void 0 : _h[0]) || ((_i = cst.children.LeftShiftColonEqual) == null ? void 0 : _i[0]) || ((_j = cst.children.RightShiftColonEqual) == null ? void 0 : _j[0]) || ((_k = cst.children.UnsignedRightShiftColonEqual) == null ? void 0 : _k[0]) || ((_l = cst.children.AndColonEqual) == null ? void 0 : _l[0]) || ((_m = cst.children.CaretColonEqual) == null ? void 0 : _m[0]) || ((_n = cst.children.OrColonEqual) == null ? void 0 : _n[0]) || ((_o = cst.children.AndAndColonEqual) == null ? void 0 : _o[0]) || ((_p = cst.children.OrOrColonEqual) == null ? void 0 : _p[0]) || ((_q = cst.children.QuestionQuestionColonEqual) == null ? void 0 : _q[0]);
2379
2397
  if (opToken2) {
2380
2398
  const left2 = convertDestructuringPattern(destructuringPattern);
2381
2399
  const right = convertExpression(getFirstChild(cst, "assignment"));
@@ -2397,7 +2415,7 @@ function convertAssignment(cst) {
2397
2415
  return convertDestructuringPattern(destructuringPattern);
2398
2416
  }
2399
2417
  const left = convertExpression(getFirstChild(cst, "conditional"));
2400
- const opToken = ((_o = cst.children.Equal) == null ? void 0 : _o[0]) || ((_p = cst.children.ColonEqual) == null ? void 0 : _p[0]) || ((_q = cst.children.PlusColonEqual) == null ? void 0 : _q[0]) || ((_r = cst.children.MinusColonEqual) == null ? void 0 : _r[0]) || ((_s = cst.children.StarColonEqual) == null ? void 0 : _s[0]) || ((_t = cst.children.SlashColonEqual) == null ? void 0 : _t[0]) || ((_u = cst.children.PercentColonEqual) == null ? void 0 : _u[0]) || ((_v = cst.children.StarStarColonEqual) == null ? void 0 : _v[0]) || ((_w = cst.children.LeftShiftColonEqual) == null ? void 0 : _w[0]) || ((_x = cst.children.RightShiftColonEqual) == null ? void 0 : _x[0]) || ((_y = cst.children.UnsignedRightShiftColonEqual) == null ? void 0 : _y[0]) || ((_z = cst.children.AndColonEqual) == null ? void 0 : _z[0]) || ((_A = cst.children.CaretColonEqual) == null ? void 0 : _A[0]) || ((_B = cst.children.OrColonEqual) == null ? void 0 : _B[0]);
2418
+ const opToken = ((_r = cst.children.Equal) == null ? void 0 : _r[0]) || ((_s = cst.children.ColonEqual) == null ? void 0 : _s[0]) || ((_t = cst.children.PlusColonEqual) == null ? void 0 : _t[0]) || ((_u = cst.children.MinusColonEqual) == null ? void 0 : _u[0]) || ((_v = cst.children.StarColonEqual) == null ? void 0 : _v[0]) || ((_w = cst.children.SlashColonEqual) == null ? void 0 : _w[0]) || ((_x = cst.children.PercentColonEqual) == null ? void 0 : _x[0]) || ((_y = cst.children.StarStarColonEqual) == null ? void 0 : _y[0]) || ((_z = cst.children.LeftShiftColonEqual) == null ? void 0 : _z[0]) || ((_A = cst.children.RightShiftColonEqual) == null ? void 0 : _A[0]) || ((_B = cst.children.UnsignedRightShiftColonEqual) == null ? void 0 : _B[0]) || ((_C = cst.children.AndColonEqual) == null ? void 0 : _C[0]) || ((_D = cst.children.CaretColonEqual) == null ? void 0 : _D[0]) || ((_E = cst.children.OrColonEqual) == null ? void 0 : _E[0]) || ((_F = cst.children.AndAndColonEqual) == null ? void 0 : _F[0]) || ((_G = cst.children.OrOrColonEqual) == null ? void 0 : _G[0]) || ((_H = cst.children.QuestionQuestionColonEqual) == null ? void 0 : _H[0]);
2401
2419
  if (opToken) {
2402
2420
  const right = convertExpression(getFirstChild(cst, "assignment"));
2403
2421
  if (left && left.type === "arraySlice") {
@@ -3794,78 +3812,187 @@ var MODIFIER_TRANSFORMATIONS = {
3794
3812
  // @mutate x = (arg1, arg2) => { x1 := value1; x2 := value2 }
3795
3813
  // -> const x = mutate((finalizer, x1, x2, ...outerDeps, arg1, arg2) => { ... }, finalizerFn, stateContainers, outerDeps)
3796
3814
  transform: (oddoExpr, leftExpr) => {
3797
- var _a, _b, _c, _d;
3815
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
3798
3816
  if (oddoExpr.type !== "arrowFunction") {
3799
3817
  throw new Error("@mutate modifier must be a function");
3800
3818
  }
3801
3819
  const funcParams = (oddoExpr.parameters || []).map((p) => p.name);
3802
- const assignments = [];
3803
- const bodyStatements = ((_a = oddoExpr.body) == null ? void 0 : _a.body) || [];
3804
- for (const stmt of bodyStatements) {
3805
- if (stmt.type === "expressionStatement" && ((_b = stmt.expression) == null ? void 0 : _b.type) === "assignment" && ((_c = stmt.expression) == null ? void 0 : _c.operator) === ":=") {
3806
- const leftName = (_d = stmt.expression.left) == null ? void 0 : _d.name;
3807
- if (!leftName) {
3808
- throw new Error("@mutate: := assignment must have an identifier on the left side");
3820
+ const mutateScope = oddoExpr._scope;
3821
+ const stateAssignmentsMap = /* @__PURE__ */ new Map();
3822
+ const processedStatements = [];
3823
+ const oddoBodyStatements = ((_a = oddoExpr.body) == null ? void 0 : _a.body) || [];
3824
+ let hasMutation = false;
3825
+ for (const stmt of oddoBodyStatements) {
3826
+ if (stmt.type === "expressionStatement") {
3827
+ if (((_b = stmt.expression) == null ? void 0 : _b.type) === "assignment") {
3828
+ const leftName = (_c = stmt.expression.left) == null ? void 0 : _c.name;
3829
+ if (!leftName && ((_d = stmt.expression.left) == null ? void 0 : _d.type) === "memberAccess") {
3830
+ hasMutation = true;
3831
+ let rightOddo2 = stmt.expression.right;
3832
+ const op2 = stmt.expression.operator;
3833
+ if (op2 !== ":=") {
3834
+ const baseOp = op2.slice(0, -2);
3835
+ let exprType;
3836
+ if (baseOp === "??") {
3837
+ exprType = "nullishCoalescing";
3838
+ } else if (baseOp === "&&" || baseOp === "||") {
3839
+ exprType = "logical";
3840
+ } else {
3841
+ exprType = "binary";
3842
+ }
3843
+ rightOddo2 = {
3844
+ type: exprType,
3845
+ operator: baseOp,
3846
+ left: stmt.expression.left,
3847
+ right: stmt.expression.right
3848
+ };
3849
+ }
3850
+ processedStatements.push({
3851
+ kind: "member",
3852
+ leftOddo: stmt.expression.left,
3853
+ rightOddo: rightOddo2
3854
+ });
3855
+ continue;
3856
+ }
3857
+ if (!leftName) {
3858
+ throw new Error("@mutate: unsupported left-hand side in assignment");
3859
+ }
3860
+ let rightOddo = stmt.expression.right;
3861
+ const op = stmt.expression.operator;
3862
+ if (op !== ":=") {
3863
+ const baseOp = op.slice(0, -2);
3864
+ let exprType;
3865
+ if (baseOp === "??") {
3866
+ exprType = "nullishCoalescing";
3867
+ } else if (baseOp === "&&" || baseOp === "||") {
3868
+ exprType = "logical";
3869
+ } else {
3870
+ exprType = "binary";
3871
+ }
3872
+ rightOddo = {
3873
+ type: exprType,
3874
+ operator: baseOp,
3875
+ left: stmt.expression.left,
3876
+ right: stmt.expression.right
3877
+ };
3878
+ }
3879
+ if (stateSetterMap.has(leftName)) {
3880
+ hasMutation = true;
3881
+ stateAssignmentsMap.set(leftName, {
3882
+ kind: "state",
3883
+ setter: stateSetterMap.get(leftName)
3884
+ });
3885
+ processedStatements.push({
3886
+ kind: "state",
3887
+ name: leftName,
3888
+ rightOddo
3889
+ });
3890
+ } else if (mutableVariables.has(leftName)) {
3891
+ hasMutation = true;
3892
+ processedStatements.push({
3893
+ kind: "mutable",
3894
+ name: leftName,
3895
+ rightOddo
3896
+ });
3897
+ } else {
3898
+ processedStatements.push({
3899
+ kind: "regular",
3900
+ stmtOddo: stmt
3901
+ });
3902
+ }
3903
+ continue;
3809
3904
  }
3810
- if (stateSetterMap.has(leftName)) {
3811
- assignments.push({
3812
- name: leftName,
3813
- kind: "state",
3814
- setter: stateSetterMap.get(leftName),
3815
- rightOddo: stmt.expression.right
3816
- });
3817
- } else if (mutableVariables.has(leftName)) {
3818
- assignments.push({
3819
- name: leftName,
3820
- kind: "mutable",
3821
- rightOddo: stmt.expression.right
3822
- });
3823
- } else {
3824
- throw new Error(`@mutate: Cannot mutate '${leftName}': not a @state or @mutable variable in current scope`);
3905
+ if (((_e = stmt.expression) == null ? void 0 : _e.type) === "arraySliceAssignment") {
3906
+ const arrayName = (_g = (_f = stmt.expression.slice) == null ? void 0 : _f.object) == null ? void 0 : _g.name;
3907
+ if (!arrayName) {
3908
+ throw new Error("@mutate: array slice assignment must have an identifier as the array");
3909
+ }
3910
+ if (stateSetterMap.has(arrayName)) {
3911
+ hasMutation = true;
3912
+ if (!stateAssignmentsMap.has(arrayName)) {
3913
+ stateAssignmentsMap.set(arrayName, {
3914
+ kind: "state-slice",
3915
+ setter: stateSetterMap.get(arrayName)
3916
+ });
3917
+ }
3918
+ processedStatements.push({
3919
+ kind: "state-slice",
3920
+ name: arrayName,
3921
+ sliceOddo: stmt.expression.slice,
3922
+ rightOddo: stmt.expression.value
3923
+ });
3924
+ } else if (mutableVariables.has(arrayName)) {
3925
+ hasMutation = true;
3926
+ processedStatements.push({
3927
+ kind: "mutable-slice",
3928
+ name: arrayName,
3929
+ sliceOddo: stmt.expression.slice,
3930
+ rightOddo: stmt.expression.value
3931
+ });
3932
+ } else {
3933
+ throw new Error(`@mutate: Cannot mutate '${arrayName}': not a @state or @mutable variable in current scope`);
3934
+ }
3935
+ continue;
3825
3936
  }
3826
3937
  }
3938
+ processedStatements.push({
3939
+ kind: "regular",
3940
+ stmtOddo: stmt
3941
+ });
3827
3942
  }
3828
- if (assignments.length === 0) {
3829
- throw new Error("@mutate function must contain at least one := assignment");
3943
+ if (!hasMutation) {
3944
+ throw new Error("@mutate function must contain at least one mutation");
3830
3945
  }
3831
- const stateAssignments = assignments.filter((a) => a.kind === "state");
3832
- const mutableAssignments = assignments.filter((a) => a.kind === "mutable");
3833
- const stateContainerNames = stateAssignments.map((a) => a.name);
3834
- const allAssignmentNames = assignments.map((a) => a.name);
3835
- const outerDeps = /* @__PURE__ */ new Set();
3836
- for (const assignment of assignments) {
3837
- collectOddoIdentifiers(assignment.rightOddo).forEach((id) => {
3838
- if (!funcParams.includes(id) && !allAssignmentNames.includes(id)) {
3839
- outerDeps.add(id);
3946
+ const uniqueStateNames = Array.from(stateAssignmentsMap.keys());
3947
+ const savedScopeMutate = currentScope;
3948
+ currentScope = mutateScope;
3949
+ const outerReactiveDeps = /* @__PURE__ */ new Set();
3950
+ for (const processed of processedStatements) {
3951
+ const nodesToScan = [];
3952
+ if (processed.rightOddo) nodesToScan.push(processed.rightOddo);
3953
+ if ((_h = processed.sliceOddo) == null ? void 0 : _h.start) nodesToScan.push(processed.sliceOddo.start);
3954
+ if ((_i = processed.sliceOddo) == null ? void 0 : _i.end) nodesToScan.push(processed.sliceOddo.end);
3955
+ if (processed.stmtOddo) nodesToScan.push(processed.stmtOddo);
3956
+ for (const node of nodesToScan) {
3957
+ const ids = collectOddoIdentifiersOnly(node);
3958
+ for (const id of ids) {
3959
+ if (isReactive(id) && !uniqueStateNames.includes(id)) {
3960
+ outerReactiveDeps.add(id);
3961
+ }
3840
3962
  }
3841
- });
3963
+ }
3842
3964
  }
3843
- const outerDepsArray = Array.from(outerDeps);
3965
+ const outerDepsArray = Array.from(outerReactiveDeps);
3844
3966
  const mutateParams = [
3845
3967
  t.identifier("finalizer"),
3846
- ...stateContainerNames.map((n) => t.identifier(n)),
3968
+ ...uniqueStateNames.map((n) => t.identifier(n)),
3847
3969
  ...outerDepsArray.map((n) => t.identifier(n)),
3848
3970
  ...funcParams.map((n) => t.identifier(n))
3849
3971
  ];
3850
3972
  const mutateBodyStmts = [];
3851
- if (stateAssignments.length > 0) {
3973
+ const hasStateAssignments = Array.from(stateAssignmentsMap.values()).some((v) => v.kind === "state");
3974
+ if (hasStateAssignments) {
3852
3975
  usedModifiers.add("stateProxy");
3853
3976
  }
3854
3977
  const callableIds = /* @__PURE__ */ new Set([
3855
- ...stateContainerNames,
3856
- ...outerDepsArray.filter((id) => !mutableVariables.has(id))
3978
+ ...uniqueStateNames,
3979
+ ...outerDepsArray
3857
3980
  ]);
3858
- const savedScopeMutate = currentScope;
3859
- currentScope = Object.create(currentScope);
3981
+ currentScope = Object.create(mutateScope);
3860
3982
  currentScope[reactiveScope] = false;
3861
- for (const assignment of assignments) {
3862
- const rightBabel = convertExpression2(assignment.rightOddo);
3863
- const tempFile = t.file(t.program([t.expressionStatement(rightBabel)]));
3983
+ for (const id of callableIds) {
3984
+ currentScope[id] = { type: "param", reactive: false };
3985
+ }
3986
+ const wrapCallableIds = (babelExpr, skipNode = null) => {
3987
+ const tempFile = t.file(t.program([t.expressionStatement(babelExpr)]));
3864
3988
  const toReplace = [];
3865
3989
  const shorthandToExpand = [];
3866
3990
  traverse(tempFile, {
3867
3991
  noScope: true,
3868
3992
  Identifier(path) {
3993
+ if (skipNode && path.node === skipNode) {
3994
+ return;
3995
+ }
3869
3996
  const parent = path.parent;
3870
3997
  const isMemberProp = (t.isMemberExpression(parent) || t.isOptionalMemberExpression(parent)) && parent.property === path.node && !parent.computed;
3871
3998
  const isObjectKey = t.isObjectProperty(parent) && parent.key === path.node && !parent.shorthand;
@@ -3884,13 +4011,17 @@ var MODIFIER_TRANSFORMATIONS = {
3884
4011
  prop.value = t.callExpression(t.identifier(name), []);
3885
4012
  });
3886
4013
  toReplace.forEach((p) => p.replaceWith(t.callExpression(t.identifier(p.node.name), [])));
3887
- const wrappedRightExpr = tempFile.program.body[0].expression;
3888
- if (assignment.kind === "state") {
4014
+ return tempFile.program.body[0].expression;
4015
+ };
4016
+ for (const processed of processedStatements) {
4017
+ if (processed.kind === "state") {
4018
+ const rightBabel = convertExpression2(processed.rightOddo);
4019
+ const wrappedRightExpr = wrapCallableIds(rightBabel);
3889
4020
  mutateBodyStmts.push(
3890
4021
  t.expressionStatement(
3891
4022
  t.assignmentExpression(
3892
4023
  "=",
3893
- t.identifier(assignment.name),
4024
+ t.identifier(processed.name),
3894
4025
  t.callExpression(
3895
4026
  t.identifier(modifierAliases["stateProxy"]),
3896
4027
  [wrappedRightExpr]
@@ -3898,25 +4029,59 @@ var MODIFIER_TRANSFORMATIONS = {
3898
4029
  )
3899
4030
  )
3900
4031
  );
3901
- } else {
4032
+ } else if (processed.kind === "mutable") {
4033
+ const rightBabel = convertExpression2(processed.rightOddo);
4034
+ const wrappedRightExpr = wrapCallableIds(rightBabel);
3902
4035
  mutateBodyStmts.push(
3903
4036
  t.expressionStatement(
3904
4037
  t.assignmentExpression(
3905
4038
  "=",
3906
- t.identifier(assignment.name),
4039
+ t.identifier(processed.name),
3907
4040
  wrappedRightExpr
3908
4041
  )
3909
4042
  )
3910
4043
  );
4044
+ } else if (processed.kind === "state-slice" || processed.kind === "mutable-slice") {
4045
+ const sliceAssignmentOddo = {
4046
+ type: "arraySliceAssignment",
4047
+ slice: processed.sliceOddo,
4048
+ value: processed.rightOddo
4049
+ };
4050
+ const sliceExpr = convertExpression2(sliceAssignmentOddo);
4051
+ const firstArg = sliceExpr.arguments[0];
4052
+ const wrappedSliceExpr = wrapCallableIds(sliceExpr, firstArg);
4053
+ mutateBodyStmts.push(t.expressionStatement(wrappedSliceExpr));
4054
+ } else if (processed.kind === "member") {
4055
+ const leftBabel = convertExpression2(processed.leftOddo);
4056
+ const rightBabel = convertExpression2(processed.rightOddo);
4057
+ const wrappedRightExpr = wrapCallableIds(rightBabel);
4058
+ mutateBodyStmts.push(
4059
+ t.expressionStatement(
4060
+ t.assignmentExpression("=", leftBabel, wrappedRightExpr)
4061
+ )
4062
+ );
4063
+ } else if (processed.kind === "regular") {
4064
+ const convertedStmt = convertStatement2(processed.stmtOddo);
4065
+ if (t.isVariableDeclaration(convertedStmt)) {
4066
+ for (const decl of convertedStmt.declarations) {
4067
+ if (decl.init) {
4068
+ decl.init = wrapCallableIds(decl.init);
4069
+ }
4070
+ }
4071
+ } else if (t.isExpressionStatement(convertedStmt)) {
4072
+ convertedStmt.expression = wrapCallableIds(convertedStmt.expression);
4073
+ }
4074
+ mutateBodyStmts.push(convertedStmt);
3911
4075
  }
3912
4076
  }
3913
4077
  currentScope = savedScopeMutate;
3914
- if (stateContainerNames.length > 0) {
4078
+ const stateNamesForFinalizer = Array.from(stateAssignmentsMap.entries()).filter(([_, info]) => info.kind === "state").map(([name, _]) => name);
4079
+ if (stateNamesForFinalizer.length > 0) {
3915
4080
  mutateBodyStmts.push(
3916
4081
  t.expressionStatement(
3917
4082
  t.callExpression(
3918
4083
  t.identifier("finalizer"),
3919
- stateContainerNames.map((n) => t.callExpression(t.identifier(n), []))
4084
+ stateNamesForFinalizer.map((n) => t.callExpression(t.identifier(n), []))
3920
4085
  )
3921
4086
  )
3922
4087
  );
@@ -3925,14 +4090,15 @@ var MODIFIER_TRANSFORMATIONS = {
3925
4090
  mutateParams,
3926
4091
  t.blockStatement(mutateBodyStmts)
3927
4092
  );
3928
- const finalizerParams = stateContainerNames.map((n) => t.identifier(n));
3929
- const finalizerCalls = stateAssignments.map(
3930
- (a) => t.callExpression(t.identifier(a.setter), [t.identifier(a.name)])
3931
- );
4093
+ const finalizerParams = stateNamesForFinalizer.map((n) => t.identifier(n));
4094
+ const finalizerCalls = stateNamesForFinalizer.map((name) => {
4095
+ const info = stateAssignmentsMap.get(name);
4096
+ return t.callExpression(t.identifier(info.setter), [t.identifier(name)]);
4097
+ });
3932
4098
  const finalizerBody = finalizerCalls.length === 0 ? t.identifier("undefined") : finalizerCalls.length === 1 ? finalizerCalls[0] : t.sequenceExpression(finalizerCalls);
3933
4099
  const finalizerFunc = t.arrowFunctionExpression(finalizerParams, finalizerBody);
3934
4100
  const stateContainersArray = t.arrayExpression(
3935
- stateContainerNames.map((n) => t.identifier(n))
4101
+ uniqueStateNames.map((n) => t.identifier(n))
3936
4102
  );
3937
4103
  const outerDepsArrayExpr = t.arrayExpression(
3938
4104
  outerDepsArray.map((n) => t.identifier(n))
@@ -4214,7 +4380,7 @@ function compileToJS(ast, config = {}) {
4214
4380
  moduleScope = null;
4215
4381
  currentScope = null;
4216
4382
  usedNames = collectOddoIdentifiers(ast);
4217
- const allImports = ["state", "computed", "mutate", "effect", "stateProxy", "lift", "liftFn", "e", "c", "x", "f"];
4383
+ const allImports = ["state", "computed", "mutate", "effect", "stateProxy", "arraySplice", "lift", "liftFn", "e", "c", "x", "f"];
4218
4384
  for (const name of allImports) {
4219
4385
  modifierAliases[name] = `__ODDO_IMPORT_${name}__`;
4220
4386
  }
@@ -4393,7 +4559,7 @@ function convertExpressionStatement2(stmt) {
4393
4559
  if (stmt.expression) {
4394
4560
  const isPlainExpr = stmt.expression.type !== "variableDeclaration" && stmt.expression.type !== "assignment" && stmt.expression.type !== "arraySliceAssignment";
4395
4561
  if (isPlainExpr) {
4396
- const allIdentifiers = collectOddoIdentifiersOnly(stmt.expression);
4562
+ const allIdentifiers = collectOddoIdentifiersOnly(stmt.expression, /* @__PURE__ */ new Set(), false, true);
4397
4563
  const reactiveDeps = allIdentifiers.filter((id) => isReactive(id));
4398
4564
  if (reactiveDeps.length > 0) {
4399
4565
  const savedScope = currentScope;
@@ -4666,20 +4832,23 @@ function convertReactiveContainer(expr) {
4666
4832
  currentScope = savedScope;
4667
4833
  return t.functionExpression(null, params, body);
4668
4834
  }
4669
- function collectOddoIdentifiersOnly(node, names = /* @__PURE__ */ new Set(), stopAtJsxExpressions = false) {
4835
+ function collectOddoIdentifiersOnly(node, names = /* @__PURE__ */ new Set(), stopAtJsxExpressions = false, stopAtArrowFunctions = false) {
4670
4836
  if (!node || typeof node !== "object") return Array.from(names);
4671
4837
  if (stopAtJsxExpressions && node.type === "jsxExpression") {
4672
4838
  return Array.from(names);
4673
4839
  }
4840
+ if (stopAtArrowFunctions && node.type === "arrowFunction") {
4841
+ return Array.from(names);
4842
+ }
4674
4843
  if (node.type === "identifier") {
4675
4844
  names.add(node.name);
4676
4845
  }
4677
4846
  if (node.type === "property") {
4678
4847
  if (node.computed && node.key) {
4679
- collectOddoIdentifiersOnly(node.key, names, stopAtJsxExpressions);
4848
+ collectOddoIdentifiersOnly(node.key, names, stopAtJsxExpressions, stopAtArrowFunctions);
4680
4849
  }
4681
4850
  if (node.value) {
4682
- collectOddoIdentifiersOnly(node.value, names, stopAtJsxExpressions);
4851
+ collectOddoIdentifiersOnly(node.value, names, stopAtJsxExpressions, stopAtArrowFunctions);
4683
4852
  }
4684
4853
  return Array.from(names);
4685
4854
  }
@@ -4687,9 +4856,9 @@ function collectOddoIdentifiersOnly(node, names = /* @__PURE__ */ new Set(), sto
4687
4856
  if (key === "type") continue;
4688
4857
  const val = node[key];
4689
4858
  if (Array.isArray(val)) {
4690
- val.forEach((item) => collectOddoIdentifiersOnly(item, names, stopAtJsxExpressions));
4859
+ val.forEach((item) => collectOddoIdentifiersOnly(item, names, stopAtJsxExpressions, stopAtArrowFunctions));
4691
4860
  } else if (val && typeof val === "object") {
4692
- collectOddoIdentifiersOnly(val, names, stopAtJsxExpressions);
4861
+ collectOddoIdentifiersOnly(val, names, stopAtJsxExpressions, stopAtArrowFunctions);
4693
4862
  }
4694
4863
  }
4695
4864
  return Array.from(names);
@@ -4839,7 +5008,10 @@ function convertAssignmentExpression(expr) {
4839
5008
  ">>>:=": ">>>=",
4840
5009
  "&:=": "&=",
4841
5010
  "^:=": "^=",
4842
- "|:=": "|="
5011
+ "|:=": "|=",
5012
+ "&&:=": "&&=",
5013
+ "||:=": "||=",
5014
+ "??:=": "??="
4843
5015
  };
4844
5016
  const operator = operatorMap[expr.operator] || expr.operator;
4845
5017
  return t.assignmentExpression(operator, left, right);
@@ -4883,16 +5055,11 @@ function convertArraySliceAssignment(expr) {
4883
5055
  t.memberExpression(spliceArgs, t.identifier("concat"), false),
4884
5056
  [value]
4885
5057
  );
4886
- const spliceMethod = t.memberExpression(
4887
- t.memberExpression(
4888
- t.memberExpression(t.identifier("Array"), t.identifier("prototype"), false),
4889
- t.identifier("splice"),
4890
- false
4891
- ),
4892
- t.identifier("apply"),
4893
- false
5058
+ usedModifiers.add("arraySplice");
5059
+ return t.callExpression(
5060
+ t.identifier(modifierAliases["arraySplice"]),
5061
+ [object, concatCall]
4894
5062
  );
4895
- return t.callExpression(spliceMethod, [object, concatCall]);
4896
5063
  }
4897
5064
  function convertArrayPattern(expr) {
4898
5065
  const elements = expr.elements.map((el) => {
@@ -5153,6 +5320,9 @@ var tokenClassMap = {
5153
5320
  "AndColonEqual": "operator",
5154
5321
  "OrColonEqual": "operator",
5155
5322
  "CaretColonEqual": "operator",
5323
+ "AndAndColonEqual": "operator",
5324
+ "OrOrColonEqual": "operator",
5325
+ "QuestionQuestionColonEqual": "operator",
5156
5326
  // JSX
5157
5327
  "JSXCloseTagStart": "tag",
5158
5328
  "JSXSelfClosing": "tag",