@oddo/lang 0.0.7 → 0.0.8

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
@@ -3586,71 +3586,6 @@ var traverse = _traverse3.default.default || _traverse3.default;
3586
3586
  function isValidJSIdentifier(name) {
3587
3587
  return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
3588
3588
  }
3589
- function extractIdentifiers(babelNode) {
3590
- const identifiers = /* @__PURE__ */ new Set();
3591
- const locals = /* @__PURE__ */ new Set();
3592
- function traverse2(node) {
3593
- var _a, _b, _c;
3594
- if (!node) return;
3595
- if (t.isIdentifier(node)) {
3596
- if (!locals.has(node.name) && !node.name.startsWith("__ODDO_IMPORT_")) {
3597
- identifiers.add(node.name);
3598
- }
3599
- } else if (t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) {
3600
- traverse2(node.object);
3601
- if (node.computed) traverse2(node.property);
3602
- } else if (t.isCallExpression(node) || t.isOptionalCallExpression(node)) {
3603
- traverse2(node.callee);
3604
- (_a = node.arguments) == null ? void 0 : _a.forEach((arg) => traverse2(arg));
3605
- } else if (t.isBinaryExpression(node) || t.isLogicalExpression(node)) {
3606
- traverse2(node.left);
3607
- traverse2(node.right);
3608
- } else if (t.isUnaryExpression(node)) {
3609
- traverse2(node.argument);
3610
- } else if (t.isConditionalExpression(node)) {
3611
- traverse2(node.test);
3612
- traverse2(node.consequent);
3613
- traverse2(node.alternate);
3614
- } else if (t.isArrayExpression(node)) {
3615
- (_b = node.elements) == null ? void 0 : _b.forEach((el) => traverse2(el));
3616
- } else if (t.isObjectExpression(node)) {
3617
- (_c = node.properties) == null ? void 0 : _c.forEach((prop) => {
3618
- if (t.isObjectProperty(prop)) {
3619
- if (prop.computed) traverse2(prop.key);
3620
- traverse2(prop.value);
3621
- } else if (t.isSpreadElement(prop)) {
3622
- traverse2(prop.argument);
3623
- }
3624
- });
3625
- } else if (t.isArrowFunctionExpression(node)) {
3626
- node.params.forEach((p) => {
3627
- var _a2;
3628
- if (t.isIdentifier(p)) locals.add(p.name);
3629
- else if (t.isObjectPattern(p)) p.properties.forEach((prop) => t.isIdentifier(prop.value) && locals.add(prop.value.name));
3630
- else if (t.isArrayPattern(p)) (_a2 = p.elements) == null ? void 0 : _a2.forEach((el) => t.isIdentifier(el) && locals.add(el.name));
3631
- });
3632
- if (t.isBlockStatement(node.body)) node.body.body.forEach((s) => traverse2(s));
3633
- else traverse2(node.body);
3634
- } else if (t.isBlockStatement(node)) {
3635
- node.body.forEach((s) => traverse2(s));
3636
- } else if (t.isExpressionStatement(node)) {
3637
- traverse2(node.expression);
3638
- } else if (t.isReturnStatement(node)) {
3639
- traverse2(node.argument);
3640
- } else if (t.isSequenceExpression(node)) {
3641
- node.expressions.forEach((expr) => traverse2(expr));
3642
- } else if (t.isUpdateExpression(node)) {
3643
- traverse2(node.argument);
3644
- } else if (t.isAssignmentExpression(node)) {
3645
- traverse2(node.left);
3646
- traverse2(node.right);
3647
- } else if (t.isSpreadElement(node)) {
3648
- traverse2(node.argument);
3649
- }
3650
- }
3651
- traverse2(babelNode);
3652
- return Array.from(identifiers);
3653
- }
3654
3589
  function wrapDependenciesWithCalls(arrowFunc, deps) {
3655
3590
  const depSet = new Set(deps);
3656
3591
  const locals = /* @__PURE__ */ new Set();
@@ -3734,9 +3669,9 @@ function createLiftedExpr(valueExpr, identifiers) {
3734
3669
  [arrowFunc, t.arrayExpression(depsArray)]
3735
3670
  );
3736
3671
  }
3737
- function createReactiveExpr(valueExpr, attrExpression = false) {
3738
- const allIdentifiers = extractIdentifiers(valueExpr);
3739
- const identifiers = getReactiveDeps(allIdentifiers);
3672
+ function createReactiveExpr(oddoExpr, valueExpr, attrExpression = false) {
3673
+ const allIdentifiers = collectOddoIdentifiersOnly(oddoExpr);
3674
+ const identifiers = allIdentifiers.filter((id) => isReactive(id));
3740
3675
  const pragma = attrExpression ? "computed" : "x";
3741
3676
  if (identifiers.length === 0) {
3742
3677
  if (t.isLiteral(valueExpr)) {
@@ -3789,9 +3724,11 @@ var MODIFIER_TRANSFORMATIONS = {
3789
3724
  computed: {
3790
3725
  needsImport: true,
3791
3726
  // @computed sum = x + y -> const sum = _computed((x, y) => x() + y(), [x, y])
3792
- transform: (valueExpr, leftExpr) => {
3793
- const allIds = extractIdentifiers(valueExpr);
3794
- const identifiers = getReactiveDeps(allIds);
3727
+ // Receives Oddo AST, extracts deps from Oddo, converts internally
3728
+ transform: (oddoExpr, leftExpr) => {
3729
+ const allIds = collectOddoIdentifiersOnly(oddoExpr);
3730
+ const identifiers = allIds.filter((id) => isReactive(id));
3731
+ const valueExpr = convertExpression2(oddoExpr);
3795
3732
  const params = identifiers.map((id) => t.identifier(id));
3796
3733
  const deps = identifiers.map((id) => t.identifier(id));
3797
3734
  const arrowFunc = t.arrowFunctionExpression(params, valueExpr);
@@ -3808,28 +3745,6 @@ var MODIFIER_TRANSFORMATIONS = {
3808
3745
  return t.expressionStatement(computedCall);
3809
3746
  }
3810
3747
  },
3811
- react: {
3812
- needsImport: true,
3813
- // @react sum = x + y -> const sum = _react((x, y) => x() + y(), [x, y])
3814
- transform: (valueExpr, leftExpr) => {
3815
- const allIds = extractIdentifiers(valueExpr);
3816
- const identifiers = getReactiveDeps(allIds);
3817
- const params = identifiers.map((id) => t.identifier(id));
3818
- const deps = identifiers.map((id) => t.identifier(id));
3819
- const arrowFunc = t.arrowFunctionExpression(params, valueExpr);
3820
- wrapDependenciesWithCalls(arrowFunc, identifiers);
3821
- const reactCall = t.callExpression(
3822
- t.identifier(modifierAliases["react"]),
3823
- [arrowFunc, t.arrayExpression(deps)]
3824
- );
3825
- if (leftExpr) {
3826
- return t.variableDeclaration("const", [
3827
- t.variableDeclarator(leftExpr, reactCall)
3828
- ]);
3829
- }
3830
- return t.expressionStatement(reactCall);
3831
- }
3832
- },
3833
3748
  mutate: {
3834
3749
  needsImport: true,
3835
3750
  // @mutate x = (arg1, arg2) => { x1 := value1; x2 := value2 }
@@ -4028,16 +3943,52 @@ var MODIFIER_TRANSFORMATIONS = {
4028
3943
  needsImport: false,
4029
3944
  // @mutable x = 3 -> let x = 3;
4030
3945
  // @mutable x = y + 1 (y is @state) -> let x = _lift((y) => y() + 1, [y])
4031
- transform: (valueExpr, leftExpr) => {
3946
+ // Receives Oddo AST, extracts deps from Oddo, converts internally
3947
+ transform: (oddoExpr, leftExpr) => {
4032
3948
  if (leftExpr && t.isIdentifier(leftExpr)) {
4033
3949
  mutableVariables.add(leftExpr.name);
4034
- const identifiers = extractIdentifiers(valueExpr);
3950
+ const identifiers = collectOddoIdentifiersOnly(oddoExpr);
3951
+ const valueExpr = convertExpression2(oddoExpr);
4035
3952
  const liftedExpr = createLiftedExpr(valueExpr, identifiers);
4036
3953
  return t.variableDeclaration("let", [
4037
3954
  t.variableDeclarator(leftExpr, liftedExpr || valueExpr)
4038
3955
  ]);
4039
3956
  }
4040
- return t.expressionStatement(valueExpr);
3957
+ return t.expressionStatement(convertExpression2(oddoExpr));
3958
+ }
3959
+ },
3960
+ component: {
3961
+ needsImport: false,
3962
+ // @component Counter = (props) => { ... } -> const Counter = function(props) { ... }
3963
+ // Parameters are treated as reactive, no _liftFn wrapping, compiles to regular function
3964
+ transform: (oddoExpr, leftExpr) => {
3965
+ if (oddoExpr.type !== "arrowFunction") {
3966
+ throw new Error("@component modifier must be applied to an arrow function");
3967
+ }
3968
+ const funcExpr = convertReactiveContainer(oddoExpr);
3969
+ if (leftExpr && t.isIdentifier(leftExpr)) {
3970
+ return t.variableDeclaration("const", [
3971
+ t.variableDeclarator(leftExpr, funcExpr)
3972
+ ]);
3973
+ }
3974
+ return t.expressionStatement(funcExpr);
3975
+ }
3976
+ },
3977
+ hook: {
3978
+ needsImport: false,
3979
+ // @hook useCounter = (initial) => { ... } -> const useCounter = function(initial) { ... }
3980
+ // Parameters are treated as reactive, no _liftFn wrapping, compiles to regular function
3981
+ transform: (oddoExpr, leftExpr) => {
3982
+ if (oddoExpr.type !== "arrowFunction") {
3983
+ throw new Error("@hook modifier must be applied to an arrow function");
3984
+ }
3985
+ const funcExpr = convertReactiveContainer(oddoExpr);
3986
+ if (leftExpr && t.isIdentifier(leftExpr)) {
3987
+ return t.variableDeclaration("const", [
3988
+ t.variableDeclarator(leftExpr, funcExpr)
3989
+ ]);
3990
+ }
3991
+ return t.expressionStatement(funcExpr);
4041
3992
  }
4042
3993
  }
4043
3994
  };
@@ -4197,7 +4148,7 @@ function compileToJS(ast, config = {}) {
4197
4148
  moduleScope = null;
4198
4149
  currentScope = null;
4199
4150
  usedNames = collectOddoIdentifiers(ast);
4200
- const allImports = ["state", "computed", "react", "mutate", "effect", "stateProxy", "lift", "liftFn", "e", "c", "x", "f"];
4151
+ const allImports = ["state", "computed", "mutate", "effect", "stateProxy", "lift", "liftFn", "e", "c", "x", "f"];
4201
4152
  for (const name of allImports) {
4202
4153
  modifierAliases[name] = `__ODDO_IMPORT_${name}__`;
4203
4154
  }
@@ -4297,13 +4248,13 @@ function convertExpressionStatement2(stmt) {
4297
4248
  let leftExpr = null;
4298
4249
  if (stmt.expression.type === "variableDeclaration" || stmt.expression.type === "assignment") {
4299
4250
  leftExpr = convertExpression2(stmt.expression.left);
4300
- if (stmt.modifier === "mutate" || stmt.modifier === "effect") {
4251
+ if (stmt.modifier === "mutate" || stmt.modifier === "effect" || stmt.modifier === "computed" || stmt.modifier === "mutable" || stmt.modifier === "component" || stmt.modifier === "hook") {
4301
4252
  valueExpr = stmt.expression.right;
4302
4253
  } else {
4303
4254
  valueExpr = convertExpression2(stmt.expression.right);
4304
4255
  }
4305
4256
  } else {
4306
- if (stmt.modifier === "mutate" || stmt.modifier === "effect") {
4257
+ if (stmt.modifier === "mutate" || stmt.modifier === "effect" || stmt.modifier === "computed" || stmt.modifier === "mutable" || stmt.modifier === "component" || stmt.modifier === "hook") {
4307
4258
  valueExpr = stmt.expression;
4308
4259
  } else {
4309
4260
  valueExpr = convertExpression2(stmt.expression);
@@ -4324,13 +4275,13 @@ function convertExpressionStatement2(stmt) {
4324
4275
  let leftExpr = null;
4325
4276
  if (blockStmt.expression.type === "variableDeclaration" || blockStmt.expression.type === "assignment") {
4326
4277
  leftExpr = convertExpression2(blockStmt.expression.left);
4327
- if (stmt.modifier === "mutate" || stmt.modifier === "effect") {
4278
+ if (stmt.modifier === "mutate" || stmt.modifier === "effect" || stmt.modifier === "computed" || stmt.modifier === "mutable" || stmt.modifier === "component" || stmt.modifier === "hook") {
4328
4279
  valueExpr = blockStmt.expression.right;
4329
4280
  } else {
4330
4281
  valueExpr = convertExpression2(blockStmt.expression.right);
4331
4282
  }
4332
4283
  } else {
4333
- if (stmt.modifier === "mutate" || stmt.modifier === "effect") {
4284
+ if (stmt.modifier === "mutate" || stmt.modifier === "effect" || stmt.modifier === "computed" || stmt.modifier === "mutable" || stmt.modifier === "component" || stmt.modifier === "hook") {
4334
4285
  valueExpr = blockStmt.expression;
4335
4286
  } else {
4336
4287
  valueExpr = convertExpression2(blockStmt.expression);
@@ -4349,11 +4300,18 @@ function convertExpressionStatement2(stmt) {
4349
4300
  }
4350
4301
  if (stmt.expression && stmt.expression.type === "variableDeclaration") {
4351
4302
  const left = convertExpression2(stmt.expression.left);
4352
- const right = convertExpression2(stmt.expression.right);
4353
- const identifiers = extractIdentifiers(right);
4354
- const liftedExpr = createLiftedExpr(right, identifiers);
4303
+ const oddoRight = stmt.expression.right;
4304
+ const right = convertExpression2(oddoRight);
4305
+ let finalExpr = right;
4306
+ if (oddoRight.type !== "arrowFunction") {
4307
+ const identifiers = collectOddoIdentifiersOnly(oddoRight);
4308
+ const liftedExpr = createLiftedExpr(right, identifiers);
4309
+ if (liftedExpr) {
4310
+ finalExpr = liftedExpr;
4311
+ }
4312
+ }
4355
4313
  return t.variableDeclaration("const", [
4356
- t.variableDeclarator(left, liftedExpr || right)
4314
+ t.variableDeclarator(left, finalExpr)
4357
4315
  ]);
4358
4316
  }
4359
4317
  let expression = null;
@@ -4553,6 +4511,58 @@ function convertArrowFunction2(expr) {
4553
4511
  }
4554
4512
  return t.arrowFunctionExpression(params, body);
4555
4513
  }
4514
+ function convertReactiveContainer(expr) {
4515
+ var _a;
4516
+ const savedScope = currentScope;
4517
+ if (expr._scope) {
4518
+ currentScope = expr._scope;
4519
+ } else {
4520
+ currentScope = Object.create(savedScope);
4521
+ }
4522
+ for (const param of expr.parameters || []) {
4523
+ if (param.name) {
4524
+ currentScope[param.name] = { type: "param", reactive: true };
4525
+ } else if (param.type === "destructuringPattern") {
4526
+ const boundNames = extractBoundNames(param.pattern);
4527
+ for (const name of boundNames) {
4528
+ currentScope[name] = { type: "param", reactive: true };
4529
+ }
4530
+ } else if (param.type === "restElement" && ((_a = param.argument) == null ? void 0 : _a.name)) {
4531
+ currentScope[param.argument.name] = { type: "param", reactive: true };
4532
+ }
4533
+ }
4534
+ const params = (expr.parameters || []).map((param) => {
4535
+ if (param.type === "restElement") {
4536
+ return t.restElement(convertExpression2(param.argument));
4537
+ }
4538
+ if (param.type === "destructuringPattern") {
4539
+ const pattern = convertExpression2(param.pattern);
4540
+ if (param.default) {
4541
+ return t.assignmentPattern(pattern, convertExpression2(param.default));
4542
+ }
4543
+ return pattern;
4544
+ }
4545
+ if (param.type === "parameter") {
4546
+ const paramId = t.identifier(param.name);
4547
+ if (param.default) {
4548
+ return t.assignmentPattern(paramId, convertExpression2(param.default));
4549
+ }
4550
+ return paramId;
4551
+ }
4552
+ return convertExpression2(param);
4553
+ });
4554
+ let body;
4555
+ if (expr.body && expr.body.type === "blockStatement") {
4556
+ const statements = expr.body.body.map((stmt) => convertStatement2(stmt));
4557
+ body = t.blockStatement(statements);
4558
+ } else if (expr.body) {
4559
+ body = t.blockStatement([t.returnStatement(convertExpression2(expr.body))]);
4560
+ } else {
4561
+ body = t.blockStatement([]);
4562
+ }
4563
+ currentScope = savedScope;
4564
+ return t.functionExpression(null, params, body);
4565
+ }
4556
4566
  function collectOddoIdentifiersOnly(node, names = /* @__PURE__ */ new Set()) {
4557
4567
  if (!node || typeof node !== "object") return Array.from(names);
4558
4568
  if (node.type === "identifier") {
@@ -4812,7 +4822,7 @@ function convertJSXChild2(child) {
4812
4822
  return t.stringLiteral(text);
4813
4823
  } else if (child.type === "jsxExpression") {
4814
4824
  const innerExpr = convertExpression2(child.expression);
4815
- return createReactiveExpr(innerExpr);
4825
+ return createReactiveExpr(child.expression, innerExpr);
4816
4826
  } else if (child.type === "jsxElement") {
4817
4827
  return convertJSXElement2(child);
4818
4828
  } else if (child.type === "jsxFragment") {
@@ -4829,9 +4839,11 @@ function convertJSXElement2(expr) {
4829
4839
  let propsArg;
4830
4840
  if (hasSpread) {
4831
4841
  const properties = [];
4842
+ const oddoExprs = [];
4832
4843
  for (const attr of expr.attributes) {
4833
4844
  if (attr.type === "jsxSpread") {
4834
4845
  properties.push(t.spreadElement(convertExpression2(attr.expression)));
4846
+ oddoExprs.push(attr.expression);
4835
4847
  } else {
4836
4848
  const key = isValidJSIdentifier(attr.name) ? t.identifier(attr.name) : t.stringLiteral(attr.name);
4837
4849
  let value;
@@ -4841,14 +4853,17 @@ function convertJSXElement2(expr) {
4841
4853
  value = t.stringLiteral(attr.value.value);
4842
4854
  } else if (attr.value.type === "expression") {
4843
4855
  value = convertExpression2(attr.value.value);
4856
+ oddoExprs.push(attr.value.value);
4844
4857
  } else {
4845
4858
  value = convertExpression2(attr.value);
4859
+ oddoExprs.push(attr.value);
4846
4860
  }
4847
4861
  properties.push(t.objectProperty(key, value));
4848
4862
  }
4849
4863
  }
4850
4864
  const propsObj = t.objectExpression(properties);
4851
- propsArg = createReactiveExpr(propsObj, true);
4865
+ const syntheticOddo = { type: "array", elements: oddoExprs };
4866
+ propsArg = createReactiveExpr(syntheticOddo, propsObj, true);
4852
4867
  } else if (expr.attributes.length === 0) {
4853
4868
  propsArg = t.nullLiteral();
4854
4869
  } else {
@@ -4862,10 +4877,10 @@ function convertJSXElement2(expr) {
4862
4877
  value = t.stringLiteral(attr.value.value);
4863
4878
  } else if (attr.value.type === "expression") {
4864
4879
  const innerExpr = convertExpression2(attr.value.value);
4865
- value = createReactiveExpr(innerExpr, true);
4880
+ value = createReactiveExpr(attr.value.value, innerExpr, true);
4866
4881
  } else {
4867
4882
  const innerExpr = convertExpression2(attr.value);
4868
- value = createReactiveExpr(innerExpr, true);
4883
+ value = createReactiveExpr(attr.value, innerExpr, true);
4869
4884
  }
4870
4885
  properties.push(t.objectProperty(key, value));
4871
4886
  }