@neocompose/cli 0.61.2 → 0.61.4

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/neo.mjs CHANGED
@@ -5112,8 +5112,8 @@ function pathRoot(path) {
5112
5112
  const dot = path.indexOf(".");
5113
5113
  return dot === -1 ? path : path.slice(0, dot);
5114
5114
  }
5115
- function factsFromIsCheck(expression, whenTrue) {
5116
- const path = canonicalPath(expression.operand);
5115
+ function factsFromIsCheck(expression, whenTrue, pathOf) {
5116
+ const path = pathOf(expression.operand);
5117
5117
  const nullCheck = expression.type.kind === "primitive" && expression.type.name === "null";
5118
5118
  if (path === null && (!whenTrue || nullCheck || !expression.bindingName)) {
5119
5119
  return [];
@@ -5137,58 +5137,72 @@ function extractNullCheckSide(expression) {
5137
5137
  if (!leftNull && !rightNull) return null;
5138
5138
  return leftNull ? expression.right : expression.left;
5139
5139
  }
5140
- function factsWhenTrue(expression) {
5141
- if (expression.kind === "is") return factsFromIsCheck(expression, true);
5140
+ function pathsAfterBindings(pathOf, facts) {
5141
+ const bindings = new Set(
5142
+ facts.flatMap((fact) => fact.bindingName ? [fact.bindingName] : [])
5143
+ );
5144
+ if (bindings.size === 0) return pathOf;
5145
+ return (expression) => {
5146
+ const path = canonicalPath(expression);
5147
+ return path !== null && bindings.has(pathRoot(path)) ? path : pathOf(expression);
5148
+ };
5149
+ }
5150
+ function factsWhenTrue(expression, pathOf) {
5151
+ if (expression.kind === "is")
5152
+ return factsFromIsCheck(expression, true, pathOf);
5142
5153
  if (expression.kind === "binary") {
5143
5154
  if (expression.op === "&&") {
5155
+ const left = factsWhenTrue(expression.left, pathOf);
5144
5156
  return [
5145
- ...factsWhenTrue(expression.left),
5146
- ...factsWhenTrue(expression.right)
5157
+ ...left,
5158
+ ...factsWhenTrue(expression.right, pathsAfterBindings(pathOf, left))
5147
5159
  ];
5148
5160
  }
5149
5161
  if (expression.op === "||") {
5150
5162
  return mergeFactSets([
5151
- factsWhenTrue(expression.left),
5152
- factsWhenTrue(expression.right)
5163
+ factsWhenTrue(expression.left, pathOf),
5164
+ factsWhenTrue(expression.right, pathOf)
5153
5165
  ]);
5154
5166
  }
5155
5167
  if (expression.op === "==" || expression.op === "!=") {
5156
5168
  const value = extractNullCheckSide(expression);
5157
- const path2 = value ? canonicalPath(value) : null;
5169
+ const path2 = value ? pathOf(value) : null;
5158
5170
  return value && path2 ? [{ expression: value, path: path2, nullValue: expression.op === "==" }] : [];
5159
5171
  }
5160
5172
  }
5161
5173
  if (expression.kind === "unary" && expression.op === "!") {
5162
- return factsWhenFalse(expression.operand);
5174
+ return factsWhenFalse(expression.operand, pathOf);
5163
5175
  }
5164
- const path = canonicalPath(expression);
5176
+ const path = pathOf(expression);
5165
5177
  return path && (expression.kind === "ident" || expression.kind === "member") ? [{ expression, path, nullValue: false, loose: true }] : [];
5166
5178
  }
5167
- function factsWhenFalse(expression) {
5168
- if (expression.kind === "is") return factsFromIsCheck(expression, false);
5179
+ function factsWhenFalse(expression, pathOf) {
5180
+ if (expression.kind === "is")
5181
+ return factsFromIsCheck(expression, false, pathOf);
5169
5182
  if (expression.kind === "binary") {
5170
5183
  if (expression.op === "||") {
5184
+ const left = factsWhenFalse(expression.left, pathOf);
5171
5185
  return [
5172
- ...factsWhenFalse(expression.left),
5173
- ...factsWhenFalse(expression.right)
5186
+ ...left,
5187
+ ...factsWhenFalse(expression.right, pathsAfterBindings(pathOf, left))
5174
5188
  ];
5175
5189
  }
5176
5190
  if (expression.op === "&&") {
5177
5191
  return mergeFactSets([
5178
- factsWhenFalse(expression.left),
5179
- factsWhenFalse(expression.right)
5192
+ factsWhenFalse(expression.left, pathOf),
5193
+ factsWhenFalse(expression.right, pathOf)
5180
5194
  ]);
5181
5195
  }
5182
5196
  if (expression.op === "==" || expression.op === "!=") {
5183
5197
  const value = extractNullCheckSide(expression);
5184
- const path2 = value ? canonicalPath(value) : null;
5198
+ const path2 = value ? pathOf(value) : null;
5185
5199
  return value && path2 ? [{ expression: value, path: path2, nullValue: expression.op !== "==" }] : [];
5186
5200
  }
5187
5201
  }
5188
5202
  if (expression.kind === "unary" && expression.op === "!") {
5189
- return factsWhenTrue(expression.operand);
5203
+ return factsWhenTrue(expression.operand, pathOf);
5190
5204
  }
5191
- const path = canonicalPath(expression);
5205
+ const path = pathOf(expression);
5192
5206
  return path && (expression.kind === "ident" || expression.kind === "member") ? [{ expression, path, nullValue: true, loose: true }] : [];
5193
5207
  }
5194
5208
  function mergeFactSets(sets) {
@@ -5350,156 +5364,440 @@ function scopeVariable(name, value, sourceType, writability, ownership, writeRoo
5350
5364
  ...readonlyBinding ? { readonlyBinding } : {}
5351
5365
  };
5352
5366
  }
5353
- function invalidateLoopEntryNarrowingsAssignedBy(loopEntryScope, outerScope, statements) {
5354
- for (const rootName of collectAssignedPathRoots(statements)) {
5355
- const outerEntry = outerScope.lookup(rootName);
5356
- if (outerEntry) {
5357
- loopEntryScope.hideInheritedNarrowing(outerEntry);
5367
+ function statementFlow(statements, cache) {
5368
+ const cached = cache.get(statements);
5369
+ if (cached) return cached;
5370
+ const flow = /* @__PURE__ */ new Set(["fallthrough"]);
5371
+ for (const statement of statements) {
5372
+ if (!flow.delete("fallthrough")) break;
5373
+ let next;
5374
+ switch (statement.kind) {
5375
+ case "return":
5376
+ case "throw":
5377
+ next = /* @__PURE__ */ new Set(["exit"]);
5378
+ break;
5379
+ case "break":
5380
+ next = /* @__PURE__ */ new Set(["break"]);
5381
+ break;
5382
+ case "continue":
5383
+ next = /* @__PURE__ */ new Set(["continue"]);
5384
+ break;
5385
+ case "if":
5386
+ next = new Set(statementFlow(statement.elseBody ?? [], cache));
5387
+ for (const branch of statement.branches)
5388
+ for (const outcome of statementFlow(branch.body, cache))
5389
+ next.add(outcome);
5390
+ break;
5391
+ case "try":
5392
+ next = new Set(statementFlow(statement.body, cache));
5393
+ for (const clause of statement.catches)
5394
+ for (const outcome of statementFlow(clause.body, cache))
5395
+ next.add(outcome);
5396
+ break;
5397
+ case "switch":
5398
+ next = /* @__PURE__ */ new Set();
5399
+ if (!statement.sections.some(
5400
+ (section) => section.labels.some((label) => label.kind === "default")
5401
+ )) {
5402
+ next.add("fallthrough");
5403
+ }
5404
+ for (const section of statement.sections)
5405
+ for (const outcome of statementFlow(section.body, cache))
5406
+ next.add(outcome);
5407
+ if (next.delete("break")) next.add("fallthrough");
5408
+ break;
5409
+ case "doWhile":
5410
+ next = new Set(statementFlow(statement.body, cache));
5411
+ if (next.delete("break")) next.add("fallthrough");
5412
+ if (next.delete("continue")) next.add("fallthrough");
5413
+ break;
5414
+ default:
5415
+ next = /* @__PURE__ */ new Set(["fallthrough"]);
5416
+ break;
5358
5417
  }
5418
+ for (const outcome of next) flow.add(outcome);
5359
5419
  }
5420
+ cache.set(statements, flow);
5421
+ return flow;
5360
5422
  }
5361
- function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set()) {
5423
+ function localsWithBindings(locals, expression, whenTrue) {
5424
+ const facts = whenTrue ? factsWhenTrue(expression, canonicalPath) : factsWhenFalse(expression, canonicalPath);
5425
+ return /* @__PURE__ */ new Set([
5426
+ ...locals,
5427
+ ...facts.flatMap((fact) => fact.bindingName ? [fact.bindingName] : [])
5428
+ ]);
5429
+ }
5430
+ function collectAssignedPathRoots(statements, roots = /* @__PURE__ */ new Set(), inheritedLocals = /* @__PURE__ */ new Set(), flowCache = /* @__PURE__ */ new WeakMap()) {
5431
+ const locals = new Set(inheritedLocals);
5362
5432
  for (const statement of statements) {
5363
5433
  if (statement.kind === "assign") {
5364
5434
  const assignedPath = canonicalPath(statement.target);
5365
- if (assignedPath) roots.add(pathRoot(assignedPath));
5366
- collectAssignedPathRootsInExpression(statement.target, roots);
5435
+ if (assignedPath && !locals.has(pathRoot(assignedPath))) {
5436
+ roots.add(pathRoot(assignedPath));
5437
+ }
5438
+ collectAssignedPathRootsInExpression(
5439
+ statement.target,
5440
+ roots,
5441
+ locals,
5442
+ flowCache
5443
+ );
5367
5444
  if (statement.value)
5368
- collectAssignedPathRootsInExpression(statement.value, roots);
5445
+ collectAssignedPathRootsInExpression(
5446
+ statement.value,
5447
+ roots,
5448
+ locals,
5449
+ flowCache
5450
+ );
5369
5451
  continue;
5370
5452
  }
5371
5453
  if (statement.kind === "varDecl") {
5372
- collectAssignedPathRootsInExpression(statement.init, roots);
5454
+ collectAssignedPathRootsInExpression(
5455
+ statement.init,
5456
+ roots,
5457
+ locals,
5458
+ flowCache
5459
+ );
5460
+ locals.add(statement.name);
5373
5461
  continue;
5374
5462
  }
5375
5463
  if (statement.kind === "if") {
5464
+ let falseLocals = locals;
5465
+ const falseFacts = [];
5466
+ const fallthroughFacts = [];
5376
5467
  for (const branch of statement.branches) {
5377
- collectAssignedPathRootsInExpression(branch.cond, roots);
5378
- collectAssignedPathRoots(branch.body, roots);
5468
+ collectAssignedPathRootsInExpression(
5469
+ branch.cond,
5470
+ roots,
5471
+ falseLocals,
5472
+ flowCache
5473
+ );
5474
+ const branchFacts = [
5475
+ ...falseFacts,
5476
+ ...factsWhenTrue(branch.cond, canonicalPath)
5477
+ ];
5478
+ collectAssignedPathRoots(
5479
+ branch.body,
5480
+ roots,
5481
+ localsWithBindings(falseLocals, branch.cond, true),
5482
+ flowCache
5483
+ );
5484
+ if (statementFlow(branch.body, flowCache).has("fallthrough"))
5485
+ fallthroughFacts.push(branchFacts);
5486
+ falseFacts.push(...factsWhenFalse(branch.cond, canonicalPath));
5487
+ falseLocals = localsWithBindings(falseLocals, branch.cond, false);
5379
5488
  }
5380
5489
  if (statement.elseBody) {
5381
- collectAssignedPathRoots(statement.elseBody, roots);
5490
+ collectAssignedPathRoots(
5491
+ statement.elseBody,
5492
+ roots,
5493
+ falseLocals,
5494
+ flowCache
5495
+ );
5496
+ if (statementFlow(statement.elseBody, flowCache).has("fallthrough"))
5497
+ fallthroughFacts.push(falseFacts);
5498
+ } else {
5499
+ fallthroughFacts.push(falseFacts);
5500
+ }
5501
+ for (const fact of mergeFactSets(fallthroughFacts)) {
5502
+ if (fact.bindingName) locals.add(fact.bindingName);
5382
5503
  }
5383
5504
  continue;
5384
5505
  }
5385
5506
  if (statement.kind === "try") {
5386
- collectAssignedPathRoots(statement.body, roots);
5507
+ collectAssignedPathRoots(statement.body, roots, locals, flowCache);
5387
5508
  for (const clause of statement.catches) {
5509
+ const catchLocals = /* @__PURE__ */ new Set([...locals, clause.name]);
5388
5510
  if (clause.filter) {
5389
- collectAssignedPathRootsInExpression(clause.filter, roots);
5511
+ collectAssignedPathRootsInExpression(
5512
+ clause.filter,
5513
+ roots,
5514
+ catchLocals,
5515
+ flowCache
5516
+ );
5390
5517
  }
5391
- collectAssignedPathRoots(clause.body, roots);
5518
+ collectAssignedPathRoots(
5519
+ clause.body,
5520
+ roots,
5521
+ clause.filter ? localsWithBindings(catchLocals, clause.filter, true) : catchLocals,
5522
+ flowCache
5523
+ );
5392
5524
  }
5393
5525
  continue;
5394
5526
  }
5395
5527
  if (statement.kind === "while" || statement.kind === "doWhile") {
5396
- collectAssignedPathRootsInExpression(statement.condition, roots);
5397
- collectAssignedPathRoots(statement.body, roots);
5528
+ collectAssignedPathRootsInExpression(
5529
+ statement.condition,
5530
+ roots,
5531
+ locals,
5532
+ flowCache
5533
+ );
5534
+ collectAssignedPathRoots(
5535
+ statement.body,
5536
+ roots,
5537
+ statement.kind === "while" ? localsWithBindings(locals, statement.condition, true) : locals,
5538
+ flowCache
5539
+ );
5398
5540
  continue;
5399
5541
  }
5400
5542
  if (statement.kind === "for") {
5401
- collectAssignedPathRootsInExpression(statement.initializer.init, roots);
5402
- collectAssignedPathRootsInExpression(statement.condition, roots);
5403
- collectAssignedPathRoots([statement.iterator], roots);
5404
- collectAssignedPathRoots(statement.body, roots);
5543
+ collectAssignedPathRootsInExpression(
5544
+ statement.initializer.init,
5545
+ roots,
5546
+ locals,
5547
+ flowCache
5548
+ );
5549
+ const loopLocals = /* @__PURE__ */ new Set([...locals, statement.initializer.name]);
5550
+ collectAssignedPathRootsInExpression(
5551
+ statement.condition,
5552
+ roots,
5553
+ loopLocals,
5554
+ flowCache
5555
+ );
5556
+ const iterationLocals = localsWithBindings(
5557
+ loopLocals,
5558
+ statement.condition,
5559
+ true
5560
+ );
5561
+ collectAssignedPathRoots(
5562
+ [statement.iterator],
5563
+ roots,
5564
+ iterationLocals,
5565
+ flowCache
5566
+ );
5567
+ collectAssignedPathRoots(
5568
+ statement.body,
5569
+ roots,
5570
+ iterationLocals,
5571
+ flowCache
5572
+ );
5405
5573
  continue;
5406
5574
  }
5407
5575
  if (statement.kind === "forEach") {
5408
- collectAssignedPathRootsInExpression(statement.collection, roots);
5409
- collectAssignedPathRoots(statement.body, roots);
5576
+ collectAssignedPathRootsInExpression(
5577
+ statement.collection,
5578
+ roots,
5579
+ locals,
5580
+ flowCache
5581
+ );
5582
+ const loopLocals = /* @__PURE__ */ new Set([...locals, statement.name]);
5583
+ if (statement.key) loopLocals.add(statement.key.name);
5584
+ collectAssignedPathRoots(statement.body, roots, loopLocals, flowCache);
5410
5585
  continue;
5411
5586
  }
5412
5587
  if (statement.kind === "switch") {
5413
- collectAssignedPathRootsInExpression(statement.selector, roots);
5588
+ collectAssignedPathRootsInExpression(
5589
+ statement.selector,
5590
+ roots,
5591
+ locals,
5592
+ flowCache
5593
+ );
5414
5594
  for (const section of statement.sections) {
5415
5595
  for (const label of section.labels) {
5416
5596
  if (label.kind === "case") {
5417
- collectAssignedPathRootsInExpression(label.expression, roots);
5597
+ collectAssignedPathRootsInExpression(
5598
+ label.expression,
5599
+ roots,
5600
+ locals,
5601
+ flowCache
5602
+ );
5418
5603
  }
5419
5604
  }
5420
- collectAssignedPathRoots(section.body, roots);
5605
+ collectAssignedPathRoots(section.body, roots, locals, flowCache);
5421
5606
  }
5422
5607
  continue;
5423
5608
  }
5424
5609
  if (statement.kind === "return" || statement.kind === "throw") {
5425
5610
  if (statement.expr)
5426
- collectAssignedPathRootsInExpression(statement.expr, roots);
5611
+ collectAssignedPathRootsInExpression(
5612
+ statement.expr,
5613
+ roots,
5614
+ locals,
5615
+ flowCache
5616
+ );
5427
5617
  continue;
5428
5618
  }
5429
5619
  if (statement.kind === "exprStmt") {
5430
- collectAssignedPathRootsInExpression(statement.expr, roots);
5620
+ collectAssignedPathRootsInExpression(
5621
+ statement.expr,
5622
+ roots,
5623
+ locals,
5624
+ flowCache
5625
+ );
5431
5626
  }
5432
5627
  }
5433
5628
  return roots;
5434
5629
  }
5435
- function collectAssignedPathRootsInExpression(expression, roots) {
5630
+ function collectAssignedPathRootsInExpression(expression, roots, locals, flowCache) {
5436
5631
  switch (expression.kind) {
5437
5632
  case "litInterp":
5438
5633
  for (const part of expression.parts) {
5439
5634
  if (part.kind === "expr") {
5440
- collectAssignedPathRootsInExpression(part.expr, roots);
5635
+ collectAssignedPathRootsInExpression(
5636
+ part.expr,
5637
+ roots,
5638
+ locals,
5639
+ flowCache
5640
+ );
5441
5641
  }
5442
5642
  }
5443
5643
  return;
5444
5644
  case "litList":
5445
5645
  for (const element of expression.elements) {
5446
- collectAssignedPathRootsInExpression(element, roots);
5646
+ collectAssignedPathRootsInExpression(element, roots, locals, flowCache);
5447
5647
  }
5448
5648
  return;
5449
5649
  case "litDict":
5450
5650
  for (const entry of expression.entries) {
5451
- collectAssignedPathRootsInExpression(entry.key, roots);
5452
- collectAssignedPathRootsInExpression(entry.value, roots);
5651
+ collectAssignedPathRootsInExpression(
5652
+ entry.key,
5653
+ roots,
5654
+ locals,
5655
+ flowCache
5656
+ );
5657
+ collectAssignedPathRootsInExpression(
5658
+ entry.value,
5659
+ roots,
5660
+ locals,
5661
+ flowCache
5662
+ );
5453
5663
  }
5454
5664
  return;
5455
5665
  case "member":
5456
- collectAssignedPathRootsInExpression(expression.receiver, roots);
5666
+ collectAssignedPathRootsInExpression(
5667
+ expression.receiver,
5668
+ roots,
5669
+ locals,
5670
+ flowCache
5671
+ );
5457
5672
  return;
5458
5673
  case "index":
5459
- collectAssignedPathRootsInExpression(expression.receiver, roots);
5460
- collectAssignedPathRootsInExpression(expression.index, roots);
5674
+ collectAssignedPathRootsInExpression(
5675
+ expression.receiver,
5676
+ roots,
5677
+ locals,
5678
+ flowCache
5679
+ );
5680
+ collectAssignedPathRootsInExpression(
5681
+ expression.index,
5682
+ roots,
5683
+ locals,
5684
+ flowCache
5685
+ );
5461
5686
  return;
5462
5687
  case "call":
5463
- collectAssignedPathRootsInExpression(expression.callee, roots);
5688
+ collectAssignedPathRootsInExpression(
5689
+ expression.callee,
5690
+ roots,
5691
+ locals,
5692
+ flowCache
5693
+ );
5464
5694
  for (const argument2 of expression.args) {
5465
- collectAssignedPathRootsInExpression(argument2, roots);
5695
+ collectAssignedPathRootsInExpression(
5696
+ argument2,
5697
+ roots,
5698
+ locals,
5699
+ flowCache
5700
+ );
5466
5701
  }
5467
5702
  return;
5468
5703
  case "new":
5469
5704
  for (const argument2 of expression.args) {
5470
- collectAssignedPathRootsInExpression(argument2, roots);
5705
+ collectAssignedPathRootsInExpression(
5706
+ argument2,
5707
+ roots,
5708
+ locals,
5709
+ flowCache
5710
+ );
5471
5711
  }
5472
5712
  for (const initializer of expression.initializer ?? []) {
5473
- collectAssignedPathRootsInExpression(initializer.value, roots);
5713
+ collectAssignedPathRootsInExpression(
5714
+ initializer.value,
5715
+ roots,
5716
+ locals,
5717
+ flowCache
5718
+ );
5474
5719
  }
5475
5720
  return;
5476
5721
  case "annotated":
5477
5722
  for (const annotation2 of expression.annotations) {
5478
5723
  for (const argument2 of annotation2.args) {
5479
- collectAssignedPathRootsInExpression(argument2, roots);
5724
+ collectAssignedPathRootsInExpression(
5725
+ argument2,
5726
+ roots,
5727
+ locals,
5728
+ flowCache
5729
+ );
5480
5730
  }
5481
5731
  }
5482
- collectAssignedPathRootsInExpression(expression.expression, roots);
5732
+ collectAssignedPathRootsInExpression(
5733
+ expression.expression,
5734
+ roots,
5735
+ locals,
5736
+ flowCache
5737
+ );
5483
5738
  return;
5484
5739
  case "binary":
5485
5740
  case "coalesce":
5486
- collectAssignedPathRootsInExpression(expression.left, roots);
5487
- collectAssignedPathRootsInExpression(expression.right, roots);
5741
+ collectAssignedPathRootsInExpression(
5742
+ expression.left,
5743
+ roots,
5744
+ locals,
5745
+ flowCache
5746
+ );
5747
+ collectAssignedPathRootsInExpression(
5748
+ expression.right,
5749
+ roots,
5750
+ locals,
5751
+ flowCache
5752
+ );
5488
5753
  return;
5489
5754
  case "conditional":
5490
- collectAssignedPathRootsInExpression(expression.condition, roots);
5491
- collectAssignedPathRootsInExpression(expression.whenTrue, roots);
5492
- collectAssignedPathRootsInExpression(expression.whenFalse, roots);
5755
+ collectAssignedPathRootsInExpression(
5756
+ expression.condition,
5757
+ roots,
5758
+ locals,
5759
+ flowCache
5760
+ );
5761
+ collectAssignedPathRootsInExpression(
5762
+ expression.whenTrue,
5763
+ roots,
5764
+ locals,
5765
+ flowCache
5766
+ );
5767
+ collectAssignedPathRootsInExpression(
5768
+ expression.whenFalse,
5769
+ roots,
5770
+ locals,
5771
+ flowCache
5772
+ );
5493
5773
  return;
5494
5774
  case "unary":
5495
5775
  case "force":
5496
- collectAssignedPathRootsInExpression(expression.operand, roots);
5776
+ collectAssignedPathRootsInExpression(
5777
+ expression.operand,
5778
+ roots,
5779
+ locals,
5780
+ flowCache
5781
+ );
5497
5782
  return;
5498
5783
  case "is":
5499
- collectAssignedPathRootsInExpression(expression.operand, roots);
5784
+ collectAssignedPathRootsInExpression(
5785
+ expression.operand,
5786
+ roots,
5787
+ locals,
5788
+ flowCache
5789
+ );
5500
5790
  return;
5501
5791
  case "lambda":
5502
- collectAssignedPathRoots(expression.body, roots);
5792
+ collectAssignedPathRoots(
5793
+ expression.body,
5794
+ roots,
5795
+ /* @__PURE__ */ new Set([
5796
+ ...locals,
5797
+ ...expression.params.map((parameter4) => parameter4.name)
5798
+ ]),
5799
+ flowCache
5800
+ );
5503
5801
  return;
5504
5802
  case "litNull":
5505
5803
  case "litBool":
@@ -6846,16 +7144,18 @@ var init_strict_resolver = __esm({
6846
7144
  const child = new Scope(scope);
6847
7145
  const branchFacts = [
6848
7146
  ...cumulativeFalseFacts,
6849
- ...factsWhenTrue(branch.cond)
7147
+ ...this.conditionFacts(branch.cond, scope, true)
6850
7148
  ];
6851
- this.applyFactsToScope(scope, child, branchFacts);
7149
+ this.applyFactsToScope(child, branchFacts);
6852
7150
  const instructions = this.resolveStatements(branch.body, child);
6853
7151
  if (!instructionsTerminate(instructions)) {
6854
7152
  branchExitFacts.push(branchFacts);
6855
7153
  branchExitNarrowings.push(new Map(child.narrowedPaths));
6856
7154
  branchExitOwnershipScopes.push(child);
6857
7155
  }
6858
- cumulativeFalseFacts.push(...factsWhenFalse(branch.cond));
7156
+ cumulativeFalseFacts.push(
7157
+ ...this.conditionFacts(branch.cond, scope, false)
7158
+ );
6859
7159
  return {
6860
7160
  expression: pointerToBooleanExpression(condition.pointer),
6861
7161
  instructions
@@ -6864,7 +7164,7 @@ var init_strict_resolver = __esm({
6864
7164
  let otherwise = null;
6865
7165
  if (statement.elseBody) {
6866
7166
  const elseScope = new Scope(scope);
6867
- this.applyFactsToScope(scope, elseScope, cumulativeFalseFacts);
7167
+ this.applyFactsToScope(elseScope, cumulativeFalseFacts);
6868
7168
  otherwise = this.resolveStatements(statement.elseBody, elseScope);
6869
7169
  if (!instructionsTerminate(otherwise)) {
6870
7170
  branchExitFacts.push([...cumulativeFalseFacts]);
@@ -6873,7 +7173,7 @@ var init_strict_resolver = __esm({
6873
7173
  }
6874
7174
  } else {
6875
7175
  const noBranchScope = new Scope(scope);
6876
- this.applyFactsToScope(scope, noBranchScope, cumulativeFalseFacts);
7176
+ this.applyFactsToScope(noBranchScope, cumulativeFalseFacts);
6877
7177
  branchExitFacts.push([...cumulativeFalseFacts]);
6878
7178
  branchExitNarrowings.push(new Map(noBranchScope.narrowedPaths));
6879
7179
  branchExitOwnershipScopes.push(noBranchScope);
@@ -6891,7 +7191,6 @@ var init_strict_resolver = __esm({
6891
7191
  }
6892
7192
  mergeBranchOwnership(scope, branchExitOwnershipScopes);
6893
7193
  this.applyFactsToScope(
6894
- scope,
6895
7194
  scope,
6896
7195
  mergeFactSets(branchExitFacts),
6897
7196
  "bindings-only"
@@ -7001,10 +7300,11 @@ var init_strict_resolver = __esm({
7001
7300
  case "while":
7002
7301
  case "doWhile": {
7003
7302
  const loopScope = new Scope(scope);
7004
- invalidateLoopEntryNarrowingsAssignedBy(
7303
+ this.invalidateLoopEntryNarrowingsAssignedBy(
7005
7304
  loopScope,
7006
7305
  scope,
7007
- statement.body
7306
+ statement.body,
7307
+ statement.kind === "while" ? localsWithBindings(/* @__PURE__ */ new Set(), statement.condition, true) : /* @__PURE__ */ new Set()
7008
7308
  );
7009
7309
  const iterationScope = new Scope(loopScope);
7010
7310
  let condition;
@@ -7013,8 +7313,8 @@ var init_strict_resolver = __esm({
7013
7313
  this.resolveExpression(statement.condition, loopScope),
7014
7314
  statement.condition.pos
7015
7315
  );
7016
- this.applyFactsToScope(loopScope, iterationScope, [
7017
- ...factsWhenTrue(statement.condition)
7316
+ this.applyFactsToScope(iterationScope, [
7317
+ ...this.conditionFacts(statement.condition, loopScope, true)
7018
7318
  ]);
7019
7319
  }
7020
7320
  const bodyScope = new Scope(iterationScope);
@@ -7051,15 +7351,19 @@ var init_strict_resolver = __esm({
7051
7351
  );
7052
7352
  }
7053
7353
  const normalExitScope = new Scope(nextConditionScope);
7054
- this.applyFactsToScope(nextConditionScope, normalExitScope, [
7055
- ...factsWhenFalse(statement.condition)
7354
+ this.applyFactsToScope(normalExitScope, [
7355
+ ...this.conditionFacts(
7356
+ statement.condition,
7357
+ nextConditionScope,
7358
+ false
7359
+ )
7056
7360
  ]);
7057
7361
  const effectScopes = nextConditionEffects.length > 0 ? [nextConditionScope] : [];
7058
7362
  const exitNarrowings = nextConditionEffects.length > 0 ? [normalExitScope.effectiveNarrowedPaths()] : [];
7059
7363
  if (statement.kind === "while") {
7060
7364
  const initialExitScope = new Scope(loopScope);
7061
- this.applyFactsToScope(loopScope, initialExitScope, [
7062
- ...factsWhenFalse(statement.condition)
7365
+ this.applyFactsToScope(initialExitScope, [
7366
+ ...this.conditionFacts(statement.condition, loopScope, false)
7063
7367
  ]);
7064
7368
  effectScopes.push(loopScope);
7065
7369
  exitNarrowings.push(initialExitScope.effectiveNarrowedPaths());
@@ -7087,17 +7391,30 @@ var init_strict_resolver = __esm({
7087
7391
  );
7088
7392
  }
7089
7393
  const loopEntryScope = new Scope(loopScope);
7090
- invalidateLoopEntryNarrowingsAssignedBy(loopEntryScope, scope, [
7091
- ...statement.body,
7092
- statement.iterator
7093
- ]);
7394
+ const conditionLocals = localsWithBindings(
7395
+ /* @__PURE__ */ new Set(),
7396
+ statement.condition,
7397
+ true
7398
+ );
7399
+ this.invalidateLoopEntryNarrowingsAssignedBy(
7400
+ loopEntryScope,
7401
+ loopScope,
7402
+ statement.body,
7403
+ conditionLocals
7404
+ );
7405
+ this.invalidateLoopEntryNarrowingsAssignedBy(
7406
+ loopEntryScope,
7407
+ loopScope,
7408
+ [statement.iterator],
7409
+ conditionLocals
7410
+ );
7094
7411
  const condition = this.toBool(
7095
7412
  this.resolveExpression(statement.condition, loopEntryScope),
7096
7413
  statement.condition.pos
7097
7414
  );
7098
7415
  const iterationScope = new Scope(loopEntryScope);
7099
- this.applyFactsToScope(loopEntryScope, iterationScope, [
7100
- ...factsWhenTrue(statement.condition)
7416
+ this.applyFactsToScope(iterationScope, [
7417
+ ...this.conditionFacts(statement.condition, loopEntryScope, true)
7101
7418
  ]);
7102
7419
  const bodyScope = new Scope(iterationScope);
7103
7420
  const loopFlow = {
@@ -7133,8 +7450,8 @@ var init_strict_resolver = __esm({
7133
7450
  );
7134
7451
  }
7135
7452
  const initialConditionFalseScope = new Scope(loopScope);
7136
- this.applyFactsToScope(loopScope, initialConditionFalseScope, [
7137
- ...factsWhenFalse(statement.condition)
7453
+ this.applyFactsToScope(initialConditionFalseScope, [
7454
+ ...this.conditionFacts(statement.condition, loopScope, false)
7138
7455
  ]);
7139
7456
  const effectScopes = [loopScope];
7140
7457
  const normalExitScopes = [initialConditionFalseScope];
@@ -7145,11 +7462,13 @@ var init_strict_resolver = __esm({
7145
7462
  ]);
7146
7463
  effectScopes.push(postIterationScope);
7147
7464
  const subsequentConditionFalseScope = new Scope(postIterationScope);
7148
- this.applyFactsToScope(
7149
- postIterationScope,
7150
- subsequentConditionFalseScope,
7151
- [...factsWhenFalse(statement.condition)]
7152
- );
7465
+ this.applyFactsToScope(subsequentConditionFalseScope, [
7466
+ ...this.conditionFacts(
7467
+ statement.condition,
7468
+ postIterationScope,
7469
+ false
7470
+ )
7471
+ ]);
7153
7472
  normalExitScopes.push(subsequentConditionFalseScope);
7154
7473
  }
7155
7474
  this.mergeLoopEffects(scope, effectScopes, loopFlow.breakEffects);
@@ -7269,9 +7588,9 @@ var init_strict_resolver = __esm({
7269
7588
  });
7270
7589
  }
7271
7590
  const iterationScope = new Scope(loopScope);
7272
- invalidateLoopEntryNarrowingsAssignedBy(
7591
+ this.invalidateLoopEntryNarrowingsAssignedBy(
7273
7592
  iterationScope,
7274
- scope,
7593
+ loopScope,
7275
7594
  statement.body
7276
7595
  );
7277
7596
  const bodyScope = new Scope(iterationScope);
@@ -7563,8 +7882,8 @@ var init_strict_resolver = __esm({
7563
7882
  }
7564
7883
  const bodyScope = new Scope(catchScope);
7565
7884
  if (clause.filter) {
7566
- this.applyFactsToScope(catchScope, bodyScope, [
7567
- ...factsWhenTrue(clause.filter)
7885
+ this.applyFactsToScope(bodyScope, [
7886
+ ...this.conditionFacts(clause.filter, catchScope, true)
7568
7887
  ]);
7569
7888
  }
7570
7889
  const catchPointer = {
@@ -7857,7 +8176,10 @@ var init_strict_resolver = __esm({
7857
8176
  value.writability ?? "runtime" /* Runtime */
7858
8177
  );
7859
8178
  }
7860
- const assignedPath = canonicalPath(statement.target);
8179
+ const assignedPath = this.narrowingPath(
8180
+ canonicalPath(statement.target),
8181
+ scope
8182
+ );
7861
8183
  if (assignedPath) {
7862
8184
  const rootEntry = scope.lookup(pathRoot(assignedPath));
7863
8185
  if (rootEntry) {
@@ -7896,7 +8218,20 @@ var init_strict_resolver = __esm({
7896
8218
  * lookup `resolveMember` performs before it overlays a narrowed type.
7897
8219
  */
7898
8220
  assignmentStorageType(targetAst, resolvedTarget, local, scope) {
7899
- if (targetAst.kind === "ident") return local?.type ?? resolvedTarget.type;
8221
+ if (targetAst.kind === "ident") {
8222
+ if (local) return local.type;
8223
+ const path = this.narrowingPath(targetAst.name, scope);
8224
+ if (path === `this.${targetAst.name}`) {
8225
+ return this.resolveMemberNatural(
8226
+ { kind: "ident", name: "this", pos: targetAst.pos },
8227
+ targetAst.name,
8228
+ scope,
8229
+ targetAst.pos,
8230
+ false
8231
+ ).type;
8232
+ }
8233
+ return resolvedTarget.type;
8234
+ }
7900
8235
  if (targetAst.kind !== "member") return resolvedTarget.type;
7901
8236
  return this.resolveMemberNatural(
7902
8237
  targetAst.receiver,
@@ -7957,7 +8292,10 @@ var init_strict_resolver = __esm({
7957
8292
  actionType,
7958
8293
  scope
7959
8294
  );
7960
- const assignedPath = canonicalPath(statement.target);
8295
+ const assignedPath = this.narrowingPath(
8296
+ canonicalPath(statement.target),
8297
+ scope
8298
+ );
7961
8299
  if (assignedPath) {
7962
8300
  const rootEntry = scope.lookup(pathRoot(assignedPath));
7963
8301
  if (rootEntry) {
@@ -9108,11 +9446,42 @@ var init_strict_resolver = __esm({
9108
9446
  pos
9109
9447
  );
9110
9448
  }
9111
- applyFactsToScope(outerScope, targetScope, facts, mode = "all") {
9449
+ narrowingPath(path, scope) {
9450
+ if (path === null) return null;
9451
+ const root = pathRoot(path);
9452
+ if (scope.lookup(root)) return path;
9453
+ if (this.context.project.globals.some((symbol) => symbol.name === root)) {
9454
+ return path;
9455
+ }
9456
+ const implicit = this.implicitMember(root);
9457
+ return implicit && implicit.symbol.static !== true ? `this.${path}` : path;
9458
+ }
9459
+ conditionFacts(expression, scope, whenTrue) {
9460
+ const pathOf = (value) => this.narrowingPath(canonicalPath(value), scope);
9461
+ return whenTrue ? factsWhenTrue(expression, pathOf) : factsWhenFalse(expression, pathOf);
9462
+ }
9463
+ /**
9464
+ * A loop body is resolved once but can execute repeatedly. Any narrowing rooted
9465
+ * in an outer binding that the body or iterator may write is therefore stale
9466
+ * at a later iteration entry. Invalidate those roots before resolving the
9467
+ * shared iteration so only the loop's own condition can narrow them again.
9468
+ */
9469
+ invalidateLoopEntryNarrowingsAssignedBy(loopEntryScope, outerScope, statements, locals = /* @__PURE__ */ new Set()) {
9470
+ for (const rootName of collectAssignedPathRoots(
9471
+ statements,
9472
+ /* @__PURE__ */ new Set(),
9473
+ locals
9474
+ )) {
9475
+ const path = this.narrowingPath(rootName, outerScope);
9476
+ const outerEntry = path === null ? null : outerScope.lookup(pathRoot(path));
9477
+ if (outerEntry) loopEntryScope.hideInheritedNarrowing(outerEntry);
9478
+ }
9479
+ }
9480
+ applyFactsToScope(targetScope, facts, mode = "all") {
9112
9481
  for (const fact of facts) {
9113
9482
  if (mode === "bindings-only" && !fact.bindingName) continue;
9114
- const natural = this.resolveExpression(fact.expression, outerScope);
9115
- const rootEntry = fact.path === null ? null : outerScope.lookup(pathRoot(fact.path));
9483
+ const natural = this.resolveExpression(fact.expression, targetScope);
9484
+ const rootEntry = fact.path === null ? null : targetScope.lookup(pathRoot(fact.path));
9116
9485
  if (fact.nullValue) {
9117
9486
  if (fact.path === null || rootEntry === null) continue;
9118
9487
  if (fact.loose === true && natural.type.kind === "primitive" && (natural.type.name === "string" || natural.type.name === "int" || natural.type.name === "float" || natural.type.name === "bool")) {
@@ -9418,7 +9787,10 @@ var init_strict_resolver = __esm({
9418
9787
  optional2
9419
9788
  );
9420
9789
  if (!optional2) {
9421
- const receiverPath = canonicalPath(receiverAst);
9790
+ const receiverPath = this.narrowingPath(
9791
+ canonicalPath(receiverAst),
9792
+ scope
9793
+ );
9422
9794
  if (receiverPath) {
9423
9795
  const rootEntry = scope.lookup(pathRoot(receiverPath));
9424
9796
  if (rootEntry) {
@@ -12507,7 +12879,10 @@ var init_strict_resolver = __esm({
12507
12879
  scope,
12508
12880
  true
12509
12881
  );
12510
- const path = canonicalPath(expression.callee.receiver);
12882
+ const path = this.narrowingPath(
12883
+ canonicalPath(expression.callee.receiver),
12884
+ scope
12885
+ );
12511
12886
  if (path) {
12512
12887
  const rootEntry = scope.lookup(pathRoot(path));
12513
12888
  if (rootEntry) scope.invalidate(rootEntry);
@@ -12568,15 +12943,13 @@ var init_strict_resolver = __esm({
12568
12943
  );
12569
12944
  const trueScope = new Scope(scope);
12570
12945
  this.applyFactsToScope(
12571
- scope,
12572
12946
  trueScope,
12573
- factsWhenTrue(expression.condition)
12947
+ this.conditionFacts(expression.condition, scope, true)
12574
12948
  );
12575
12949
  const falseScope = new Scope(scope);
12576
12950
  this.applyFactsToScope(
12577
- scope,
12578
12951
  falseScope,
12579
- factsWhenFalse(expression.condition)
12952
+ this.conditionFacts(expression.condition, scope, false)
12580
12953
  );
12581
12954
  let whenTrue;
12582
12955
  let whenFalse;
@@ -12658,9 +13031,8 @@ var init_strict_resolver = __esm({
12658
13031
  if (expression.op === "&&" || expression.op === "||") {
12659
13032
  rightScope = new Scope(scope);
12660
13033
  this.applyFactsToScope(
12661
- scope,
12662
13034
  rightScope,
12663
- expression.op === "&&" ? factsWhenTrue(expression.left) : factsWhenFalse(expression.left)
13035
+ expression.op === "&&" ? this.conditionFacts(expression.left, scope, true) : this.conditionFacts(expression.left, scope, false)
12664
13036
  );
12665
13037
  }
12666
13038
  const right = preResolvedRight ?? this.resolveExpression(expression.right, rightScope, left.type);
@@ -35212,9 +35584,14 @@ var init_service = __esm({
35212
35584
  if (state.context.projectSourceKind !== "spec") continue;
35213
35585
  const snapshot = this.scriptSnapshot(state);
35214
35586
  for (const candidate of snapshot.parsed.references) {
35215
- if (resolveReferenceSymbolId(snapshot, candidate) !== declaration.id) {
35216
- continue;
35217
- }
35587
+ if (candidate.name !== declaration.name) continue;
35588
+ const symbolId = resolveReferenceSymbolId(snapshot, candidate);
35589
+ if (symbolId === null) continue;
35590
+ const matches = declaration.id !== null ? symbolId === declaration.id : sameLocationInList(
35591
+ declaration.location,
35592
+ definition(snapshot, candidate.range.start)
35593
+ );
35594
+ if (!matches) continue;
35218
35595
  locations.push({ uri: state.document.uri, range: candidate.range });
35219
35596
  }
35220
35597
  }
@@ -63084,6 +63461,7 @@ function isSourceMemberValueRead(context, expression, ownerClass) {
63084
63461
  while (current.kind === "annotated") current = current.expression;
63085
63462
  const path = expressionMemberPath(current);
63086
63463
  if (path === null) return false;
63464
+ if (path.startsWith("root.")) return true;
63087
63465
  const parts = path.split(".");
63088
63466
  let classId;
63089
63467
  let memberName;
@@ -75760,7 +76138,7 @@ function withEvaluationRuntime(ctx, writes) {
75760
76138
  ctx.__runtimeSessionValues
75761
76139
  );
75762
76140
  const referencesAlreadyRemapped = ctx.__valueOverlay !== void 0 && ctx.__runtimeReferenceRemap !== void 0;
75763
- const remap = (value) => referencesAlreadyRemapped ? value : remapRuntimeReferences(
76141
+ const remap = (value) => referencesAlreadyRemapped || ctx.storedConstructionReplay === true ? value : remapRuntimeReferences(
75764
76142
  value,
75765
76143
  overlay,
75766
76144
  referenceRemap,
@@ -85753,14 +86131,15 @@ function claimVirtualIdentity(args) {
85753
86131
  virtualId: args.fixedVirtualId
85754
86132
  };
85755
86133
  }
85756
- const derivedId = virtualValueId(args.instanceRootId, args.rawSourceIdentity);
86134
+ const valueId = (sourceIdentity4) => args.instanceRootId.startsWith("__pending__:") || hasPendingVirtualSourceIdentity(sourceIdentity4) ? pendingVirtualValueId(args.instanceRootId, sourceIdentity4) : virtualValueId(args.instanceRootId, sourceIdentity4);
86135
+ const derivedId = valueId(args.rawSourceIdentity);
85757
86136
  const claimedPath = args.claimedVirtualIds.get(derivedId);
85758
86137
  if (claimedPath === void 0 || claimedPath === args.pathKey) {
85759
86138
  args.claimedVirtualIds.set(derivedId, args.pathKey);
85760
86139
  return { sourceIdentity: args.rawSourceIdentity, virtualId: derivedId };
85761
86140
  }
85762
86141
  const sourceIdentity3 = `${args.rawSourceIdentity}:${args.pathKey}`;
85763
- const virtualId = virtualValueId(args.instanceRootId, sourceIdentity3);
86142
+ const virtualId = valueId(sourceIdentity3);
85764
86143
  args.claimedVirtualIds.set(virtualId, args.pathKey);
85765
86144
  return { sourceIdentity: sourceIdentity3, virtualId };
85766
86145
  }
@@ -88141,6 +88520,8 @@ function createHeadlessVirtualInstanceResolver(args) {
88141
88520
  const remember = (graph, rows) => {
88142
88521
  graphRowsByRootId.set(graph.instanceRootId, rows);
88143
88522
  for (const [id2, row] of graph.rowsById) {
88523
+ if (id2 !== graph.instanceRootId && graphByValueId.get(id2)?.instanceRootId === id2)
88524
+ continue;
88144
88525
  expandedRowById.set(id2, row);
88145
88526
  graphByValueId.set(id2, graph);
88146
88527
  if (typeof row.value === "object" && row.value !== null) {
@@ -88148,6 +88529,8 @@ function createHeadlessVirtualInstanceResolver(args) {
88148
88529
  }
88149
88530
  }
88150
88531
  for (const id2 of graph.locationsById.keys()) {
88532
+ if (id2 !== graph.instanceRootId && graphByValueId.get(id2)?.instanceRootId === id2)
88533
+ continue;
88151
88534
  graphByValueId.set(id2, graph);
88152
88535
  }
88153
88536
  graphByValueId.set(graph.instanceRootId, graph);
@@ -88266,7 +88649,10 @@ function createHeadlessVirtualInstanceResolver(args) {
88266
88649
  rowForValueReference: (value) => expandedRowByRecord.get(value) ?? null,
88267
88650
  virtualInstanceGraphForValue: (valueId) => {
88268
88651
  const known = graphByValueId.get(valueId);
88269
- if (known !== void 0) return known;
88652
+ if (known?.instanceRootId === valueId) return known;
88653
+ const stored = rawById.get(valueId);
88654
+ if (known !== void 0 && (stored === void 0 || !isStoredClassResolutionRoot(stored)))
88655
+ return known;
88270
88656
  virtualInstanceRowsForValue(valueId);
88271
88657
  return graphByValueId.get(valueId) ?? null;
88272
88658
  },
@@ -98336,6 +98722,389 @@ var init_project_commit_preparation_scoped_loader = __esm({
98336
98722
  }
98337
98723
  });
98338
98724
 
98725
+ // ../src/runtime/neoscript/index.ts
98726
+ var init_neoscript2 = __esm({
98727
+ "../src/runtime/neoscript/index.ts"() {
98728
+ "use strict";
98729
+ init_NSGetterRuntimeError();
98730
+ init_evaluateNSGetter();
98731
+ init_evaluateInitializer();
98732
+ init_initializer_context();
98733
+ }
98734
+ });
98735
+
98736
+ // ../src/database/headless-virtual-instance-lookups.ts
98737
+ function headlessVirtualInstanceLookups(document, options = {}) {
98738
+ const members = document.members;
98739
+ const expandedDocument = expandPackedDocumentValues(document);
98740
+ const values = expandedDocument.values;
98741
+ const indexed = makeEvaluatorLookups(
98742
+ members,
98743
+ values,
98744
+ options.includeValueGraphIndexes === true ? {
98745
+ includeValueGraphIndexes: true,
98746
+ constructorInitializerDocument: {
98747
+ classes: document.classes,
98748
+ members,
98749
+ values
98750
+ }
98751
+ } : {}
98752
+ );
98753
+ const virtual = createHeadlessVirtualInstanceResolver2({
98754
+ document: {
98755
+ ...expandedDocument,
98756
+ ...options.initializerCompiler === void 0 ? {} : { initializerCompiler: options.initializerCompiler }
98757
+ },
98758
+ // A thunk: the resolver resolves nested reads through the lookups being
98759
+ // built around it.
98760
+ resolverLookups: () => lookups
98761
+ });
98762
+ const lookups = {
98763
+ ...indexed,
98764
+ // Raw first, then virtual: a materialized row always wins over the
98765
+ // expansion that would otherwise answer for it.
98766
+ valueById: (id2) => indexed.valueById(id2) ?? virtual.valueById(id2),
98767
+ rowForValueReference: (value) => indexed.rowForValueReference(value) ?? virtual.rowForValueReference(value),
98768
+ virtualInstanceRowsForValue: (receiverValueId) => virtual.virtualInstanceRowsForValue(receiverValueId),
98769
+ // Stored-construction replay evaluates `ToVariant`, and production's
98770
+ // variant-constructed placements collapse through exactly this path.
98771
+ resolveVariantInstanceGraph: (args) => resolveVariantInstanceGraphForDocument2({
98772
+ document,
98773
+ resolverLookups: lookups,
98774
+ ...args
98775
+ }),
98776
+ // A write to a virtual key must MATERIALIZE it (a pin row at the
98777
+ // deterministic virtual id plus the sparse spine); the planner needs the
98778
+ // owning graph, not just its rows.
98779
+ virtualInstanceGraphForValue: (valueId) => virtual.virtualInstanceGraphForValue(valueId)
98780
+ };
98781
+ return lookups;
98782
+ }
98783
+ var init_headless_virtual_instance_lookups = __esm({
98784
+ "../src/database/headless-virtual-instance-lookups.ts"() {
98785
+ "use strict";
98786
+ init_virtual_instance_values();
98787
+ init_packed_value_encoding();
98788
+ init_neoscript2();
98789
+ }
98790
+ });
98791
+
98792
+ // ../src/database/collection-binding-materialization.ts
98793
+ function mergeBodies(left, right) {
98794
+ if (right === void 0) return left;
98795
+ if (typeof left === "object" && left !== null && !Array.isArray(left) && typeof right === "object" && right !== null && !Array.isArray(right)) {
98796
+ return { ...left, ...right };
98797
+ }
98798
+ return right;
98799
+ }
98800
+ var CollectionBindingMaterializer;
98801
+ var init_collection_binding_materialization = __esm({
98802
+ "../src/database/collection-binding-materialization.ts"() {
98803
+ "use strict";
98804
+ init_members();
98805
+ init_virtual_instance_values();
98806
+ init_headless_virtual_instance_lookups();
98807
+ init_document_initializer_compiler();
98808
+ CollectionBindingMaterializer = class {
98809
+ constructor(document) {
98810
+ this.document = document;
98811
+ this.stored = new Map(document.values.map((row) => [row.id, row]));
98812
+ this.lookups = headlessVirtualInstanceLookups(document, {
98813
+ initializerCompiler: documentInitializerCompiler(document)
98814
+ });
98815
+ }
98816
+ document;
98817
+ rows = /* @__PURE__ */ new Map();
98818
+ pathRowsByRootId = /* @__PURE__ */ new Map();
98819
+ stored;
98820
+ lookups;
98821
+ resolvePath(rootId, segments) {
98822
+ let id2 = rootId;
98823
+ const pathRows = this.pathRowsByRootId.get(rootId) ?? /* @__PURE__ */ new Set();
98824
+ this.pathRowsByRootId.set(rootId, pathRows);
98825
+ for (const segment of segments) {
98826
+ const graph = this.lookups.virtualInstanceGraphForValue(id2);
98827
+ const row = graph?.rowsById.get(id2) ?? this.stored.get(id2);
98828
+ if (row === void 0 || !isLiteralValueContent(row)) return null;
98829
+ const body = row.value;
98830
+ if (typeof body !== "object" || body === null || Array.isArray(body))
98831
+ return null;
98832
+ const next = Reflect.get(body, segment);
98833
+ if (typeof next !== "string") return null;
98834
+ id2 = next;
98835
+ pathRows.add(id2);
98836
+ }
98837
+ return this.materialize(id2, pathRows) ? id2 : null;
98838
+ }
98839
+ /** Discover opaque virtual IDs from web selections against this candidate's roots. */
98840
+ materializeTargets(ids) {
98841
+ const missing = new Set([...ids].filter((id2) => !this.stored.has(id2)));
98842
+ if (missing.size === 0) return;
98843
+ const visited = /* @__PURE__ */ new Set();
98844
+ for (const row of this.document.values) {
98845
+ if (typeof row.classId !== "string") continue;
98846
+ const graph = this.lookups.virtualInstanceGraphForValue(row.id);
98847
+ if (graph === null || visited.has(graph.instanceRootId)) continue;
98848
+ visited.add(graph.instanceRootId);
98849
+ for (const id2 of graph.rowsById.keys()) {
98850
+ if (!missing.has(id2)) continue;
98851
+ if (this.materialize(id2)) missing.delete(id2);
98852
+ }
98853
+ if (missing.size === 0) return;
98854
+ }
98855
+ if (missing.size > 0) {
98856
+ throw new Error(
98857
+ `Collection binding targets missing values: ${[...missing].join(", ")}.`
98858
+ );
98859
+ }
98860
+ }
98861
+ locationForValue(id2) {
98862
+ return this.lookups.virtualInstanceGraphForValue(id2)?.locationsById.get(id2);
98863
+ }
98864
+ rowForValue(id2) {
98865
+ return this.rows.get(id2) ?? this.stored.get(id2);
98866
+ }
98867
+ materialize(id2, pathRows) {
98868
+ if (this.stored.has(id2) || this.rows.has(id2)) return true;
98869
+ const graph = this.lookups.virtualInstanceGraphForValue(id2);
98870
+ const row = graph?.rowsById.get(id2);
98871
+ if (graph === null || row === void 0 || !isLiteralValueContent(row))
98872
+ return false;
98873
+ const plan = planVirtualOverrideWrite({
98874
+ graph,
98875
+ valueId: id2,
98876
+ value: row.value
98877
+ });
98878
+ for (const create of plan.creates) {
98879
+ pathRows?.add(create.id);
98880
+ const { valuePlacement: _placement, ...fields } = create;
98881
+ const previous = this.rows.get(create.id);
98882
+ this.rows.set(create.id, {
98883
+ ...fields,
98884
+ value: mergeBodies(fields.value, previous?.value),
98885
+ projectId: this.document.project.id,
98886
+ createdAt: 0,
98887
+ updatedAt: 0
98888
+ });
98889
+ }
98890
+ for (const update of plan.updates) {
98891
+ pathRows?.add(update.valueId);
98892
+ const previous = this.rows.get(update.valueId) ?? this.stored.get(update.valueId);
98893
+ if (previous === void 0)
98894
+ throw new Error(
98895
+ `Collection binding has no ancestor ${update.valueId}.`
98896
+ );
98897
+ this.rows.set(update.valueId, {
98898
+ ...previous,
98899
+ value: mergeBodies(previous.value, update.value)
98900
+ });
98901
+ }
98902
+ return true;
98903
+ }
98904
+ };
98905
+ }
98906
+ });
98907
+
98908
+ // ../src/database/project-version-write-changes.ts
98909
+ function applyProjectVersionWriteChanges(document, changes) {
98910
+ return projectVersionDocumentWithChanges(document, changes, false);
98911
+ }
98912
+ function projectVersionDocumentWithChanges(document, changes, reuseUnchangedBuckets) {
98913
+ const projectRows = (rows, kind) => {
98914
+ const relevant = changes.filter((change) => change.recordKind === kind);
98915
+ if (reuseUnchangedBuckets && relevant.length === 0) return rows;
98916
+ return applyArrayChanges(rows, relevant);
98917
+ };
98918
+ const hasGranularDialogueRecords = document.dialogueRecords !== void 0 || changes.some((change) => change.recordKind === "dialogue");
98919
+ const hasGranularDialogueNodes = document.dialogueNodes !== void 0 || changes.some((change) => change.recordKind === "dialogue-node");
98920
+ const dialogueRecords = hasGranularDialogueRecords ? projectRows(document.dialogueRecords ?? [], "dialogue") : void 0;
98921
+ const dialogueNodes = hasGranularDialogueNodes ? projectRows(document.dialogueNodes ?? [], "dialogue-node") : void 0;
98922
+ const projected = {
98923
+ localizedTexts: projectRows(
98924
+ document.localizedTexts ?? [],
98925
+ "localized-text"
98926
+ ),
98927
+ localizationConfig: applySingletonChange(
98928
+ document.localizationConfig,
98929
+ changes,
98930
+ "localization-config"
98931
+ ),
98932
+ project: applySingletonChange(document.project, changes, "project"),
98933
+ members: projectRows(document.members, "member"),
98934
+ classes: projectRows(document.classes, "class"),
98935
+ // P43 §6. Declared constructors participate in the post-transaction
98936
+ // document so the whole-graph validator and every body compile see the
98937
+ // same constructor surface the transaction is about to persist.
98938
+ constructors: projectRows(document.constructors ?? [], "constructor"),
98939
+ // P67 §2.1. Same reason as constructors: without these buckets the
98940
+ // whole-graph validator, the variant ownership roots, and every body
98941
+ // compile would grade the transaction against the pre-transaction
98942
+ // variant set — so a newly pushed variant's closures would compile
98943
+ // against a document that does not contain it.
98944
+ variants: projectRows(document.variants ?? [], "variant"),
98945
+ variantFolders: projectRows(
98946
+ document.variantFolders ?? [],
98947
+ "variant-folder"
98948
+ ),
98949
+ values: projectRows(document.values ?? [], "value"),
98950
+ // Project-file staging finalizes pending uploads before schema
98951
+ // preparation. Defaults and authored instance graphs may reference a file
98952
+ // created by the same source transaction, so every construction pass must
98953
+ // see that finalized row in its post-write document.
98954
+ projectFiles: projectRows(document.projectFiles ?? [], "project-file"),
98955
+ // Import-setting templates are part of the same file graph. A new file
98956
+ // may select a new template in one source transaction, and default-value
98957
+ // materialization validates that relationship immediately against this
98958
+ // post-write document.
98959
+ textureTemplates: projectRows(
98960
+ document.textureTemplates ?? [],
98961
+ "unity-texture-template"
98962
+ ),
98963
+ audioClipTemplates: projectRows(
98964
+ document.audioClipTemplates ?? [],
98965
+ "unity-audio-clip-template"
98966
+ ),
98967
+ internalRecordRelations: projectRows(
98968
+ document.internalRecordRelations ?? [],
98969
+ "internal-record-relation"
98970
+ ),
98971
+ enums: projectRows(document.enums, "enum"),
98972
+ interfaces: projectRows(document.interfaces, "interface"),
98973
+ dialogues: dialogueRecords === void 0 || dialogueNodes === void 0 || dialogueRecords === document.dialogueRecords && dialogueNodes === document.dialogueNodes ? document.dialogues : materializeDialogues(
98974
+ dialogueRecords,
98975
+ dialogueNodes
98976
+ ),
98977
+ dialogueGroups: projectRows(
98978
+ document.dialogueGroups ?? [],
98979
+ "dialogue-group"
98980
+ ),
98981
+ migrations: projectRows(document.migrations ?? [], "migration")
98982
+ };
98983
+ return {
98984
+ ...document,
98985
+ ...projected,
98986
+ ...dialogueRecords === void 0 ? {} : { dialogueRecords },
98987
+ ...dialogueNodes === void 0 ? {} : { dialogueNodes }
98988
+ // The document spread above carries every bucket the caller's view declares
98989
+ // beyond the projected ones, so the result is the same view; TypeScript
98990
+ // cannot prove that of an object literal built over a type parameter.
98991
+ };
98992
+ }
98993
+ function applySingletonChange(current, changes, recordKind) {
98994
+ const change = changes.find(
98995
+ (candidate) => candidate.recordKind === recordKind
98996
+ );
98997
+ if (change === void 0) return current;
98998
+ if (change.operation === "delete" || change.nextData === void 0) {
98999
+ throw new Error(`Schema commit cannot delete the ${recordKind} record.`);
99000
+ }
99001
+ return change.nextData;
99002
+ }
99003
+ function applyArrayChanges(current, changes) {
99004
+ const byId = new Map(current.map((record6) => [record6.id, record6]));
99005
+ for (const change of changes) {
99006
+ if (change.operation === "delete") {
99007
+ byId.delete(change.recordId);
99008
+ continue;
99009
+ }
99010
+ if (change.nextData !== void 0) {
99011
+ byId.set(change.recordId, change.nextData);
99012
+ }
99013
+ }
99014
+ return [...byId.values()];
99015
+ }
99016
+ var init_project_version_write_changes = __esm({
99017
+ "../src/database/project-version-write-changes.ts"() {
99018
+ "use strict";
99019
+ init_projectDocumentDialogueMaterialization();
99020
+ }
99021
+ });
99022
+
99023
+ // ../src/database/prepared-collection-bindings.ts
99024
+ function materializePreparedCollectionBindings(args) {
99025
+ const targets = /* @__PURE__ */ new Set();
99026
+ for (const change of args.prepared) {
99027
+ if (change.operation === "delete") continue;
99028
+ if (change.recordKind !== "member" && change.recordKind !== "variant-folder" && change.recordKind !== "dialogue-group")
99029
+ continue;
99030
+ const data = change.nextData;
99031
+ if (typeof data !== "object" || data === null) continue;
99032
+ const binding = change.recordKind === "variant-folder" ? Reflect.get(data, "binding") : data;
99033
+ if (typeof binding !== "object" || binding === null) continue;
99034
+ const id2 = Reflect.get(binding, "collectionValueId");
99035
+ if (typeof id2 === "string") targets.add(id2);
99036
+ }
99037
+ if (targets.size === 0) return;
99038
+ const deletedTargets = /* @__PURE__ */ new Set();
99039
+ for (const change of args.prepared) {
99040
+ if (change.recordKind !== "value" || !targets.has(change.recordId))
99041
+ continue;
99042
+ if (change.operation === "delete") deletedTargets.add(change.recordId);
99043
+ else targets.delete(change.recordId);
99044
+ }
99045
+ if (targets.size === 0) return;
99046
+ for (const row of args.document.values) {
99047
+ if (!deletedTargets.has(row.id)) targets.delete(row.id);
99048
+ if (targets.size === 0) return;
99049
+ }
99050
+ const document = projectVersionDocumentWithChanges(
99051
+ args.document,
99052
+ args.prepared,
99053
+ true
99054
+ );
99055
+ const existingIds = new Set(document.values.map((row) => row.id));
99056
+ const materializer = new CollectionBindingMaterializer(document);
99057
+ materializer.materializeTargets(targets);
99058
+ const indexes2 = /* @__PURE__ */ new Map();
99059
+ args.prepared.forEach((change, index) => {
99060
+ if (change.recordKind === "value") indexes2.set(change.recordId, index);
99061
+ });
99062
+ const hashes = new Map(
99063
+ args.contentHashHeads.filter((head) => head.recordKind === "value").map((head) => [head.recordId, head.contentHash])
99064
+ );
99065
+ for (const row of materializer.rows.values()) {
99066
+ const index = indexes2.get(row.id);
99067
+ if (index !== void 0) {
99068
+ const previous = args.prepared[index];
99069
+ args.prepared[index] = {
99070
+ ...previous,
99071
+ operation: previous.operation === "delete" ? "update" : previous.operation,
99072
+ deleted: false,
99073
+ nextData: row,
99074
+ intent: previous.operation === "delete" ? createProjectVersionIntent("value.update", {
99075
+ source: "collection-binding-materialization"
99076
+ }) : previous.intent
99077
+ };
99078
+ continue;
99079
+ }
99080
+ const contentHash = hashes.get(row.id);
99081
+ if (existingIds.has(row.id) && contentHash === void 0) {
99082
+ throw new Error(
99083
+ `Collection binding ancestor "${row.id}" has no content hash.`
99084
+ );
99085
+ }
99086
+ args.prepared.push({
99087
+ recordKind: "value",
99088
+ recordId: row.id,
99089
+ operation: existingIds.has(row.id) ? "update" : "create",
99090
+ nextData: row,
99091
+ expectedBaseContentHash: contentHash ?? null,
99092
+ intent: createProjectVersionIntent(
99093
+ existingIds.has(row.id) ? "value.update" : "value.create",
99094
+ { source: "collection-binding-materialization" }
99095
+ )
99096
+ });
99097
+ }
99098
+ }
99099
+ var init_prepared_collection_bindings = __esm({
99100
+ "../src/database/prepared-collection-bindings.ts"() {
99101
+ "use strict";
99102
+ init_project_version_intents();
99103
+ init_collection_binding_materialization();
99104
+ init_project_version_write_changes();
99105
+ }
99106
+ });
99107
+
98339
99108
  // ../src/models/project/world-content-sidecar-validation.ts
98340
99109
  function cachedWorldLayerTarget(context, args) {
98341
99110
  let target = context.linkTargetsByClassId.get(args.sourceClassId);
@@ -98991,17 +99760,6 @@ var init_world_content_sidecar_validation = __esm({
98991
99760
  }
98992
99761
  });
98993
99762
 
98994
- // ../src/runtime/neoscript/index.ts
98995
- var init_neoscript2 = __esm({
98996
- "../src/runtime/neoscript/index.ts"() {
98997
- "use strict";
98998
- init_NSGetterRuntimeError();
98999
- init_evaluateNSGetter();
99000
- init_evaluateInitializer();
99001
- init_initializer_context();
99002
- }
99003
- });
99004
-
99005
99763
  // ../src/database/dialogue-node-index.ts
99006
99764
  function indexDialogueNodesByDialogue(nodes, dialogueId) {
99007
99765
  const result = /* @__PURE__ */ new Map();
@@ -100300,62 +101058,6 @@ var init_general_function_call_ir_source_recompile = __esm({
100300
101058
  }
100301
101059
  });
100302
101060
 
100303
- // ../src/database/headless-virtual-instance-lookups.ts
100304
- function headlessVirtualInstanceLookups(document, options = {}) {
100305
- const members = document.members;
100306
- const expandedDocument = expandPackedDocumentValues(document);
100307
- const values = expandedDocument.values;
100308
- const indexed = makeEvaluatorLookups(
100309
- members,
100310
- values,
100311
- options.includeValueGraphIndexes === true ? {
100312
- includeValueGraphIndexes: true,
100313
- constructorInitializerDocument: {
100314
- classes: document.classes,
100315
- members,
100316
- values
100317
- }
100318
- } : {}
100319
- );
100320
- const virtual = createHeadlessVirtualInstanceResolver2({
100321
- document: {
100322
- ...expandedDocument,
100323
- ...options.initializerCompiler === void 0 ? {} : { initializerCompiler: options.initializerCompiler }
100324
- },
100325
- // A thunk: the resolver resolves nested reads through the lookups being
100326
- // built around it.
100327
- resolverLookups: () => lookups
100328
- });
100329
- const lookups = {
100330
- ...indexed,
100331
- // Raw first, then virtual: a materialized row always wins over the
100332
- // expansion that would otherwise answer for it.
100333
- valueById: (id2) => indexed.valueById(id2) ?? virtual.valueById(id2),
100334
- rowForValueReference: (value) => indexed.rowForValueReference(value) ?? virtual.rowForValueReference(value),
100335
- virtualInstanceRowsForValue: (receiverValueId) => virtual.virtualInstanceRowsForValue(receiverValueId),
100336
- // Stored-construction replay evaluates `ToVariant`, and production's
100337
- // variant-constructed placements collapse through exactly this path.
100338
- resolveVariantInstanceGraph: (args) => resolveVariantInstanceGraphForDocument2({
100339
- document,
100340
- resolverLookups: lookups,
100341
- ...args
100342
- }),
100343
- // A write to a virtual key must MATERIALIZE it (a pin row at the
100344
- // deterministic virtual id plus the sparse spine); the planner needs the
100345
- // owning graph, not just its rows.
100346
- virtualInstanceGraphForValue: (valueId) => virtual.virtualInstanceGraphForValue(valueId)
100347
- };
100348
- return lookups;
100349
- }
100350
- var init_headless_virtual_instance_lookups = __esm({
100351
- "../src/database/headless-virtual-instance-lookups.ts"() {
100352
- "use strict";
100353
- init_virtual_instance_values();
100354
- init_packed_value_encoding();
100355
- init_neoscript2();
100356
- }
100357
- });
100358
-
100359
101061
  // ../src/database/localized-instance-override-writes.ts
100360
101062
  function collapseEditedLocalizedInstanceOverrides(args) {
100361
101063
  const edits = args.changes.filter(
@@ -100787,121 +101489,6 @@ var init_member_access_modifier_validation = __esm({
100787
101489
  }
100788
101490
  });
100789
101491
 
100790
- // ../src/database/project-version-write-changes.ts
100791
- function applyProjectVersionWriteChanges(document, changes) {
100792
- return projectVersionDocumentWithChanges(document, changes, false);
100793
- }
100794
- function projectVersionDocumentWithChanges(document, changes, reuseUnchangedBuckets) {
100795
- const projectRows = (rows, kind) => {
100796
- const relevant = changes.filter((change) => change.recordKind === kind);
100797
- if (reuseUnchangedBuckets && relevant.length === 0) return rows;
100798
- return applyArrayChanges(rows, relevant);
100799
- };
100800
- const hasGranularDialogueRecords = document.dialogueRecords !== void 0 || changes.some((change) => change.recordKind === "dialogue");
100801
- const hasGranularDialogueNodes = document.dialogueNodes !== void 0 || changes.some((change) => change.recordKind === "dialogue-node");
100802
- const dialogueRecords = hasGranularDialogueRecords ? projectRows(document.dialogueRecords ?? [], "dialogue") : void 0;
100803
- const dialogueNodes = hasGranularDialogueNodes ? projectRows(document.dialogueNodes ?? [], "dialogue-node") : void 0;
100804
- const projected = {
100805
- localizedTexts: projectRows(
100806
- document.localizedTexts ?? [],
100807
- "localized-text"
100808
- ),
100809
- localizationConfig: applySingletonChange(
100810
- document.localizationConfig,
100811
- changes,
100812
- "localization-config"
100813
- ),
100814
- project: applySingletonChange(document.project, changes, "project"),
100815
- members: projectRows(document.members, "member"),
100816
- classes: projectRows(document.classes, "class"),
100817
- // P43 §6. Declared constructors participate in the post-transaction
100818
- // document so the whole-graph validator and every body compile see the
100819
- // same constructor surface the transaction is about to persist.
100820
- constructors: projectRows(document.constructors ?? [], "constructor"),
100821
- // P67 §2.1. Same reason as constructors: without these buckets the
100822
- // whole-graph validator, the variant ownership roots, and every body
100823
- // compile would grade the transaction against the pre-transaction
100824
- // variant set — so a newly pushed variant's closures would compile
100825
- // against a document that does not contain it.
100826
- variants: projectRows(document.variants ?? [], "variant"),
100827
- variantFolders: projectRows(
100828
- document.variantFolders ?? [],
100829
- "variant-folder"
100830
- ),
100831
- values: projectRows(document.values ?? [], "value"),
100832
- // Project-file staging finalizes pending uploads before schema
100833
- // preparation. Defaults and authored instance graphs may reference a file
100834
- // created by the same source transaction, so every construction pass must
100835
- // see that finalized row in its post-write document.
100836
- projectFiles: projectRows(document.projectFiles ?? [], "project-file"),
100837
- // Import-setting templates are part of the same file graph. A new file
100838
- // may select a new template in one source transaction, and default-value
100839
- // materialization validates that relationship immediately against this
100840
- // post-write document.
100841
- textureTemplates: projectRows(
100842
- document.textureTemplates ?? [],
100843
- "unity-texture-template"
100844
- ),
100845
- audioClipTemplates: projectRows(
100846
- document.audioClipTemplates ?? [],
100847
- "unity-audio-clip-template"
100848
- ),
100849
- internalRecordRelations: projectRows(
100850
- document.internalRecordRelations ?? [],
100851
- "internal-record-relation"
100852
- ),
100853
- enums: projectRows(document.enums, "enum"),
100854
- interfaces: projectRows(document.interfaces, "interface"),
100855
- dialogues: dialogueRecords === void 0 || dialogueNodes === void 0 || dialogueRecords === document.dialogueRecords && dialogueNodes === document.dialogueNodes ? document.dialogues : materializeDialogues(
100856
- dialogueRecords,
100857
- dialogueNodes
100858
- ),
100859
- dialogueGroups: projectRows(
100860
- document.dialogueGroups ?? [],
100861
- "dialogue-group"
100862
- ),
100863
- migrations: projectRows(document.migrations ?? [], "migration")
100864
- };
100865
- return {
100866
- ...document,
100867
- ...projected,
100868
- ...dialogueRecords === void 0 ? {} : { dialogueRecords },
100869
- ...dialogueNodes === void 0 ? {} : { dialogueNodes }
100870
- // The document spread above carries every bucket the caller's view declares
100871
- // beyond the projected ones, so the result is the same view; TypeScript
100872
- // cannot prove that of an object literal built over a type parameter.
100873
- };
100874
- }
100875
- function applySingletonChange(current, changes, recordKind) {
100876
- const change = changes.find(
100877
- (candidate) => candidate.recordKind === recordKind
100878
- );
100879
- if (change === void 0) return current;
100880
- if (change.operation === "delete" || change.nextData === void 0) {
100881
- throw new Error(`Schema commit cannot delete the ${recordKind} record.`);
100882
- }
100883
- return change.nextData;
100884
- }
100885
- function applyArrayChanges(current, changes) {
100886
- const byId = new Map(current.map((record6) => [record6.id, record6]));
100887
- for (const change of changes) {
100888
- if (change.operation === "delete") {
100889
- byId.delete(change.recordId);
100890
- continue;
100891
- }
100892
- if (change.nextData !== void 0) {
100893
- byId.set(change.recordId, change.nextData);
100894
- }
100895
- }
100896
- return [...byId.values()];
100897
- }
100898
- var init_project_version_write_changes = __esm({
100899
- "../src/database/project-version-write-changes.ts"() {
100900
- "use strict";
100901
- init_projectDocumentDialogueMaterialization();
100902
- }
100903
- });
100904
-
100905
101492
  // ../src/database/member-localization-normalization.ts
100906
101493
  function planMemberLocalizationNormalization(input, now = 0) {
100907
101494
  const before = expandPackedDocumentValues(input);
@@ -103350,6 +103937,11 @@ function* prepareServerOwnedSchemaCommitPasses(args) {
103350
103937
  prepared,
103351
103938
  contentHashHeads: args.contentHashHeads
103352
103939
  });
103940
+ materializePreparedCollectionBindings({
103941
+ document: args.document,
103942
+ prepared,
103943
+ contentHashHeads: args.contentHashHeads
103944
+ });
103353
103945
  drainConstructedGraphValidations({
103354
103946
  document: args.document,
103355
103947
  prepared,
@@ -106840,6 +107432,7 @@ var SERVER_COMPILATION_PROJECT_CACHE_LIMIT, serverCompilationProjectCache, READ_
106840
107432
  var init_project_version_schema_commit = __esm({
106841
107433
  "../src/database/project-version-schema-commit.ts"() {
106842
107434
  "use strict";
107435
+ init_prepared_collection_bindings();
106843
107436
  init_document_initializer_compiler();
106844
107437
  init_effective_value_comparison();
106845
107438
  init_classes();
@@ -120807,7 +121400,8 @@ function resolveRootPathCollectionValuesV4(args) {
120807
121400
  args.registry,
120808
121401
  placements,
120809
121402
  rootValues,
120810
- fail2
121403
+ fail2,
121404
+ args.resolveVirtualPath
120811
121405
  );
120812
121406
  if (target !== null) resolved.set(member.id, target);
120813
121407
  }
@@ -120845,7 +121439,8 @@ function resolveRootPathVariantFolderCollectionValuesV4(args) {
120845
121439
  args.registry,
120846
121440
  placements,
120847
121441
  rootValues,
120848
- fail2
121442
+ fail2,
121443
+ args.resolveVirtualPath
120849
121444
  );
120850
121445
  if (target !== null) resolved.set(folder.id, target);
120851
121446
  }
@@ -120882,7 +121477,8 @@ function resolveRootPathDialogueGroupCollectionValuesV4(args) {
120882
121477
  expression: null,
120883
121478
  label: String(record6.fileFields.name)
120884
121479
  }
120885
- })
121480
+ }),
121481
+ args.resolveVirtualPath
120886
121482
  );
120887
121483
  if (target !== null) record6.fileFields.collectionValueId = target;
120888
121484
  }
@@ -120902,7 +121498,7 @@ function rootSlotValueIds(state) {
120902
121498
  });
120903
121499
  return values;
120904
121500
  }
120905
- function walkRootValuePath(path, state, registry, placements, rootValues, fail2) {
121501
+ function walkRootValuePath(path, state, registry, placements, rootValues, fail2, resolveVirtualPath) {
120906
121502
  const segments = path.split(".");
120907
121503
  const slotName = segments[1];
120908
121504
  if (segments[0] !== "root" || slotName === void 0) {
@@ -120945,10 +121541,17 @@ function walkRootValuePath(path, state, registry, placements, rootValues, fail2)
120945
121541
  }
120946
121542
  const next = placements.childrenByParentValueId.get(cursor)?.get(segment)?.childValueId;
120947
121543
  if (typeof next !== "string") {
120948
- const cursorData = state[`value:${cursor}`]?.data;
120949
- const collapsed = isObjectRecord2(cursorData) && isVirtualInstanceRootShape(cursorData);
121544
+ try {
121545
+ const resolved = resolveVirtualPath?.(slotValueId, segments.slice(2));
121546
+ if (resolved != null) return resolved;
121547
+ } catch (error) {
121548
+ fail2(
121549
+ `collectionValue path ${path} could not resolve its construction: ${error instanceof Error ? error.message : String(error)}`
121550
+ );
121551
+ return null;
121552
+ }
120950
121553
  fail2(
120951
- collapsed ? `collectionValue path ${path} reaches segment ${segment} on a collapsed instance "${cursor}": the value exists in that instance's construction but has no stored row to bind, and this push cannot materialize one. Name the row with Reference(id: ...) instead.` : `collectionValue path ${path} has no value at segment ${segment} after this push.`
121554
+ `collectionValue path ${path} has no value at segment ${segment} after this push.`
120952
121555
  );
120953
121556
  return null;
120954
121557
  }
@@ -121018,7 +121621,6 @@ var init_root_source = __esm({
121018
121621
  "use strict";
121019
121622
  init_src();
121020
121623
  init_src2();
121021
- init_instance_provenance();
121022
121624
  init_value_sources();
121023
121625
  init_source_format();
121024
121626
  init_stored_value_placements();
@@ -122636,9 +123238,35 @@ function computeWorkspaceStatus(workspace, options) {
122636
123238
  [...staticValues.records, ...memberDefaults.records, ...rootValues.records],
122637
123239
  staticMemberValueIds
122638
123240
  );
123241
+ let collectionBindings;
123242
+ const resolveVirtualPath = (rootId, segments) => {
123243
+ if (collectionBindings === void 0) {
123244
+ const candidate = /* @__PURE__ */ new Map();
123245
+ for (const [key, record6] of Object.entries(rootPathResolutionState)) {
123246
+ if (record6.file !== void 0 && isSchemaRecordKindV4(record6.recordKind) && !documentsByKey.has(key))
123247
+ continue;
123248
+ candidate.set(key, { ...record6, deleted: false });
123249
+ }
123250
+ for (const row of valueLowerRegistry.pendingValues.values()) {
123251
+ candidate.set(`value:${row.id}`, {
123252
+ recordKind: "value",
123253
+ recordId: row.id,
123254
+ contentHash: "",
123255
+ deleted: false,
123256
+ data: { id: row.id, ...encodeStoredValueRowFields(row) }
123257
+ });
123258
+ }
123259
+ const document = readPulledProjectDocumentV4(candidate);
123260
+ compilePulledProjectDocumentForEvaluationV4(document);
123261
+ collectionBindings = new CollectionBindingMaterializer(document);
123262
+ }
123263
+ const resolved = collectionBindings.resolvePath(rootId, segments);
123264
+ return resolved;
123265
+ };
122639
123266
  const resolvedCollectionPaths = resolveRootPathCollectionValuesV4({
122640
123267
  manifest,
122641
123268
  state: rootPathResolutionState,
123269
+ resolveVirtualPath,
122642
123270
  registry: valueLowerRegistry,
122643
123271
  siteForMember: (memberId) => {
122644
123272
  const span2 = sourceByKey.get(recordStateKey("member", memberId))?.span;
@@ -122667,6 +123295,7 @@ function computeWorkspaceStatus(workspace, options) {
122667
123295
  const resolvedVariantFolderPaths = resolveRootPathVariantFolderCollectionValuesV4({
122668
123296
  manifest,
122669
123297
  state: rootPathResolutionState,
123298
+ resolveVirtualPath,
122670
123299
  registry: valueLowerRegistry,
122671
123300
  siteForFolder: (folderId) => {
122672
123301
  const span2 = sourceByKey.get(
@@ -122753,7 +123382,7 @@ function computeWorkspaceStatus(workspace, options) {
122753
123382
  }
122754
123383
  }
122755
123384
  }
122756
- const rootRecords = rootValues.records;
123385
+ const rootRecords = [...rootValues.records];
122757
123386
  const variantValues = lowerVariantValueSourcesV4(
122758
123387
  loweringRecords,
122759
123388
  manifest,
@@ -122769,8 +123398,71 @@ function computeWorkspaceStatus(workspace, options) {
122769
123398
  records: supplementalRecords,
122770
123399
  manifest,
122771
123400
  state: rootPathResolutionState,
123401
+ resolveVirtualPath,
122772
123402
  registry: valueLowerRegistry
122773
123403
  });
123404
+ if (collectionBindings !== void 0) {
123405
+ const bindingSeeds = new Map(authoredValueSeeds);
123406
+ const rootRecordsById = new Map(
123407
+ rootRecords.filter((record6) => record6.recordKind === "value").map((record6) => [record6.recordId, record6])
123408
+ );
123409
+ const rootMembers = /* @__PURE__ */ new Map();
123410
+ for (const record6 of Object.values(rootPathResolutionState)) {
123411
+ if (record6.recordKind === "member" && isObjectRecord2(record6.data) && typeof record6.data.valueId === "string")
123412
+ rootMembers.set(record6.data.valueId, record6.recordId);
123413
+ }
123414
+ for (const row of collectionBindings.rows.values()) {
123415
+ if (rootPathResolutionState[`value:${row.id}`] === void 0) continue;
123416
+ const existing = rootRecordsById.get(row.id);
123417
+ if (existing !== void 0) Object.assign(existing.fileFields, row);
123418
+ else
123419
+ rootRecords.push({
123420
+ recordKind: "value",
123421
+ recordId: row.id,
123422
+ file: "Root.neo",
123423
+ line: 1,
123424
+ fileFields: { ...row }
123425
+ });
123426
+ }
123427
+ for (const [rootId, rowIds] of collectionBindings.pathRowsByRootId) {
123428
+ const memberId = rootMembers.get(rootId);
123429
+ const root = collectionBindings.rowForValue(rootId);
123430
+ if (memberId === void 0 || root === void 0) continue;
123431
+ const seed = authoredValueSeeds.get(memberId);
123432
+ const rows = new Map((seed?.values ?? []).map((row) => [row.id, row]));
123433
+ for (const id2 of rowIds) {
123434
+ if (id2 === rootId) continue;
123435
+ const row = collectionBindings.rowForValue(id2);
123436
+ const location3 = collectionBindings.locationForValue(id2);
123437
+ if (row === void 0 || !isLiteralValueContent(row) || location3 === void 0)
123438
+ throw new Error(`Collection binding row ${id2} has no member.`);
123439
+ const isNew = rootPathResolutionState[`value:${id2}`] === void 0;
123440
+ const classId = row.classId ?? (isMemberClassBase(location3.member) ? location3.member.classId : null);
123441
+ const authored = staticValueSeedRow(
123442
+ {
123443
+ ...row,
123444
+ classId,
123445
+ ...isNew && classId !== null ? {
123446
+ constructorArgs: row.constructorArgs ?? {},
123447
+ instanceConstructorId: row.instanceConstructorId ?? null
123448
+ } : {}
123449
+ },
123450
+ location3.memberId
123451
+ );
123452
+ rows.set(id2, authored);
123453
+ if (isNew) valueLowerRegistry.pendingValues.set(id2, authored);
123454
+ }
123455
+ bindingSeeds.set(memberId, {
123456
+ ...seed,
123457
+ nodeType: "literal",
123458
+ valueId: rootId,
123459
+ value: root.value,
123460
+ classId: root.classId ?? null,
123461
+ values: [...rows.values()]
123462
+ });
123463
+ }
123464
+ authoredValueSeeds = bindingSeeds;
123465
+ }
122774
123466
  const prospectiveState = overlayProspectiveSourceRecords(
122775
123467
  loweringRecords,
122776
123468
  documents,
@@ -124153,6 +124845,8 @@ var ANIMATION_DOCUMENT_RECORD_KINDS, ANIMATION_REPLAY_RECORD_KINDS, PROSPECTIVE_
124153
124845
  var init_workspace_status_core = __esm({
124154
124846
  "src/project-source/workspace-status-core.ts"() {
124155
124847
  "use strict";
124848
+ init_members();
124849
+ init_collection_binding_materialization();
124156
124850
  init_localizable_member_value_writes();
124157
124851
  init_localized_instance_override_writes();
124158
124852
  init_localization2();
@@ -126824,6 +127518,7 @@ function collectionValueObligations(manifest) {
126824
127518
  for (const member of manifest.members) {
126825
127519
  if (member.kind !== "lookup") continue;
126826
127520
  if (typeof member.collectionValueId !== "string") continue;
127521
+ if (member.collectionValueId.startsWith("__pending__:root-path:")) continue;
126827
127522
  obligations.push({
126828
127523
  kind: "collectionValue",
126829
127524
  site: {
@@ -127208,6 +127903,7 @@ function memberInitializerRequiresEvaluation(context, member, expression, source
127208
127903
  function isSchemaMemberValueRead(context, expression, source) {
127209
127904
  const path = memberPath2(annotatedValue(expression).expression);
127210
127905
  if (path === null) return false;
127906
+ if (path.startsWith("root.")) return true;
127211
127907
  const parts = path.split(".");
127212
127908
  const name = parts.at(-1);
127213
127909
  if (name === void 0) return false;
@@ -131452,10 +132148,9 @@ function classValueBody(context, member, value, visited, targetTyped, outerEnvir
131452
132148
  `${key} = ${emitValue(context, emittedChildMember, childId, {
131453
132149
  environment,
131454
132150
  definitionSite: !context.symbolsByValueId.has(childId),
131455
- // A class slot recovers this row from the owning value and schema key.
131456
- // P61 creation metadata and localization back-pointers must not turn
131457
- // that structural child into an explicitly identified source value.
131458
- writeIdentity: false,
132151
+ // Existing slots recover identity from storage. A newly pinned virtual
132152
+ // slot must keep its derived pending identity through repeat lowering.
132153
+ writeIdentity: pendingVirtualValueIdentity(childId) !== null,
131459
132154
  visited
131460
132155
  })}`
131461
132156
  );
@@ -133121,6 +133816,7 @@ var INFERRED_GENERIC_CLASS_PREFIX, MEMBER_KIND_DICTIONARY2, MEMBER_KIND_LIST2, M
133121
133816
  var init_value_sources = __esm({
133122
133817
  "src/project-source/value-sources.ts"() {
133123
133818
  "use strict";
133819
+ init_member_value_id();
133124
133820
  init_effective_value_comparison();
133125
133821
  init_member_declared_type_info();
133126
133822
  init_constructor_argument_ownership();
@@ -145703,7 +146399,7 @@ var init_registry2 = __esm({
145703
146399
  "../packages/manifest/schema-contract/registry.mjs"() {
145704
146400
  "use strict";
145705
146401
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
145706
- cliVersion: "0.61.2",
146402
+ cliVersion: "0.61.4",
145707
146403
  projectFileUploadBatchSize: 32,
145708
146404
  documentRecords: {
145709
146405
  member: {
@@ -154383,7 +155079,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
154383
155079
  async function main() {
154384
155080
  const args = parseArgs(process.argv.slice(2));
154385
155081
  if (args.command === "--version") {
154386
- console.log("0.61.2");
155082
+ console.log("0.61.4");
154387
155083
  return;
154388
155084
  }
154389
155085
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {