octane 0.5.0 → 0.6.0

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.
@@ -1580,6 +1580,7 @@ function ssrDeoptBlockChildren(children, scope) {
1580
1580
  return ssrChild(children, scope);
1581
1581
  }
1582
1582
  function serverDescNeedsBlocks(v) {
1583
+ if (typeof v === "function") return true;
1583
1584
  if (v == null || typeof v !== "object") return false;
1584
1585
  if (v.$$kind === import_runtime_tags.CONTEXT_TAG || typeof v.then === "function") return true;
1585
1586
  if (Array.isArray(v)) {
@@ -21,7 +21,7 @@ __export(version_exports, {
21
21
  version: () => version
22
22
  });
23
23
  module.exports = __toCommonJS(version_exports);
24
- const version = "0.5.0";
24
+ const version = "0.6.0";
25
25
  // Annotate the CommonJS export names for ESM import in node:
26
26
  0 && (module.exports = {
27
27
  version
@@ -449,7 +449,8 @@ function isTemplateNode(node) {
449
449
  node?.type === 'JSXForExpression' ||
450
450
  node?.type === 'JSXIfExpression' ||
451
451
  node?.type === 'JSXSwitchExpression' ||
452
- node?.type === 'JSXTryExpression'
452
+ node?.type === 'JSXTryExpression' ||
453
+ node?.type === 'JSXCodeBlock'
453
454
  );
454
455
  }
455
456
 
@@ -2756,7 +2757,12 @@ function rewriteSourceAst(node, state) {
2756
2757
  }
2757
2758
  const replacement = state.astNodeReplacements?.get(value);
2758
2759
  if (replacement !== undefined) return replacement;
2759
- if (value !== node && isTemplateNode(value)) {
2760
+ // A template node in expression position — nested or the root itself
2761
+ // (JSX as a component prop, a sole expression child, a renderable hole) —
2762
+ // is a value and needs renderable lowering. Passing the root through
2763
+ // leaves raw JSX for DOM codegen, which emits descriptor-runtime helpers
2764
+ // the universal module does not export.
2765
+ if (isTemplateNode(value)) {
2760
2766
  return compileRenderableExpressionAst(value, state);
2761
2767
  }
2762
2768
  let output = null;
@@ -3296,19 +3302,24 @@ function compileBlockValueAst(statements, state, params = [], origin = null) {
3296
3302
  const templates = [];
3297
3303
  const setup = [];
3298
3304
  for (const statement of statements ?? []) {
3305
+ // Inside a BlockStatement the parser wraps JSX-producing nodes like
3306
+ // `@{ … }` in an ExpressionStatement; unwrap it for the template/setup
3307
+ // partition while keeping the statement for setup output.
3308
+ const inner = statement.type === 'ExpressionStatement' ? statement.expression : statement;
3299
3309
  if (
3300
- statement.type === 'JSXElement' ||
3301
- statement.type === 'Element' ||
3302
- statement.type === 'JSXFragment' ||
3303
- statement.type === 'Fragment' ||
3304
- statement.type === 'JSXText' ||
3305
- statement.type === 'JSXExpressionContainer' ||
3306
- statement.type === 'JSXForExpression' ||
3307
- statement.type === 'JSXIfExpression' ||
3308
- statement.type === 'JSXSwitchExpression' ||
3309
- statement.type === 'JSXTryExpression'
3310
+ inner.type === 'JSXElement' ||
3311
+ inner.type === 'Element' ||
3312
+ inner.type === 'JSXFragment' ||
3313
+ inner.type === 'Fragment' ||
3314
+ inner.type === 'JSXText' ||
3315
+ inner.type === 'JSXExpressionContainer' ||
3316
+ inner.type === 'JSXForExpression' ||
3317
+ inner.type === 'JSXIfExpression' ||
3318
+ inner.type === 'JSXSwitchExpression' ||
3319
+ inner.type === 'JSXTryExpression' ||
3320
+ inner.type === 'JSXCodeBlock'
3310
3321
  ) {
3311
- templates.push(...compileChildAst(statement, context, state));
3322
+ templates.push(...compileChildAst(inner, context, state));
3312
3323
  } else {
3313
3324
  setup.push(statement);
3314
3325
  }
@@ -3612,6 +3623,14 @@ function compileChildAst(node, context, state) {
3612
3623
  }
3613
3624
  if (node.type === 'JSXExpressionContainer') {
3614
3625
  if (!node.expression || node.expression.type === 'JSXEmptyExpression') return [];
3626
+ // `{() => @{ … }}` is the explicit scoped child — it lowers to the same
3627
+ // scoped block as bare `@{ … }`, keeping the arrow's parameters.
3628
+ if (
3629
+ node.expression.type === 'ArrowFunctionExpression' &&
3630
+ node.expression.body?.type === 'JSXCodeBlock'
3631
+ ) {
3632
+ return compileCodeBlockAst(node.expression.body, node.expression.params, context, state);
3633
+ }
3615
3634
  // A string-literal child is authored text with braces around it: fold it
3616
3635
  // into the plan like JSXText, so the constant stops riding every render's
3617
3636
  // slot array. Renderers without host text keep the renderable-hole slot.
@@ -3639,6 +3658,7 @@ function compileChildAst(node, context, state) {
3639
3658
  if (node.type === 'JSXIfExpression') return [compileIfAst(node, context, state)];
3640
3659
  if (node.type === 'JSXSwitchExpression') return [compileSwitchAst(node, context, state)];
3641
3660
  if (node.type === 'JSXTryExpression') return [compileTryAst(node, context, state)];
3661
+ if (node.type === 'JSXCodeBlock') return compileCodeBlockAst(node, [], context, state);
3642
3662
  if (node.type === 'JSXStyleElement') {
3643
3663
  throw universalError(
3644
3664
  state.filename,
@@ -3658,6 +3678,37 @@ function compileChildrenAst(children, context, state) {
3658
3678
  return output;
3659
3679
  }
3660
3680
 
3681
+ // `@{ … }` at child position: an empty block contributes nothing, a
3682
+ // render-only block merges into the parent template, and a setup-bearing or
3683
+ // code-only block lowers to a scoped dynamic child whose thunk runs its
3684
+ // statements inside a persistent child owner — the universal counterpart of
3685
+ // the DOM childSlot lowering for JSXCodeBlock. The explicit `{() => @{ … }}`
3686
+ // spelling always keeps its scope: its parameters bind inside the thunk.
3687
+ function compileCodeBlockAst(block, params, context, state) {
3688
+ const body = block.body ?? [];
3689
+ const render = block.render ?? null;
3690
+ if (body.length === 0 && params.length === 0) {
3691
+ return render === null ? [] : compileChildAst(render, context, state);
3692
+ }
3693
+ return [
3694
+ addDynamicAst(
3695
+ context,
3696
+ generatedCall(
3697
+ state.helpers.block,
3698
+ [
3699
+ compileBlockValueAst(
3700
+ [...body, ...(render === null ? [] : [render])],
3701
+ state,
3702
+ params,
3703
+ block,
3704
+ ),
3705
+ ],
3706
+ block,
3707
+ ),
3708
+ ),
3709
+ ];
3710
+ }
3711
+
3661
3712
  function extractEntryParallelUsesAst(expression, state) {
3662
3713
  const useAliases = new Set(
3663
3714
  [...state.runtimeImports].filter(([, imported]) => imported === 'use').map(([local]) => local),
@@ -3875,6 +3926,7 @@ function universalHelperImportAsts(state, extraPairs = [], origin = null) {
3875
3926
  ['universalChildren', state.helpers.children],
3876
3927
  ['universalContext', state.helpers.context],
3877
3928
  ['universalActivity', state.helpers.activity],
3929
+ ['universalBlock', state.helpers.block],
3878
3930
  ...(state.helpers.firstScreenEvent === undefined
3879
3931
  ? []
3880
3932
  : [['firstScreenEvent', state.helpers.firstScreenEvent]]),
@@ -4239,6 +4291,7 @@ export function lowerUniversalRendererRegionAst(
4239
4291
  state.helpers.children = allocName(state, `${prefix}Children`);
4240
4292
  state.helpers.context = allocName(state, `${prefix}Context`);
4241
4293
  state.helpers.activity = allocName(state, `${prefix}Activity`);
4294
+ state.helpers.block = allocName(state, `${prefix}Block`);
4242
4295
  const generatedRuntimeAliases = Object.freeze(
4243
4296
  Object.fromEntries(
4244
4297
  [
@@ -4464,6 +4517,7 @@ export function lowerUniversalRendererRegionAst(
4464
4517
  try: state.helpers.try,
4465
4518
  context: state.helpers.context,
4466
4519
  activity: state.helpers.activity,
4520
+ block: state.helpers.block,
4467
4521
  }),
4468
4522
  components: Object.freeze(state.components),
4469
4523
  bindings: Object.freeze([...specializationBindings]),
@@ -4553,6 +4607,7 @@ export function compileUniversal(
4553
4607
  state.helpers.children = allocName(state, '__octaneUniversalChildren');
4554
4608
  state.helpers.context = allocName(state, '__octaneUniversalContext');
4555
4609
  state.helpers.activity = allocName(state, '__octaneUniversalActivity');
4610
+ state.helpers.block = allocName(state, '__octaneUniversalBlock');
4556
4611
  if (state.hmr) {
4557
4612
  state.helpers.hmr = allocName(state, '__octaneUniversalHmr');
4558
4613
  state.helpers.hmrSymbol = allocName(state, '__octaneUniversalHmrSymbol');
@@ -4606,6 +4661,7 @@ export function compileUniversal(
4606
4661
  try: state.helpers.try,
4607
4662
  context: state.helpers.context,
4608
4663
  activity: state.helpers.activity,
4664
+ block: state.helpers.block,
4609
4665
  },
4610
4666
  components: state.components,
4611
4667
  };
@@ -16856,6 +16856,7 @@ function transformUniversalParallelUse(ast, ctx, metadata) {
16856
16856
  else if (name === regions.switch) thunkIndexes = [1, 2];
16857
16857
  else if (name === regions.for) thunkIndexes = [2, 3];
16858
16858
  else if (name === regions.try) thunkIndexes = [0, 1, 2];
16859
+ else if (name === regions.block) thunkIndexes = [0];
16859
16860
  if (thunkIndexes !== null) {
16860
16861
  for (const index of thunkIndexes) transformThunkValue(node.arguments?.[index], ownerName);
16861
16862
  for (let index = 0; index < (node.arguments?.length || 0); index++) {
@@ -46,11 +46,11 @@
46
46
  * `JSXElement`: it is not a block, opens no scope, and is never stamped.
47
47
  * - Assigned blocks (`const theme = <style>…</style>`) lower anywhere a
48
48
  * declaration is legal: their sheet injects at the declaration position and
49
- * the initializer becomes the class-map object (`$class` first). Exported or
50
- * applied blocks are themes and keep every selector; other blocks keep only
51
- * what the class map exposes. The classification comes from the core
52
- * analyzer (`metadata.styleKind`, `metadata.styleApplies`), which runs on
53
- * the parser AST before it is adopted, so this pass reads it read-only.
49
+ * the initializer becomes the class-map object (`$class` first). Every
50
+ * assigned block is a theme and keeps every selector. The classification
51
+ * comes from the core analyzer (`metadata.styleKind`, `metadata.styleApplies`),
52
+ * which runs on the parser AST before it is adopted, so this pass reads it
53
+ * read-only.
54
54
  * - `style(expr)` is Octane's class-string expression (core has no such
55
55
  * intrinsic): it resolves to the scope chain plus the value only where TSRX
56
56
  * reads a class value — as the expression of a JSX attribute value or of a
@@ -69,7 +69,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
69
69
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
70
70
  SOFTWARE.
71
71
 
72
- @tsrx/core@0.3.2
72
+ @tsrx/core@0.4.0
73
73
 
74
74
  MIT License
75
75
 
@@ -93,7 +93,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
93
93
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
94
94
  SOFTWARE.
95
95
 
96
- acorn@8.17.0
96
+ acorn@8.18.0
97
97
 
98
98
  MIT License
99
99