@neocompose/cli 0.22.1 → 0.22.3

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
@@ -1369,6 +1369,9 @@ function isNeoScriptTypeAssignable(source, target, project) {
1369
1369
  if (source.kind === "typeParameter" && target.kind === "typeParameter") {
1370
1370
  return source.id === target.id;
1371
1371
  }
1372
+ if (source.kind === "typeParameter" && source.constraint !== void 0) {
1373
+ return isNeoScriptTypeAssignable(source.constraint, target, project);
1374
+ }
1372
1375
  if (source.kind === "list" && target.kind === "list") {
1373
1376
  return isNeoScriptTypeAssignable(
1374
1377
  source.elementType,
@@ -29056,7 +29059,7 @@ function memberFromDocument(record3, members, owners, classNames, context) {
29056
29059
  );
29057
29060
  const modifier = memberModifier(overrideOf, isVirtual, isAbstract);
29058
29061
  const defaultValue = defaultValueFromDocument(
29059
- field("defaultValue", null),
29062
+ overrideOf !== null && !Object.hasOwn(data, "defaultValue") ? null : field("defaultValue", null),
29060
29063
  record3
29061
29064
  );
29062
29065
  const docsText = optionalDocsText(data.docsText, record3, "docsText");
@@ -36759,7 +36762,9 @@ function isMemberGenericBase(value) {
36759
36762
  if (!isSystemMetadata(v.system)) return false;
36760
36763
  if (v.system.kind !== SystemProtectionKind.WorldAuthoring) return false;
36761
36764
  }
36762
- if (v.defaultValue !== void 0 && v.defaultValue !== null) return false;
36765
+ if (v.defaultValue !== void 0 && v.defaultValue !== null && !isInitValueContent(v.defaultValue)) {
36766
+ return false;
36767
+ }
36763
36768
  if (v.required === true) return false;
36764
36769
  return true;
36765
36770
  }
@@ -38101,10 +38106,20 @@ var init_world_system_classes_generated = __esm({
38101
38106
  docsText: "One value at a frame index inside a segment. It holds until the next row\nyou author, or until the segment's Duration runs out.",
38102
38107
  extendsWorldKind: "animationFrameBase",
38103
38108
  isAbstract: false,
38104
- constructorProjections: [
38109
+ requiredConstructorId: "system_498d073e-0018-5828-af2b-22b113c31380",
38110
+ constructors: [
38105
38111
  {
38106
- memberId: "system_b71d1f73-da72-49de-ab9a-911cc9bffa43",
38107
- parameterName: "value"
38112
+ constructorId: "system_498d073e-0018-5828-af2b-22b113c31380",
38113
+ argumentTypes: [
38114
+ {
38115
+ name: "value",
38116
+ type: 21,
38117
+ required: true,
38118
+ ownerClassId: "system_9c4f3bfb-f0d8-4231-a7e7-9115bab8d5ab",
38119
+ genericParamId: "system_887b11d3-e56a-47ff-8d01-e2fcefb846a1"
38120
+ }
38121
+ ],
38122
+ code: null
38108
38123
  }
38109
38124
  ],
38110
38125
  genericParams: [
@@ -38114,6 +38129,7 @@ var init_world_system_classes_generated = __esm({
38114
38129
  {
38115
38130
  memberId: "system_b71d1f73-da72-49de-ab9a-911cc9bffa43",
38116
38131
  memberKind: "generic",
38132
+ defaultInitializerCode: "value",
38117
38133
  genericParamId: "system_887b11d3-e56a-47ff-8d01-e2fcefb846a1",
38118
38134
  required: false,
38119
38135
  schemaKey: "Value"
@@ -38191,14 +38207,32 @@ var init_world_system_classes_generated = __esm({
38191
38207
  name: "NeoAnimationChildOverride",
38192
38208
  docsText: "What one child looks like while a clip frame holds: which child, and the\nvalues to override on it.",
38193
38209
  isAbstract: false,
38194
- constructorProjections: [
38210
+ requiredConstructorId: "system_2fefcc00-08ab-5a16-a76a-758beac24ef1",
38211
+ constructors: [
38195
38212
  {
38196
- memberId: "system_48e66117-43fe-4429-97a8-964165f063ea",
38197
- parameterName: "selector"
38198
- },
38199
- {
38200
- memberId: "system_819b3743-0c3d-4896-b679-9aeeb73255f4",
38201
- parameterName: "overrides"
38213
+ constructorId: "system_2fefcc00-08ab-5a16-a76a-758beac24ef1",
38214
+ argumentTypes: [
38215
+ {
38216
+ name: "selector",
38217
+ type: 25,
38218
+ required: true,
38219
+ returnTypeInfo: {
38220
+ type: 21,
38221
+ required: true,
38222
+ ownerClassId: "system_e2e88eba-5335-4a16-9dcf-2c0e1951e8bd",
38223
+ genericParamId: "system_de23448a-45be-4e3f-8965-072a545e08f0"
38224
+ },
38225
+ argumentTypes: []
38226
+ },
38227
+ {
38228
+ name: "overrides",
38229
+ type: 21,
38230
+ required: true,
38231
+ ownerClassId: "system_e2e88eba-5335-4a16-9dcf-2c0e1951e8bd",
38232
+ genericParamId: "system_de23448a-45be-4e3f-8965-072a545e08f0"
38233
+ }
38234
+ ],
38235
+ code: null
38202
38236
  }
38203
38237
  ],
38204
38238
  genericParams: [
@@ -38212,6 +38246,7 @@ var init_world_system_classes_generated = __esm({
38212
38246
  {
38213
38247
  memberId: "system_48e66117-43fe-4429-97a8-964165f063ea",
38214
38248
  memberKind: "delegate",
38249
+ defaultInitializerCode: "selector",
38215
38250
  returnTypeInfo: {
38216
38251
  type: 21,
38217
38252
  required: true,
@@ -38234,6 +38269,7 @@ var init_world_system_classes_generated = __esm({
38234
38269
  {
38235
38270
  memberId: "system_819b3743-0c3d-4896-b679-9aeeb73255f4",
38236
38271
  memberKind: "generic",
38272
+ defaultInitializerCode: "overrides",
38237
38273
  genericParamId: "system_de23448a-45be-4e3f-8965-072a545e08f0",
38238
38274
  partial: true,
38239
38275
  required: false,
@@ -38247,16 +38283,31 @@ var init_world_system_classes_generated = __esm({
38247
38283
  name: "NeoAnimationTrackBase",
38248
38284
  docsText: "A lane on a clip's timeline: which child it plays against, when it starts,\nwhich way it runs, and which slice of the content to use. Both kinds of\ntrack derive from this, so playing a child clip reversed or cropped is\nsomething you author on the lane rather than pass in when you play it.",
38249
38285
  isAbstract: true,
38250
- constructorProjections: [
38286
+ requiredConstructorId: "system_8980d09b-0a6d-5461-9615-2f524515b1af",
38287
+ constructors: [
38251
38288
  {
38252
- memberId: "system_1e877396-1802-474a-9e4d-1df478d4c888",
38253
- parameterName: "selector"
38289
+ constructorId: "system_8980d09b-0a6d-5461-9615-2f524515b1af",
38290
+ argumentTypes: [
38291
+ {
38292
+ name: "selector",
38293
+ type: 25,
38294
+ required: true,
38295
+ returnTypeInfo: {
38296
+ type: 7,
38297
+ required: true,
38298
+ classId: "system_61b30a92-90dc-4bf8-8503-ee4f6414effc"
38299
+ },
38300
+ argumentTypes: []
38301
+ }
38302
+ ],
38303
+ code: null
38254
38304
  }
38255
38305
  ],
38256
38306
  schemaFields: [
38257
38307
  {
38258
38308
  memberId: "system_1e877396-1802-474a-9e4d-1df478d4c888",
38259
38309
  memberKind: "delegate",
38310
+ defaultInitializerCode: "selector",
38260
38311
  returnTypeInfo: {
38261
38312
  type: 7,
38262
38313
  required: true,
@@ -38330,20 +38381,33 @@ var init_world_system_classes_generated = __esm({
38330
38381
  docsText: "Plays another object's clip on this clip's timeline, looked up by name. The\nlane is as long as the clip it names.",
38331
38382
  extendsWorldKind: "animationTrack",
38332
38383
  isAbstract: false,
38333
- constructorProjections: [
38334
- {
38335
- memberId: "system_1e877396-1802-474a-9e4d-1df478d4c888",
38336
- parameterName: "selector"
38337
- },
38384
+ requiredConstructorId: "system_6baa12a7-be86-5ae0-82da-2fed308320a0",
38385
+ constructors: [
38338
38386
  {
38339
- memberId: "system_2c816624-0281-46d3-9ed5-d20bd43519f4",
38340
- parameterName: "clipKey"
38387
+ constructorId: "system_6baa12a7-be86-5ae0-82da-2fed308320a0",
38388
+ argumentTypes: [
38389
+ {
38390
+ name: "selector",
38391
+ type: 25,
38392
+ required: true,
38393
+ returnTypeInfo: {
38394
+ type: 7,
38395
+ required: true,
38396
+ classId: "system_61b30a92-90dc-4bf8-8503-ee4f6414effc"
38397
+ },
38398
+ argumentTypes: []
38399
+ },
38400
+ { name: "clipKey", type: 3, required: true }
38401
+ ],
38402
+ code: null,
38403
+ baseArguments: [{ name: "selector", code: "selector" }]
38341
38404
  }
38342
38405
  ],
38343
38406
  schemaFields: [
38344
38407
  {
38345
38408
  memberId: "system_2c816624-0281-46d3-9ed5-d20bd43519f4",
38346
38409
  memberKind: "string",
38410
+ defaultInitializerCode: "clipKey",
38347
38411
  localizable: false,
38348
38412
  required: true,
38349
38413
  schemaKey: "ClipKey"
@@ -38357,10 +38421,26 @@ var init_world_system_classes_generated = __esm({
38357
38421
  docsText: "Plays a sequence of values onto one member of one child, on the owning\nclip's clock. Where a child track hands off to another clip, this lane is a\nleaf: it writes one value per frame to the member its subclass targets.\n\nDerive from it with the child type you author against, so that a Segment\ngetter can reach that child's own members.",
38358
38422
  extendsWorldKind: "animationTrack",
38359
38423
  isAbstract: true,
38360
- constructorProjections: [
38424
+ requiredConstructorId: "system_1e7f8826-5392-5b4c-8cc3-6052d20e5280",
38425
+ constructors: [
38361
38426
  {
38362
- memberId: "system_b29e7ab9-0b8e-4399-84c1-1203070b75dd",
38363
- parameterName: "selector"
38427
+ constructorId: "system_1e7f8826-5392-5b4c-8cc3-6052d20e5280",
38428
+ argumentTypes: [
38429
+ {
38430
+ name: "selector",
38431
+ type: 25,
38432
+ required: true,
38433
+ returnTypeInfo: {
38434
+ type: 21,
38435
+ required: true,
38436
+ ownerClassId: "system_fd551dd8-6e6b-4044-9f32-7445ab344200",
38437
+ genericParamId: "system_d4fe9f71-d9d9-4baf-bc52-8de16933b655"
38438
+ },
38439
+ argumentTypes: []
38440
+ }
38441
+ ],
38442
+ code: null,
38443
+ baseArguments: [{ name: "selector", code: "selector" }]
38364
38444
  }
38365
38445
  ],
38366
38446
  genericParams: [
@@ -38376,6 +38456,7 @@ var init_world_system_classes_generated = __esm({
38376
38456
  memberId: "system_b29e7ab9-0b8e-4399-84c1-1203070b75dd",
38377
38457
  memberKind: "delegate",
38378
38458
  extendsMemberId: "system_1e877396-1802-474a-9e4d-1df478d4c888",
38459
+ defaultInitializerCode: "selector",
38379
38460
  docsText: "The child this lane plays against, typed as the child class you derived with, so a Segment getter can read that child's own members.",
38380
38461
  returnTypeInfo: {
38381
38462
  type: 21,
@@ -38417,6 +38498,28 @@ var init_world_system_classes_generated = __esm({
38417
38498
  docsText: "Plays a sprite segment onto a sprite child's Sprite member \u2014 the lane that\nanimates a sprite over time. Derive from it to say where the segment comes\nfrom; Segment is left for you to fill in, so every lane that plays is one of\nyour own classes.",
38418
38499
  extendsWorldKind: "animationSegmentTrack",
38419
38500
  isAbstract: true,
38501
+ requiredConstructorId: "system_9a3f52ca-872a-50a5-aad9-e9a040f40802",
38502
+ constructors: [
38503
+ {
38504
+ constructorId: "system_9a3f52ca-872a-50a5-aad9-e9a040f40802",
38505
+ argumentTypes: [
38506
+ {
38507
+ name: "selector",
38508
+ type: 25,
38509
+ required: true,
38510
+ returnTypeInfo: {
38511
+ type: 21,
38512
+ required: true,
38513
+ ownerClassId: "system_24b70585-0798-49ad-b650-4c118bac1eb1",
38514
+ genericParamId: "system_4de90637-6a3b-4bba-95ef-2ff9dfb05268"
38515
+ },
38516
+ argumentTypes: []
38517
+ }
38518
+ ],
38519
+ code: null,
38520
+ baseArguments: [{ name: "selector", code: "selector" }]
38521
+ }
38522
+ ],
38420
38523
  extendsGenericBindings: {
38421
38524
  "system_d4fe9f71-d9d9-4baf-bc52-8de16933b655": {
38422
38525
  kind: "generic",
@@ -47886,20 +47989,60 @@ function buildDeclaredConstructorIndex(analysis) {
47886
47989
  if (declaration.constructors.length === 0) continue;
47887
47990
  byClassName.set(declaration.name, declaration.constructors);
47888
47991
  }
47889
- return { byClassName, requiredByClassName };
47992
+ return {
47993
+ byClassName,
47994
+ requiredByClassName,
47995
+ persistedByClassName: /* @__PURE__ */ new Map(),
47996
+ persistedRequiredByClassName: /* @__PURE__ */ new Map()
47997
+ };
47998
+ }
47999
+ function withPersistedConstructorSignatures(index, classes, constructors) {
48000
+ const byId = new Map(constructors.map((entry) => [entry.id, entry]));
48001
+ const persistedByClassName = /* @__PURE__ */ new Map();
48002
+ const persistedRequiredByClassName = /* @__PURE__ */ new Map();
48003
+ for (const schemaClass2 of classes) {
48004
+ if (schemaClass2.requiredConstructorId !== void 0) {
48005
+ const required2 = byId.get(schemaClass2.requiredConstructorId);
48006
+ if (required2 !== void 0) {
48007
+ persistedRequiredByClassName.set(
48008
+ schemaClass2.name,
48009
+ required2.arguments.map((argument2) => argument2.name)
48010
+ );
48011
+ }
48012
+ }
48013
+ const overloads = (schemaClass2.constructorIds ?? []).flatMap((id2) => {
48014
+ const constructor2 = byId.get(id2);
48015
+ return constructor2 === void 0 ? [] : [constructor2.arguments.map((argument2) => argument2.name)];
48016
+ });
48017
+ if (overloads.length > 0) {
48018
+ persistedByClassName.set(schemaClass2.name, overloads);
48019
+ }
48020
+ }
48021
+ return {
48022
+ ...index,
48023
+ persistedByClassName,
48024
+ persistedRequiredByClassName
48025
+ };
47890
48026
  }
47891
48027
  function declaresConstructors(index, className) {
47892
48028
  if (className === null) return false;
47893
48029
  if (index.requiredByClassName.has(className)) return true;
47894
- return (index.byClassName.get(className)?.length ?? 0) > 0;
48030
+ if (index.persistedRequiredByClassName.has(className)) return true;
48031
+ return (index.byClassName.get(className)?.length ?? 0) > 0 || (index.persistedByClassName.get(className)?.length ?? 0) > 0;
47895
48032
  }
47896
48033
  function declaresParameterlessConstructor(index, className) {
47897
48034
  if (className === null) return false;
47898
48035
  const required2 = index.requiredByClassName.get(className);
47899
48036
  if (required2 !== void 0 && required2.parameters.length === 0) return true;
48037
+ const persistedRequired = index.persistedRequiredByClassName.get(className);
48038
+ if (persistedRequired !== void 0 && persistedRequired.length === 0) {
48039
+ return true;
48040
+ }
47900
48041
  const declared = index.byClassName.get(className);
47901
- if (declared === void 0) return false;
47902
- return declared.some((entry) => entry.parameters.length === 0);
48042
+ if (declared?.some((entry) => entry.parameters.length === 0) === true) {
48043
+ return true;
48044
+ }
48045
+ return index.persistedByClassName.get(className)?.some((parameters) => parameters.length === 0) ?? false;
47903
48046
  }
47904
48047
  function initializerRequiresEvaluation(index, expression, targetClassName, runtimeIdentifiers = /* @__PURE__ */ new Set()) {
47905
48048
  if (expression.kind === "annotated") {
@@ -47925,8 +48068,10 @@ function initializerRequiresEvaluation(index, expression, targetClassName, runti
47925
48068
  function requiredConstructorParameterNames(index, className) {
47926
48069
  if (className === null) return /* @__PURE__ */ new Set();
47927
48070
  const required2 = index.requiredByClassName.get(className);
47928
- if (required2 === void 0) return /* @__PURE__ */ new Set();
47929
- return new Set(required2.parameters.map((parameter3) => parameter3.name));
48071
+ if (required2 !== void 0) {
48072
+ return new Set(required2.parameters.map((parameter3) => parameter3.name));
48073
+ }
48074
+ return new Set(index.persistedRequiredByClassName.get(className) ?? []);
47930
48075
  }
47931
48076
  function expressionReadsRuntimeIdentifier(expression, runtimeIdentifiers) {
47932
48077
  if (runtimeIdentifiers.size === 0) return false;
@@ -48019,7 +48164,9 @@ var init_declared_constructors2 = __esm({
48019
48164
  init_src();
48020
48165
  EMPTY_DECLARED_CONSTRUCTOR_INDEX = {
48021
48166
  byClassName: /* @__PURE__ */ new Map(),
48022
- requiredByClassName: /* @__PURE__ */ new Map()
48167
+ requiredByClassName: /* @__PURE__ */ new Map(),
48168
+ persistedByClassName: /* @__PURE__ */ new Map(),
48169
+ persistedRequiredByClassName: /* @__PURE__ */ new Map()
48023
48170
  };
48024
48171
  }
48025
48172
  });
@@ -50961,7 +51108,14 @@ function classToLanguageType(schemaClass2, context) {
50961
51108
  type: {
50962
51109
  kind: "typeParameter",
50963
51110
  id: parameter3.id,
50964
- name: parameter3.name
51111
+ name: parameter3.name,
51112
+ ownerClassId: schemaClass2.id,
51113
+ ...parameter3.constraint === void 0 || parameter3.constraint === null ? {} : {
51114
+ constraint: namedType(
51115
+ parameter3.constraint.kind === "class" ? parameter3.constraint.classId : parameter3.constraint.enumId,
51116
+ true
51117
+ )
51118
+ }
50965
51119
  },
50966
51120
  location: virtualIdentifierLocation(
50967
51121
  context,
@@ -51788,10 +51942,20 @@ function toLanguageType(type, context, genericEnvironment) {
51788
51942
  const name = owner?.genericParams?.find(
51789
51943
  (parameter3) => parameter3.id === effectiveParamId
51790
51944
  )?.name ?? effectiveParamId;
51945
+ const declaration = owner?.genericParams?.find(
51946
+ (parameter3) => parameter3.id === effectiveParamId
51947
+ );
51791
51948
  return {
51792
51949
  kind: "typeParameter",
51793
51950
  id: effectiveParamId,
51794
51951
  name,
51952
+ ...owner === void 0 ? {} : { ownerClassId: owner.id },
51953
+ ...declaration?.constraint === void 0 || declaration.constraint === null ? {} : {
51954
+ constraint: namedType(
51955
+ declaration.constraint.kind === "class" ? declaration.constraint.classId : declaration.constraint.enumId,
51956
+ true
51957
+ )
51958
+ },
51795
51959
  nullable: !required2
51796
51960
  };
51797
51961
  }
@@ -52432,7 +52596,7 @@ function compileMemberInitializerBody(args) {
52432
52596
  );
52433
52597
  }
52434
52598
  const members = replaceMember(args.members, args.member);
52435
- const returnTypeInfo = resolveMemberDeclaredTypeInfo(args.member, members);
52599
+ const returnTypeInfo = resolveMemberDeclaredTypeInfo(args.member, members) ?? initializerGenericTypeInfo(args.member, args.thisClass);
52436
52600
  if (returnTypeInfo === null) {
52437
52601
  throw new Error(
52438
52602
  `Member "${args.member.name}" has an initializer but no resolvable declared type.`
@@ -52469,6 +52633,19 @@ function compileMemberInitializerBody(args) {
52469
52633
  }
52470
52634
  Object.assign(defaultValue.init, { compiled });
52471
52635
  }
52636
+ function initializerGenericTypeInfo(member, ownerClass) {
52637
+ if (!isMemberGenericBase(member) || ownerClass === null) return null;
52638
+ const declaration = ownerClass.genericParams?.find(
52639
+ (parameter3) => parameter3.id === member.genericParamId
52640
+ );
52641
+ if (declaration === void 0) return null;
52642
+ return {
52643
+ type: 21 /* Generic */,
52644
+ required: member.required,
52645
+ ownerClassId: ownerClass.id,
52646
+ genericParamId: declaration.id
52647
+ };
52648
+ }
52472
52649
  function compileValueRowInitializerBody(args) {
52473
52650
  const container = args.valueRow;
52474
52651
  if (!isInitValueContent(container)) return;
@@ -52644,6 +52821,11 @@ function compileConstructorBaseArguments(args, owner) {
52644
52821
  `Constructor "${args.constructor.id}" binds base argument "${baseArgument.name}", which base constructor "${baseConstructor.id}" does not declare.`
52645
52822
  );
52646
52823
  }
52824
+ const returnTypeInfo = substituteConstructorBaseType(
52825
+ parameter3,
52826
+ owner,
52827
+ args
52828
+ );
52647
52829
  return compileUnit2(
52648
52830
  "getter",
52649
52831
  () => compileNSInitializer(baseArgument.code, {
@@ -52655,7 +52837,7 @@ function compileConstructorBaseArguments(args, owner) {
52655
52837
  interfaces: [...args.interfaces ?? []],
52656
52838
  constructors: args.constructors,
52657
52839
  ...args.compilationProject === void 0 ? {} : { compilationProject: args.compilationProject },
52658
- returnTypeInfo: parameter3,
52840
+ returnTypeInfo,
52659
52841
  argumentTypes,
52660
52842
  initializerName: `${owner.name} base argument ${baseArgument.name}`
52661
52843
  })
@@ -52664,6 +52846,65 @@ function compileConstructorBaseArguments(args, owner) {
52664
52846
  );
52665
52847
  Object.assign(args.constructor, { compiledBaseArguments });
52666
52848
  }
52849
+ function substituteConstructorBaseType(typeInfo, owner, args) {
52850
+ if (typeInfo.type === 21 /* Generic */) {
52851
+ const binding = resolveGenericEnv(owner.id, args.classes).get(
52852
+ typeInfo.genericParamId
52853
+ );
52854
+ if (binding === void 0) return typeInfo;
52855
+ if (binding.kind === "unbound") {
52856
+ return {
52857
+ ...typeInfo,
52858
+ ownerClassId: owner.id,
52859
+ genericParamId: binding.paramId
52860
+ };
52861
+ }
52862
+ const member = args.members.find(
52863
+ (candidate) => candidate.id === binding.memberId
52864
+ );
52865
+ if (member === void 0) {
52866
+ throw new Error(
52867
+ `Constructor "${args.constructor.id}" resolves generic parameter "${typeInfo.genericParamId}" to missing member "${binding.memberId}".`
52868
+ );
52869
+ }
52870
+ return resolveMemberDeclaredTypeInfo(member, args.members) ?? typeInfo;
52871
+ }
52872
+ if (typeInfo.type === 25 /* NSDelegate */) {
52873
+ return {
52874
+ ...typeInfo,
52875
+ returnTypeInfo: substituteConstructorBaseType(
52876
+ typeInfo.returnTypeInfo,
52877
+ owner,
52878
+ args
52879
+ ),
52880
+ argumentTypes: typeInfo.argumentTypes.map(
52881
+ (argument2) => substituteConstructorBaseType(argument2, owner, args)
52882
+ )
52883
+ };
52884
+ }
52885
+ if (typeInfo.type === 6 /* List */ || typeInfo.type === 5 /* Dictionary */ || typeInfo.type === 9 /* Lookup */) {
52886
+ return {
52887
+ ...typeInfo,
52888
+ entryTypeInfo: substituteConstructorBaseType(
52889
+ typeInfo.entryTypeInfo,
52890
+ owner,
52891
+ args
52892
+ )
52893
+ };
52894
+ }
52895
+ if (typeInfo.type !== 7 /* Class */ || typeInfo.typeArguments === void 0) {
52896
+ return typeInfo;
52897
+ }
52898
+ return {
52899
+ ...typeInfo,
52900
+ typeArguments: Object.fromEntries(
52901
+ Object.entries(typeInfo.typeArguments).map(([parameterId, argument2]) => [
52902
+ parameterId,
52903
+ substituteConstructorBaseType(argument2, owner, args)
52904
+ ])
52905
+ )
52906
+ };
52907
+ }
52667
52908
  function compileConstructorBaseInitializerFields(args, owner) {
52668
52909
  const fields = args.constructor.baseInitializerFields ?? [];
52669
52910
  if (fields.length === 0) {
@@ -52983,6 +53224,7 @@ var init_compile_ns_property = __esm({
52983
53224
  "use strict";
52984
53225
  init_members();
52985
53226
  init_inheritance();
53227
+ init_generics();
52986
53228
  init_neoscript();
52987
53229
  init_core();
52988
53230
  init_lookup_declared_type();
@@ -53196,6 +53438,19 @@ var init_value_row_owner_members = __esm({
53196
53438
  });
53197
53439
 
53198
53440
  // ../src/database/constructor-argument-ownership.ts
53441
+ function constructorActionParameterId(constructor2, index) {
53442
+ const action = constructor2.action;
53443
+ if (action !== null && typeof action === "object") {
53444
+ const parameters = action.parameters;
53445
+ if (Array.isArray(parameters)) {
53446
+ const parameter3 = parameters[index + 2];
53447
+ if (parameter3 !== null && typeof parameter3 === "object" && typeof parameter3.id === "string") {
53448
+ return parameter3.id;
53449
+ }
53450
+ }
53451
+ }
53452
+ return `__arg_${index}__`;
53453
+ }
53199
53454
  function createTypedValueNormalizer(rows, document, childrenByContainerId, parameterTypesForRow, memberById, memberTypeInfo) {
53200
53455
  const visiting = /* @__PURE__ */ new Set();
53201
53456
  const normalizeLiteral = (value) => {
@@ -53550,7 +53805,7 @@ var init_constructor_argument_ownership = __esm({
53550
53805
  }
53551
53806
  const env = rowGenericEnvironment(this.document, root);
53552
53807
  for (let index = 0; index < constructor2.argumentTypes.length; index += 1) {
53553
- const parameterId = constructor2.action.parameters[index + 2]?.id;
53808
+ const parameterId = constructorActionParameterId(constructor2, index);
53554
53809
  const rawTypeInfo = constructor2.argumentTypes[index];
53555
53810
  if (parameterId === void 0 || rawTypeInfo === void 0) continue;
53556
53811
  const typeInfo = this.resolveTypeInfo(rawTypeInfo, env);
@@ -57590,6 +57845,8 @@ function runtimeTypeCheck(value, checkType, ctx, seenCollections = /* @__PURE__
57590
57845
  return isDecimalString(value);
57591
57846
  case 3 /* String */:
57592
57847
  return typeof value === "string";
57848
+ case 25 /* NSDelegate */:
57849
+ return isNSDelegateClosureValue(value) || isMemberDelegateTarget(value);
57593
57850
  case 11 /* Sprite */:
57594
57851
  return isRuntimeSpriteValue(value);
57595
57852
  case 12 /* Audio */:
@@ -59079,7 +59336,15 @@ function constructClassValueWithinFrame(descriptor, scope, ctx) {
59079
59336
  // A class with no declared constructors can still carry init-backed
59080
59337
  // member defaults (P43 §2, `string Foo = StaticFunc("bar")`), so the
59081
59338
  // schema-derived path evaluates them exactly as the declared one does.
59082
- initEvaluator: constructionInitEvaluator(ctx, createdValues),
59339
+ initEvaluator: constructionInitEvaluator(
59340
+ ctx,
59341
+ createdValues,
59342
+ {
59343
+ valuesByClassId: /* @__PURE__ */ new Map(),
59344
+ missingScopeReason: "no-constructor"
59345
+ },
59346
+ classId
59347
+ ),
59083
59348
  constructorRoot: {
59084
59349
  providedSchemaKeys: new Set(
59085
59350
  supplied.filter((entry) => entry.value !== null).map((entry) => entry.validated.schemaKey)
@@ -59330,15 +59595,17 @@ function runDeclaredConstructorChain(args) {
59330
59595
  args.visitedConstructorIds.add(record3.id);
59331
59596
  const baseRecord = resolveBaseConstructorRecord(record3, ctx);
59332
59597
  if (baseRecord !== null) {
59598
+ const preparedBaseArguments = args.preparedArgumentScopes.valuesByClassId.get(baseRecord.classId);
59333
59599
  runDeclaredConstructorChain({
59334
59600
  record: baseRecord,
59335
- argumentValues: evaluateBaseConstructorArguments(
59601
+ argumentValues: preparedBaseArguments ?? evaluateBaseConstructorArguments(
59336
59602
  record3,
59337
59603
  baseRecord,
59338
59604
  args.argumentValues,
59339
59605
  args.thisValue,
59340
59606
  ctx
59341
59607
  ),
59608
+ preparedArgumentScopes: args.preparedArgumentScopes,
59342
59609
  thisValue: args.thisValue,
59343
59610
  ctx,
59344
59611
  visitedConstructorIds: args.visitedConstructorIds,
@@ -59443,13 +59710,165 @@ function evaluateBaseInitializerFields(args) {
59443
59710
  return { validated, value };
59444
59711
  });
59445
59712
  }
59446
- function constructionInitEvaluator(ctx, createdValues, argumentValues = []) {
59447
- return (member, init) => evaluateInitializerInContext(
59448
- init,
59449
- member,
59450
- ctx,
59451
- createdValues,
59452
- argumentValues
59713
+ function constructionInitEvaluator(ctx, createdValues, argumentScopes, constructedClassId) {
59714
+ const indexes = constructorInitializerIndexes(ctx);
59715
+ const inheritanceChain = resolveInheritanceChain(
59716
+ constructedClassId,
59717
+ ctx.vm.classes
59718
+ );
59719
+ const owningClassId = (memberId) => {
59720
+ const visited = /* @__PURE__ */ new Set();
59721
+ let currentId = memberId;
59722
+ while (currentId !== void 0 && !visited.has(currentId)) {
59723
+ visited.add(currentId);
59724
+ const declaringClassIds = indexes.declaringClassIdsByMemberId.get(currentId);
59725
+ const owner = inheritanceChain.find(
59726
+ (schemaClass2) => declaringClassIds?.has(schemaClass2.id)
59727
+ );
59728
+ if (owner !== void 0) return owner.id;
59729
+ currentId = indexes.containerMemberIdByEntryId.get(currentId) ?? indexes.memberById.get(currentId)?.extendsMemberId;
59730
+ }
59731
+ return null;
59732
+ };
59733
+ return (member, init) => {
59734
+ if (init.compiled === void 0) {
59735
+ return evaluateInitializerInContext(init, member, ctx, createdValues);
59736
+ }
59737
+ const memberId = Reflect.get(member, "id");
59738
+ const scopeMemberId = indexes.initializerScopeMemberIds.get(init) ?? (typeof memberId === "string" ? memberId : "");
59739
+ const ownerClassId = owningClassId(scopeMemberId);
59740
+ const expectedArgumentCount = init.compiled?.parameters.slice(2).length;
59741
+ if (ownerClassId === null) {
59742
+ if (expectedArgumentCount !== void 0 && expectedArgumentCount > 0) {
59743
+ throw new NSGetterRuntimeError(
59744
+ `Member initializer '${member.name}' has ${expectedArgumentCount} constructor parameter(s), but its declaring class scope could not be resolved.`
59745
+ );
59746
+ }
59747
+ return evaluateInitializerInContext(init, member, ctx, createdValues);
59748
+ }
59749
+ const scopedArguments = argumentScopes.valuesByClassId.get(ownerClassId);
59750
+ if (scopedArguments === void 0) {
59751
+ if (expectedArgumentCount === 0) {
59752
+ return evaluateInitializerInContext(init, member, ctx, createdValues);
59753
+ }
59754
+ if (argumentScopes.missingScopeReason === "no-constructor") {
59755
+ throw new NSGetterRuntimeError(
59756
+ `Member initializer '${member.name}' on '${ownerClassId}' cannot read constructor parameters because schema-derived construction invoked no constructor.`
59757
+ );
59758
+ }
59759
+ throw new NSGetterRuntimeError(
59760
+ `Member initializer '${member.name}' on '${ownerClassId}' cannot read constructor parameters because its ': base(...)' arguments depend on initialized 'this'.`
59761
+ );
59762
+ }
59763
+ if (expectedArgumentCount !== void 0 && expectedArgumentCount !== scopedArguments.length) {
59764
+ throw new NSGetterRuntimeError(
59765
+ `Member initializer '${member.name}' on '${ownerClassId}' expected ${expectedArgumentCount} constructor argument(s), got ${scopedArguments.length}.`
59766
+ );
59767
+ }
59768
+ return evaluateInitializerInContext(
59769
+ init,
59770
+ member,
59771
+ ctx,
59772
+ createdValues,
59773
+ scopedArguments
59774
+ );
59775
+ };
59776
+ }
59777
+ function constructorInitializerIndexes(ctx) {
59778
+ if (ctx.__constructorInitializerIndexes !== void 0) {
59779
+ return ctx.__constructorInitializerIndexes;
59780
+ }
59781
+ const initializerScopeMemberIds = /* @__PURE__ */ new WeakMap();
59782
+ const initializerByValueId = /* @__PURE__ */ new Map();
59783
+ for (const row of ctx.vm.values) {
59784
+ const initializer = Reflect.get(row, "init");
59785
+ if (initializer !== void 0)
59786
+ initializerByValueId.set(row.id, initializer);
59787
+ }
59788
+ for (const member of ctx.vm.members) {
59789
+ const defaultValue = member.defaultValue;
59790
+ if (isInitValueContent(defaultValue)) {
59791
+ initializerScopeMemberIds.set(defaultValue.init, member.id);
59792
+ continue;
59793
+ }
59794
+ if (!isLiteralValueContent(defaultValue)) continue;
59795
+ const value = defaultValue.value;
59796
+ const valueIds = Array.isArray(value) ? value : typeof value === "object" && value !== null ? Object.values(value) : [];
59797
+ for (const valueId of valueIds) {
59798
+ if (typeof valueId !== "string") continue;
59799
+ const initializer = initializerByValueId.get(valueId);
59800
+ if (initializer !== void 0) {
59801
+ initializerScopeMemberIds.set(initializer, member.id);
59802
+ }
59803
+ }
59804
+ }
59805
+ const declaringClassIdsByMemberId = /* @__PURE__ */ new Map();
59806
+ for (const schemaClass2 of ctx.vm.classes) {
59807
+ for (const memberId of Object.values(schemaClass2.schema)) {
59808
+ const owners = declaringClassIdsByMemberId.get(memberId) ?? /* @__PURE__ */ new Set();
59809
+ owners.add(schemaClass2.id);
59810
+ declaringClassIdsByMemberId.set(memberId, owners);
59811
+ }
59812
+ }
59813
+ const memberById = new Map(
59814
+ ctx.vm.members.map((member) => [member.id, member])
59815
+ );
59816
+ const containerMemberIdByEntryId = /* @__PURE__ */ new Map();
59817
+ for (const member of ctx.vm.members) {
59818
+ if (isMemberList(member) || isMemberDictionary(member)) {
59819
+ containerMemberIdByEntryId.set(member.entryMemberId, member.id);
59820
+ }
59821
+ }
59822
+ const built = {
59823
+ initializerScopeMemberIds,
59824
+ declaringClassIdsByMemberId,
59825
+ memberById,
59826
+ containerMemberIdByEntryId
59827
+ };
59828
+ ctx.__constructorInitializerIndexes = built;
59829
+ return built;
59830
+ }
59831
+ function prepareConstructorArgumentScopes(record3, argumentValues, ctx) {
59832
+ const values = /* @__PURE__ */ new Map();
59833
+ let current = record3;
59834
+ let currentValues = argumentValues;
59835
+ while (current !== null) {
59836
+ values.set(current.classId, currentValues);
59837
+ const base = resolveBaseConstructorRecord(current, ctx);
59838
+ if (base === null) break;
59839
+ if (baseArgumentGettersReferenceThis(current)) break;
59840
+ currentValues = evaluateBaseConstructorArguments(
59841
+ current,
59842
+ base,
59843
+ currentValues,
59844
+ null,
59845
+ ctx
59846
+ );
59847
+ current = base;
59848
+ }
59849
+ return {
59850
+ valuesByClassId: values,
59851
+ missingScopeReason: record3 === null ? "no-constructor" : "base-arguments-depend-on-this"
59852
+ };
59853
+ }
59854
+ function baseArgumentGettersReferenceThis(record3) {
59855
+ return (record3.compiledBaseArguments ?? []).some((getter) => {
59856
+ const thisParameter = getter.parameters[0];
59857
+ return thisParameter !== void 0 && runtimeValueReferencesVariable(getter.instructions, thisParameter.id);
59858
+ });
59859
+ }
59860
+ function runtimeValueReferencesVariable(value, variableId, visited = /* @__PURE__ */ new WeakSet()) {
59861
+ if (typeof value !== "object" || value === null) return false;
59862
+ if (visited.has(value)) return false;
59863
+ visited.add(value);
59864
+ if (Reflect.get(value, "type") === "variable" /* variable */ && Reflect.get(value, "variableId") === variableId) {
59865
+ return true;
59866
+ }
59867
+ const children = Object.values(Object.getOwnPropertyDescriptors(value)).filter(
59868
+ (descriptor) => "value" in descriptor
59869
+ ).map((descriptor) => descriptor.value);
59870
+ return children.some(
59871
+ (child) => runtimeValueReferencesVariable(child, variableId, visited)
59453
59872
  );
59454
59873
  }
59455
59874
  function evaluateInitializerInContext(init, member, ctx, createdValues, argumentValues = []) {
@@ -59636,6 +60055,11 @@ function constructDeclaredClassValueWithinFrame(descriptor, record3, info, scope
59636
60055
  const schemaClass2 = descriptor.schemaClass;
59637
60056
  const classId = schemaClass2.id;
59638
60057
  const argumentValues = record3 === null ? [] : evaluateDeclaredConstructorArguments(info, record3, scope, ctx);
60058
+ const preparedArgumentScopes = prepareConstructorArgumentScopes(
60059
+ record3,
60060
+ argumentValues,
60061
+ ctx
60062
+ );
59639
60063
  const createdValues = [];
59640
60064
  const storageKeyDeclarations = /* @__PURE__ */ new Map();
59641
60065
  let root;
@@ -59660,7 +60084,8 @@ function constructDeclaredClassValueWithinFrame(descriptor, record3, info, scope
59660
60084
  initEvaluator: constructionInitEvaluator(
59661
60085
  ctx,
59662
60086
  createdValues,
59663
- argumentValues
60087
+ preparedArgumentScopes,
60088
+ classId
59664
60089
  ),
59665
60090
  constructorRoot: {
59666
60091
  providedSchemaKeys: new Set(
@@ -59721,6 +60146,7 @@ function constructDeclaredClassValueWithinFrame(descriptor, record3, info, scope
59721
60146
  runDeclaredConstructorChain({
59722
60147
  record: record3,
59723
60148
  argumentValues,
60149
+ preparedArgumentScopes,
59724
60150
  thisValue: root.value,
59725
60151
  ctx,
59726
60152
  visitedConstructorIds: /* @__PURE__ */ new Set(),
@@ -60906,6 +61332,7 @@ function evaluateMemberInitializer(args) {
60906
61332
  constructors: args.document.constructors,
60907
61333
  interfaces: args.document.interfaces,
60908
61334
  localizedTexts: args.document.localizedTexts,
61335
+ localizationConfig: args.document.localizationConfig,
60909
61336
  databaseVM: initializerEvaluatorLookups(args.document)
60910
61337
  },
60911
61338
  thisValue: null,
@@ -61070,6 +61497,14 @@ function isNeoClassConstructorBase(value) {
61070
61497
  }
61071
61498
  return v.compiledBaseInitializerFields === void 0 || v.compiledBaseInitializerFields === null;
61072
61499
  }
61500
+ function isUncompiledNeoClassConstructor(value) {
61501
+ if (!isNeoClassConstructorBase(value)) return false;
61502
+ const v = value;
61503
+ if (typeof v.id !== "string" || v.id.length === 0) return false;
61504
+ if (typeof v.projectId !== "string" || v.projectId.length === 0) return false;
61505
+ if (!isEpochMillis(v.createdAt)) return false;
61506
+ return isEpochMillis(v.updatedAt);
61507
+ }
61073
61508
  function hasValidConstructorAction(action, argumentTypes) {
61074
61509
  if (!isNSFunctionWithReturnType(action)) return false;
61075
61510
  if (action.typeInfo.type !== 0 /* Null */) return false;
@@ -62461,7 +62896,7 @@ function readProjectDocument(value, options = {}) {
62461
62896
  constructors: readOptionalArrayField(
62462
62897
  value,
62463
62898
  "constructors",
62464
- isNeoClassConstructor
62899
+ options.constructors === "authored-or-compiled" ? (candidate) => isNeoClassConstructor(candidate) || isUncompiledNeoClassConstructor(candidate) : isNeoClassConstructor
62465
62900
  ),
62466
62901
  internalRecordRelations: readOptionalArrayField(
62467
62902
  value,
@@ -68291,6 +68726,7 @@ function collectNeoScriptRecompileTargets(args) {
68291
68726
  if (args.forceRecompile === true) return completeTargets(args.postDocument);
68292
68727
  const explicit = explicitTargetIds(args.changes);
68293
68728
  const { impactedIds, impactedTypeNames, constructedClassIds } = collectChangedContractIds(args);
68729
+ for (const id2 of args.additionalImpactedIds ?? []) impactedIds.add(id2);
68294
68730
  includeDerivedConstructionContracts(
68295
68731
  constructedClassIds,
68296
68732
  args.postDocument.classes
@@ -68316,13 +68752,21 @@ function collectNeoScriptRecompileTargets(args) {
68316
68752
  }
68317
68753
  }
68318
68754
  const constructorOwnerById = constructorOwners(args.postDocument);
68755
+ const impactedSourceNames = collectImpactedSourceNames({
68756
+ currentDocument: args.currentDocument,
68757
+ postDocument: args.postDocument,
68758
+ impactedIds,
68759
+ impactedTypeNames,
68760
+ constructedClassIds
68761
+ });
68319
68762
  const memberIds = new Set(explicit.memberIds);
68320
68763
  for (const member of args.postDocument.members) {
68321
68764
  if (recordDependsOnChangedContract(
68322
68765
  member,
68323
68766
  impactedIds,
68324
68767
  impactedTypeNames,
68325
- constructedClassIds
68768
+ constructedClassIds,
68769
+ impactedSourceNames
68326
68770
  )) {
68327
68771
  memberIds.add(member.id);
68328
68772
  }
@@ -68333,7 +68777,8 @@ function collectNeoScriptRecompileTargets(args) {
68333
68777
  explicit.valueIds,
68334
68778
  impactedIds,
68335
68779
  impactedTypeNames,
68336
- constructedClassIds
68780
+ constructedClassIds,
68781
+ impactedSourceNames
68337
68782
  );
68338
68783
  if (impactedIds.size > 0 && postValues.length > 0) {
68339
68784
  const ownerByValueId = resolveOwnerMembersForValues(
@@ -68356,6 +68801,7 @@ function collectNeoScriptRecompileTargets(args) {
68356
68801
  impactedIds,
68357
68802
  impactedTypeNames,
68358
68803
  constructedClassIds,
68804
+ impactedSourceNames,
68359
68805
  (record3) => constructorOwnerById.get(record3.id) ?? null
68360
68806
  ),
68361
68807
  migrationIds: selectedRecordIds(
@@ -68363,21 +68809,24 @@ function collectNeoScriptRecompileTargets(args) {
68363
68809
  explicit.migrationIds,
68364
68810
  impactedIds,
68365
68811
  impactedTypeNames,
68366
- constructedClassIds
68812
+ constructedClassIds,
68813
+ impactedSourceNames
68367
68814
  ),
68368
68815
  dialogueNodeIds: selectedRecordIds(
68369
68816
  args.postDocument.dialogueNodes ?? [],
68370
68817
  explicit.dialogueNodeIds,
68371
68818
  impactedIds,
68372
68819
  impactedTypeNames,
68373
- constructedClassIds
68820
+ constructedClassIds,
68821
+ impactedSourceNames
68374
68822
  ),
68375
68823
  dialogueGroupIds: selectedRecordIds(
68376
68824
  args.postDocument.dialogueGroups ?? [],
68377
68825
  explicit.dialogueGroupIds,
68378
68826
  impactedIds,
68379
68827
  impactedTypeNames,
68380
- constructedClassIds
68828
+ constructedClassIds,
68829
+ impactedSourceNames
68381
68830
  ),
68382
68831
  valueIds
68383
68832
  };
@@ -68746,7 +69195,7 @@ function explicitTargetIds(changes) {
68746
69195
  }
68747
69196
  return result;
68748
69197
  }
68749
- function selectedRecordIds(records2, explicitIds, impactedIds, impactedTypeNames, constructedClassIds, ownerId = () => null) {
69198
+ function selectedRecordIds(records2, explicitIds, impactedIds, impactedTypeNames, constructedClassIds, impactedSourceNames, ownerId = () => null) {
68750
69199
  const selected2 = new Set(explicitIds);
68751
69200
  for (const record3 of records2) {
68752
69201
  const owner = ownerId(record3);
@@ -68754,14 +69203,17 @@ function selectedRecordIds(records2, explicitIds, impactedIds, impactedTypeNames
68754
69203
  record3,
68755
69204
  impactedIds,
68756
69205
  impactedTypeNames,
68757
- constructedClassIds
69206
+ constructedClassIds,
69207
+ impactedSourceNames
68758
69208
  )) {
68759
69209
  selected2.add(record3.id);
68760
69210
  }
68761
69211
  }
68762
69212
  return selected2;
68763
69213
  }
68764
- function recordDependsOnChangedContract(record3, impactedIds, impactedTypeNames, constructedClassIds) {
69214
+ function recordDependsOnChangedContract(record3, impactedIds, impactedTypeNames, constructedClassIds, impactedSourceNames) {
69215
+ const recordId = isObjectRecord3(record3) ? record3.id : void 0;
69216
+ if (typeof recordId === "string" && impactedIds.has(recordId)) return true;
68765
69217
  if (intersects(collectCompilerReferenceIds(record3), impactedIds)) return true;
68766
69218
  if (intersects(collectCompilerReferenceNames(record3), impactedTypeNames)) {
68767
69219
  return true;
@@ -68769,7 +69221,109 @@ function recordDependsOnChangedContract(record3, impactedIds, impactedTypeNames,
68769
69221
  if (intersects(collectConstructedClassIds(record3), constructedClassIds)) {
68770
69222
  return true;
68771
69223
  }
68772
- return (impactedIds.size > 0 || impactedTypeNames.size > 0) && containsAuthoredNeoScriptSource(record3) && !containsCompiledNeoScriptBody(record3);
69224
+ if (impactedIds.size === 0 && impactedTypeNames.size === 0) return false;
69225
+ if (!containsAuthoredNeoScriptSource(record3)) return false;
69226
+ if (containsCompiledNeoScriptBody(record3)) return false;
69227
+ if (impactedSourceNames === null) return true;
69228
+ const sourceIdentifiers = collectAuthoredNeoScriptSourceIdentifiers(record3);
69229
+ if (sourceIdentifiers === null) return true;
69230
+ return intersects(sourceIdentifiers, impactedSourceNames);
69231
+ }
69232
+ function collectImpactedSourceNames(args) {
69233
+ const names = new Set(args.impactedTypeNames);
69234
+ let recoveredContract = args.impactedTypeNames.size > 0;
69235
+ const collectDocument = (document) => {
69236
+ const classById = new Map(
69237
+ document.classes.map((schemaClass2) => [schemaClass2.id, schemaClass2])
69238
+ );
69239
+ const ownerByConstructorId = constructorOwners(document);
69240
+ const impactedValueIds = new Set(
69241
+ (document.values ?? []).filter((value) => args.impactedIds.has(value.id)).map((value) => value.id)
69242
+ );
69243
+ const ownerByValueId = resolveOwnerMembersForValues(
69244
+ document,
69245
+ impactedValueIds
69246
+ );
69247
+ for (const owner of ownerByValueId.values()) {
69248
+ recoveredContract = true;
69249
+ collectDeclaredSourceNames(owner, names);
69250
+ const ownerId = Reflect.get(owner, "id");
69251
+ if (typeof ownerId !== "string") continue;
69252
+ for (const classId of classPlacementsForMember(ownerId, document)) {
69253
+ const schemaClass2 = classById.get(classId);
69254
+ if (schemaClass2 !== void 0) {
69255
+ collectDeclaredSourceNames(schemaClass2, names);
69256
+ }
69257
+ }
69258
+ }
69259
+ const records2 = [
69260
+ ...document.classes,
69261
+ ...document.members,
69262
+ ...document.constructors ?? [],
69263
+ ...document.enums,
69264
+ ...document.interfaces ?? [],
69265
+ ...document.values ?? []
69266
+ ];
69267
+ for (const record3 of records2) {
69268
+ if (!args.impactedIds.has(record3.id)) continue;
69269
+ recoveredContract = true;
69270
+ collectDeclaredSourceNames(record3, names);
69271
+ const ownerClassId = ownerByConstructorId.get(record3.id);
69272
+ if (ownerClassId === void 0) continue;
69273
+ const owner = classById.get(ownerClassId);
69274
+ if (owner !== void 0) collectDeclaredSourceNames(owner, names);
69275
+ }
69276
+ for (const schemaClass2 of document.classes) {
69277
+ if (!args.constructedClassIds.has(schemaClass2.id)) continue;
69278
+ recoveredContract = true;
69279
+ collectDeclaredSourceNames(schemaClass2, names);
69280
+ }
69281
+ };
69282
+ collectDocument(args.currentDocument);
69283
+ collectDocument(args.postDocument);
69284
+ return recoveredContract ? names : null;
69285
+ }
69286
+ function collectDeclaredSourceNames(value, names) {
69287
+ if (Array.isArray(value)) {
69288
+ for (const child of value) collectDeclaredSourceNames(child, names);
69289
+ return;
69290
+ }
69291
+ if (!isObjectRecord3(value)) return;
69292
+ for (const [field, child] of Object.entries(value)) {
69293
+ if (typeof child === "string" && (field === "name" || field === "sourceName" || field === "sourceFunctionName" || field === "declaredTypeName" || field === "typeName")) {
69294
+ names.add(child);
69295
+ continue;
69296
+ }
69297
+ collectDeclaredSourceNames(child, names);
69298
+ }
69299
+ }
69300
+ function collectAuthoredNeoScriptSourceIdentifiers(value) {
69301
+ const identifiers = /* @__PURE__ */ new Set();
69302
+ let complete2 = true;
69303
+ const collect = (child) => {
69304
+ if (Array.isArray(child)) {
69305
+ for (const entry of child) collect(entry);
69306
+ return;
69307
+ }
69308
+ if (!isObjectRecord3(child)) return;
69309
+ for (const [field, nested] of Object.entries(child)) {
69310
+ if ((field === "code" || field === "setterCode") && typeof nested === "string") {
69311
+ const result = lex(nested);
69312
+ if (result.diagnostics.some(
69313
+ (diagnostic) => diagnostic.severity === "error"
69314
+ )) {
69315
+ complete2 = false;
69316
+ }
69317
+ for (const token of result.tokens) {
69318
+ if (token.kind === "identifier") identifiers.add(token.text);
69319
+ }
69320
+ continue;
69321
+ }
69322
+ collect(nested);
69323
+ }
69324
+ };
69325
+ collect(value);
69326
+ return complete2 ? identifiers : null;
68773
69327
  }
68774
69328
  function containsAuthoredNeoScriptSource(value) {
68775
69329
  if (Array.isArray(value)) {
@@ -68868,6 +69422,7 @@ var init_neo_script_recompile_scope = __esm({
68868
69422
  "../src/database/neo-script-recompile-scope.ts"() {
68869
69423
  "use strict";
68870
69424
  init_canonical_json();
69425
+ init_src();
68871
69426
  init_member_kind_enum();
68872
69427
  init_inheritance();
68873
69428
  init_effective_storage();
@@ -69230,9 +69785,17 @@ function materializeInitializersLocallyV4(args) {
69230
69785
  );
69231
69786
  if (sourceRoots.size === 0) return { roots: [] };
69232
69787
  let document = readPulledProjectDocumentV4(records2);
69233
- const rootOwners = resolveOwnerMembersForValues(document, sourceRoots);
69788
+ const rootKinds = /* @__PURE__ */ new Map();
69789
+ const rootOwners = resolveOwnerMembersForValues(
69790
+ document,
69791
+ sourceRoots,
69792
+ void 0,
69793
+ void 0,
69794
+ rootKinds
69795
+ );
69234
69796
  const roots = [];
69235
69797
  for (const sourceValueId of sourceRoots) {
69798
+ if (rootKinds.get(sourceValueId) === "declaration") continue;
69236
69799
  const rootOwner = rootOwners.get(sourceValueId);
69237
69800
  if (rootOwner === void 0) {
69238
69801
  throw new Error(
@@ -70280,18 +70843,26 @@ function replayAnimationDeclarationInitializersV4(records2, document) {
70280
70843
  const rootOwner = rootOwners.get(row.id);
70281
70844
  const rootOwnerId = Reflect.get(rootOwner ?? {}, "id");
70282
70845
  const initializerOwnerClass = typeof rootOwnerId !== "string" ? null : findSchemaPlacement(rootOwnerId, document.classes)?.ownerClass ?? null;
70283
- const replay = replayStoredConstructionV4({
70284
- records: pulled,
70285
- valueId: row.id,
70286
- code,
70287
- member: owner,
70288
- compileDocumentBodies: true,
70289
- initializerOwnerClass,
70290
- // A parameterized declaration is a template. Its arguments exist only
70291
- // at concrete construction sites, so validate the authored body here
70292
- // without fabricating values for the class header parameters.
70293
- evaluate: initializerOwnerClass?.requiredConstructorId === void 0 || initializerOwnerClass.requiredConstructorId === null
70294
- });
70846
+ let replay;
70847
+ try {
70848
+ replay = replayStoredConstructionV4({
70849
+ records: pulled,
70850
+ valueId: row.id,
70851
+ code,
70852
+ member: owner,
70853
+ compileDocumentBodies: true,
70854
+ initializerOwnerClass,
70855
+ // A parameterized declaration is a template. Its arguments exist only
70856
+ // at concrete construction sites, so validate the authored body here
70857
+ // without fabricating values for the class header parameters.
70858
+ evaluate: initializerOwnerClass?.requiredConstructorId === void 0 || initializerOwnerClass.requiredConstructorId === null
70859
+ });
70860
+ } catch (error) {
70861
+ throw new Error(
70862
+ `Animation declaration replay failed for value "${row.id}": ${error instanceof Error ? error.message : String(error)}`,
70863
+ { cause: error }
70864
+ );
70865
+ }
70295
70866
  for (const [id2, value] of replay) {
70296
70867
  if (!isMemberValue(value)) {
70297
70868
  throw new Error(
@@ -73970,7 +74541,8 @@ function prepareServerOwnedSchemaCommit(args) {
73970
74541
  const hasValueChange = authoredChanges.some(
73971
74542
  (change) => change.recordKind === "value"
73972
74543
  );
73973
- if (!hasSchemaChange && !hasMigrationChange && !hasDialogueSourceChange && !hasValueChange) {
74544
+ const hasAdditionalContractImpact = (args.additionalImpactedIds?.size ?? 0) > 0;
74545
+ if (!hasSchemaChange && !hasMigrationChange && !hasDialogueSourceChange && !hasValueChange && !hasAdditionalContractImpact) {
73974
74546
  return authoredChanges;
73975
74547
  }
73976
74548
  const authoredPostDocument = applyProjectVersionWriteChanges(
@@ -73981,6 +74553,7 @@ function prepareServerOwnedSchemaCommit(args) {
73981
74553
  currentDocument: args.document,
73982
74554
  postDocument: authoredPostDocument,
73983
74555
  changes: authoredChanges,
74556
+ additionalImpactedIds: args.additionalImpactedIds,
73984
74557
  forceRecompile: args.forceRecompile
73985
74558
  });
73986
74559
  const explicitlyChangedMemberIds = new Set(
@@ -77374,6 +77947,19 @@ function isOpaqueNSTypeInfo(value, ancestors = /* @__PURE__ */ new Set()) {
77374
77947
  if (value.type === 22) {
77375
77948
  return typeof value.interfaceId === "string" && value.interfaceId.length > 0;
77376
77949
  }
77950
+ if (value.type === 25) {
77951
+ if (!Array.isArray(value.argumentTypes) || ancestors.has(value)) {
77952
+ return false;
77953
+ }
77954
+ ancestors.add(value);
77955
+ try {
77956
+ return isOpaqueNSFunctionReturnTypeInfo(value.returnTypeInfo) && value.argumentTypes.every(
77957
+ (argument2) => isOpaqueNSTypeInfo(argument2, ancestors)
77958
+ );
77959
+ } finally {
77960
+ ancestors.delete(value);
77961
+ }
77962
+ }
77377
77963
  if (value.type === 5 || value.type === 6) {
77378
77964
  if (ancestors.has(value)) return false;
77379
77965
  ancestors.add(value);
@@ -77403,6 +77989,11 @@ function opaqueTypeInfoContainsUnknown(value) {
77403
77989
  if (value.type === 5 || value.type === 6 || value.type === 9) {
77404
77990
  return isRecord8(value.entryTypeInfo) && opaqueTypeInfoContainsUnknown(value.entryTypeInfo);
77405
77991
  }
77992
+ if (value.type === 25) {
77993
+ return isRecord8(value.returnTypeInfo) && opaqueTypeInfoContainsUnknown(value.returnTypeInfo) || Array.isArray(value.argumentTypes) && value.argumentTypes.some(
77994
+ (argument2) => isRecord8(argument2) && opaqueTypeInfoContainsUnknown(argument2)
77995
+ );
77996
+ }
77406
77997
  if (value.type !== 7 || !isRecord8(value.typeArguments)) return false;
77407
77998
  return Object.values(value.typeArguments).some(
77408
77999
  (argument2) => isRecord8(argument2) && opaqueTypeInfoContainsUnknown(argument2)
@@ -77417,6 +78008,10 @@ function isOpaqueNSFunctionReturnTypeInfo(value) {
77417
78008
  function isOpaqueNSFunctionArgumentTypeInfo(value) {
77418
78009
  return isOpaqueNSTypeInfo(value) && isOpaqueCallableIdentifier(value.name) && !opaqueTypeInfoContainsUnknown(value);
77419
78010
  }
78011
+ function isOpaqueConstructorArgumentTypeInfo(value) {
78012
+ if (!isRecord8(value)) return false;
78013
+ return isOpaqueNSTypeInfo(value) && (value.name === "value" || isOpaqueCallableIdentifier(value.name)) && !opaqueTypeInfoContainsUnknown(value);
78014
+ }
77420
78015
  function memberSignature(member) {
77421
78016
  if (member.kind === "property") {
77422
78017
  return `property:${member.settable === true}:${stableTypeInfo(member.typeInfo)}`;
@@ -78768,7 +79363,7 @@ function assertOpaqueConstructorValid(declaredConstructor) {
78768
79363
  );
78769
79364
  }
78770
79365
  const argumentTypes = declaredConstructor.argumentTypes;
78771
- if (!argumentTypes.every(isOpaqueNSFunctionArgumentTypeInfo)) {
79366
+ if (!argumentTypes.every(isOpaqueConstructorArgumentTypeInfo)) {
78772
79367
  throw new Error(
78773
79368
  `Constructor "${declaredConstructor.id}" argumentTypes are invalid.`
78774
79369
  );
@@ -80546,6 +81141,7 @@ function replayStoredConstructionV4(args) {
80546
81141
  );
80547
81142
  }
80548
81143
  if (args.evaluate === false) return /* @__PURE__ */ new Map();
81144
+ assertPulledConstructorsCompiled(document);
80549
81145
  const compiledDependencies = /* @__PURE__ */ new Set();
80550
81146
  let materialized;
80551
81147
  for (; ; ) {
@@ -80586,6 +81182,7 @@ function compilePulledProjectDocumentBodiesV4(document) {
80586
81182
  for (const constructor2 of compileArgs.constructors) {
80587
81183
  compileConstructorRecord({ ...compileArgs, constructor: constructor2 });
80588
81184
  }
81185
+ assertPulledConstructorsCompiled(document);
80589
81186
  const ownerClassByMemberId = new Map(
80590
81187
  compileArgs.classes.flatMap(
80591
81188
  (schemaClass2) => Object.values(schemaClass2.schema).map(
@@ -80601,6 +81198,16 @@ function compilePulledProjectDocumentBodiesV4(document) {
80601
81198
  });
80602
81199
  }
80603
81200
  }
81201
+ function assertPulledConstructorsCompiled(document) {
81202
+ const uncompiled = (document.constructors ?? []).find(
81203
+ (constructor2) => !isNeoClassConstructor(constructor2)
81204
+ );
81205
+ if (uncompiled !== void 0) {
81206
+ throw new Error(
81207
+ `Constructor "${uncompiled.id}" was read from authored source but was not compiled before evaluation.`
81208
+ );
81209
+ }
81210
+ }
80604
81211
  function compilePulledMemberInitializerBodyV4(document, memberId) {
80605
81212
  const compileArgs = {
80606
81213
  project: document.project,
@@ -80628,7 +81235,8 @@ function compilePulledMemberInitializerBodyV4(document, memberId) {
80628
81235
  }
80629
81236
  function readPulledProjectDocumentV4(records2) {
80630
81237
  return readProjectDocument(
80631
- pulledProjectDocumentRaw(replayWorkspace(records2))
81238
+ pulledProjectDocumentRaw(replayWorkspace(records2)),
81239
+ { constructors: "authored-or-compiled" }
80632
81240
  );
80633
81241
  }
80634
81242
  function replayWorkspace(records2) {
@@ -80668,6 +81276,7 @@ var init_initializer_replay = __esm({
80668
81276
  init_project_document_read();
80669
81277
  init_server_preparation_preflight();
80670
81278
  init_projection();
81279
+ init_constructors2();
80671
81280
  init_neoscript_evaluator();
80672
81281
  }
80673
81282
  });
@@ -81035,7 +81644,12 @@ function buildValueLowerContext(state, manifest, options = {}) {
81035
81644
  const classesByName = new Map(
81036
81645
  manifest.classes.map((entry) => [entry.name, entry])
81037
81646
  );
81038
- const declaredConstructorIndex = options.analysis === void 0 ? EMPTY_DECLARED_CONSTRUCTOR_INDEX : buildDeclaredConstructorIndex(options.analysis);
81647
+ const sourceConstructorIndex = options.analysis === void 0 ? EMPTY_DECLARED_CONSTRUCTOR_INDEX : buildDeclaredConstructorIndex(options.analysis);
81648
+ const declaredConstructorIndex = withPersistedConstructorSignatures(
81649
+ sourceConstructorIndex,
81650
+ manifest.classes,
81651
+ manifest.constructors
81652
+ );
81039
81653
  return {
81040
81654
  state,
81041
81655
  members,
@@ -87199,20 +87813,172 @@ async function fetchProjectDocument(workspace) {
87199
87813
  });
87200
87814
  }
87201
87815
  }
87816
+ const revision = readProjectDocumentRevisionMarker2(raw);
87202
87817
  return {
87203
87818
  records: records2,
87204
87819
  heads,
87205
- raw
87820
+ raw,
87821
+ ...revision === null ? {} : { revision }
87822
+ };
87823
+ }
87824
+ async function fetchProjectDocumentSyncMarker(workspace) {
87825
+ const convex = await createConvexClient(workspace);
87826
+ return queryProjectDocumentSyncMarker(workspace, convex);
87827
+ }
87828
+ async function queryProjectDocumentSyncMarker(workspace, convex) {
87829
+ const [revisionValue, signal] = await Promise.all([
87830
+ convex.query(api2.projectDocuments.getDocumentRevision, {
87831
+ projectId: workspace.config.projectId,
87832
+ versionId: workspace.config.versionId
87833
+ }),
87834
+ convex.query(api2.projectExportData.schemaSignal, {
87835
+ projectId: workspace.config.projectId,
87836
+ versionId: workspace.config.versionId
87837
+ })
87838
+ ]);
87839
+ if (!isProjectDocumentRevisionMarker(revisionValue)) {
87840
+ throw new Error(
87841
+ "Project document revision query returned an invalid cursor marker."
87842
+ );
87843
+ }
87844
+ return {
87845
+ revision: revisionValue,
87846
+ headTransactionId: signal?.transactionId ?? null,
87847
+ headTransactionHash: signal?.transactionHash ?? null
87848
+ };
87849
+ }
87850
+ async function fetchProjectDocumentDelta(workspace, cursor) {
87851
+ const convex = await createConvexClient(workspace);
87852
+ const marker = await queryProjectDocumentSyncMarker(workspace, convex);
87853
+ if (marker.revision.versionsStamp !== cursor.versionsStamp) {
87854
+ return {
87855
+ fullResync: true,
87856
+ headTransactionHash: marker.headTransactionHash
87857
+ };
87858
+ }
87859
+ if (marker.headTransactionId === marker.revision.latestTransactionId && marker.headTransactionHash === workspace.state.headTransactionHash) {
87860
+ return {
87861
+ fullResync: false,
87862
+ document: projectDocumentFromWorkspaceState(workspace.state, cursor),
87863
+ changedKeys: /* @__PURE__ */ new Set(),
87864
+ cursor,
87865
+ headTransactionHash: marker.headTransactionHash
87866
+ };
87867
+ }
87868
+ const result = await convex.query(api2.projectDocuments.getRecordsSince, {
87869
+ projectId: workspace.config.projectId,
87870
+ versionId: workspace.config.versionId,
87871
+ sinceCreatedAt: cursor.createdAt,
87872
+ seenTransactionIds: [...cursor.transactionIds]
87873
+ });
87874
+ if (result.fullResync) {
87875
+ return {
87876
+ fullResync: true,
87877
+ headTransactionHash: marker.headTransactionHash
87878
+ };
87879
+ }
87880
+ const document = projectDocumentFromWorkspaceState(workspace.state, cursor);
87881
+ const { records: records2, heads } = document;
87882
+ const changedKeys = /* @__PURE__ */ new Set();
87883
+ for (const record3 of result.records) {
87884
+ const key = `${record3.recordKind}:${record3.recordId}`;
87885
+ changedKeys.add(key);
87886
+ if (record3.deleted) {
87887
+ records2.delete(key);
87888
+ heads.set(key, {
87889
+ recordKind: record3.recordKind,
87890
+ recordId: record3.recordId,
87891
+ contentHash: "",
87892
+ deleted: true
87893
+ });
87894
+ continue;
87895
+ }
87896
+ if (record3.contentHash === null) {
87897
+ throw new Error(
87898
+ `Project document delta record "${key}" is live but has no content hash.`
87899
+ );
87900
+ }
87901
+ records2.set(key, {
87902
+ recordKind: record3.recordKind,
87903
+ recordId: record3.recordId,
87904
+ contentHash: record3.contentHash,
87905
+ deleted: false,
87906
+ data: record3.data
87907
+ });
87908
+ heads.set(key, {
87909
+ recordKind: record3.recordKind,
87910
+ recordId: record3.recordId,
87911
+ contentHash: record3.contentHash,
87912
+ deleted: false
87913
+ });
87914
+ }
87915
+ const next = result.cursor ?? cursor;
87916
+ const nextCursor = {
87917
+ createdAt: next.createdAt,
87918
+ transactionIds: [...next.transactionIds],
87919
+ versionsStamp: marker.revision.versionsStamp
87920
+ };
87921
+ return {
87922
+ fullResync: false,
87923
+ document: projectDocumentWithRevision(document, nextCursor),
87924
+ changedKeys,
87925
+ cursor: nextCursor,
87926
+ headTransactionHash: marker.headTransactionHash
87206
87927
  };
87207
87928
  }
87208
- var fetchProjectDocumentRawChunked2, readProjectDocumentContentHashHeads2, SOURCE_RECORD_KINDS;
87929
+ function projectDocumentFromWorkspaceState(state, cursor) {
87930
+ const records2 = serverRecordsFromWorkspaceState(state);
87931
+ const heads = new Map(
87932
+ [...records2].map(([key, record3]) => [
87933
+ key,
87934
+ {
87935
+ recordKind: record3.recordKind,
87936
+ recordId: record3.recordId,
87937
+ contentHash: record3.contentHash,
87938
+ deleted: false
87939
+ }
87940
+ ])
87941
+ );
87942
+ return projectDocumentWithRevision({ records: records2, heads, raw: {} }, cursor);
87943
+ }
87944
+ function projectDocumentWithRevision(document, cursor) {
87945
+ return {
87946
+ ...document,
87947
+ revision: {
87948
+ latestTransactionId: cursor.transactionIds[cursor.transactionIds.length - 1] ?? null,
87949
+ latestTransactionCreatedAt: cursor.createdAt,
87950
+ versionsStamp: cursor.versionsStamp
87951
+ }
87952
+ };
87953
+ }
87954
+ function serverRecordsFromWorkspaceState(state) {
87955
+ const records2 = /* @__PURE__ */ new Map();
87956
+ for (const [key, record3] of Object.entries(state.records)) {
87957
+ if (record3.conflictServerHash === null) continue;
87958
+ const conflictServerHash = record3.conflictServerHash;
87959
+ const hasConflictServer = conflictServerHash !== void 0;
87960
+ records2.set(key, {
87961
+ recordKind: record3.recordKind,
87962
+ recordId: record3.recordId,
87963
+ contentHash: hasConflictServer ? conflictServerHash : record3.contentHash,
87964
+ deleted: false,
87965
+ data: hasConflictServer ? record3.conflictServerData : record3.data
87966
+ });
87967
+ }
87968
+ return records2;
87969
+ }
87970
+ var fetchProjectDocumentRawChunked2, readProjectDocumentContentHashHeads2, readProjectDocumentRevisionMarker2, SOURCE_RECORD_KINDS;
87209
87971
  var init_document = __esm({
87210
87972
  "src/document.ts"() {
87211
87973
  "use strict";
87212
87974
  init_project_document_read();
87213
87975
  init_project2();
87214
87976
  init_convex();
87215
- ({ fetchProjectDocumentRawChunked: fetchProjectDocumentRawChunked2, readProjectDocumentContentHashHeads: readProjectDocumentContentHashHeads2 } = project_document_read_exports);
87977
+ ({
87978
+ fetchProjectDocumentRawChunked: fetchProjectDocumentRawChunked2,
87979
+ readProjectDocumentContentHashHeads: readProjectDocumentContentHashHeads2,
87980
+ readProjectDocumentRevisionMarker: readProjectDocumentRevisionMarker2
87981
+ } = project_document_read_exports);
87216
87982
  SOURCE_RECORD_KINDS = new Set(
87217
87983
  Object.values(ProjectRecordKind)
87218
87984
  );
@@ -87899,6 +88665,7 @@ var init_static_value_seed_records = __esm({
87899
88665
  // src/commands/pull.ts
87900
88666
  var pull_exports = {};
87901
88667
  __export(pull_exports, {
88668
+ deltaRequiresSourceProjectionV4: () => deltaRequiresSourceProjectionV4,
87902
88669
  projectSourcePathsRequiringRewriteV4: () => projectSourcePathsRequiringRewriteV4,
87903
88670
  runPull: () => runPull
87904
88671
  });
@@ -87915,6 +88682,15 @@ async function runPull(workspace, options) {
87915
88682
  await runResetPull(workspace);
87916
88683
  return;
87917
88684
  }
88685
+ const progress = spinner("Checking local workspace\u2026");
88686
+ try {
88687
+ await runNormalPull(workspace, options, progress);
88688
+ } catch (error) {
88689
+ progress.fail("Pull failed.");
88690
+ throw error;
88691
+ }
88692
+ }
88693
+ async function runNormalPull(workspace, options, progress) {
87918
88694
  const destructive = options.force;
87919
88695
  const hasBaseline = Object.keys(workspace.state.records).length > 0;
87920
88696
  let localByKey = /* @__PURE__ */ new Map();
@@ -87943,25 +88719,54 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
87943
88719
  ])
87944
88720
  );
87945
88721
  }
87946
- if (!destructive && !options.regenerateSourceNames && workspace.state.headTransactionHash !== void 0) {
87947
- const convex = await createConvexClient(workspace);
87948
- const signal = await convex.query(api2.projectExportData.schemaSignal, {
87949
- projectId: workspace.config.projectId,
87950
- versionId: workspace.config.versionId
87951
- });
87952
- if (signal !== null && signal.transactionHash === workspace.state.headTransactionHash && localByKey.size > 0) {
87953
- const dirtyRecords = [...localByKey.entries()].some(([key, local]) => {
87954
- const base = workspace.state.records[key];
87955
- return base === void 0 || !authoredRecordsSemanticallyEqual(base.recordKind, local, base.data);
87956
- });
87957
- const dirtyBinaries = (localStatus?.binaryChanges?.length ?? 0) > 0;
87958
- if (!dirtyRecords && !dirtyBinaries) {
87959
- console.log("Already up to date (sync-signal head unchanged).");
88722
+ let changedRecordKeys = null;
88723
+ let nextCursor = null;
88724
+ let observedHeadTransactionHash;
88725
+ let document = null;
88726
+ if (!destructive && hasBaseline) {
88727
+ progress.update("Checking remote changes\u2026");
88728
+ const cursor = workspace.state.documentRevisionCursor;
88729
+ if (cursor !== void 0) {
88730
+ const delta = await fetchProjectDocumentDelta(workspace, cursor);
88731
+ observedHeadTransactionHash = delta.headTransactionHash;
88732
+ if (!delta.fullResync) {
88733
+ document = delta.document;
88734
+ changedRecordKeys = delta.changedKeys;
88735
+ nextCursor = delta.cursor;
88736
+ if (delta.changedKeys.size === 0 && !options.regenerateSourceNames) {
88737
+ const cursorChanged = !cursorsEqual(
88738
+ workspace.state.documentRevisionCursor,
88739
+ delta.cursor
88740
+ );
88741
+ const headChanged = workspace.state.headTransactionHash !== delta.headTransactionHash;
88742
+ if (cursorChanged || headChanged) {
88743
+ workspace.state.documentRevisionCursor = mutableCursor(
88744
+ delta.cursor
88745
+ );
88746
+ workspace.state.headTransactionHash = delta.headTransactionHash;
88747
+ writeWorkspaceState(workspace.root, workspace.state);
88748
+ }
88749
+ progress.succeed("Already up to date.");
88750
+ return;
88751
+ }
88752
+ }
88753
+ } else if (!options.regenerateSourceNames && workspace.state.headTransactionHash !== void 0) {
88754
+ const marker = await fetchProjectDocumentSyncMarker(workspace);
88755
+ observedHeadTransactionHash = marker.headTransactionHash;
88756
+ if (marker.headTransactionId === marker.revision.latestTransactionId && marker.headTransactionHash === workspace.state.headTransactionHash) {
88757
+ const seededCursor = cursorFromRevision(marker.revision);
88758
+ workspace.state.documentRevisionCursor = mutableCursor(seededCursor);
88759
+ writeWorkspaceState(workspace.root, workspace.state);
88760
+ progress.succeed("Already up to date.");
87960
88761
  return;
87961
88762
  }
87962
88763
  }
87963
88764
  }
87964
- const document = await fetchProjectDocument(workspace);
88765
+ if (document === null) {
88766
+ progress.update("Downloading full project snapshot\u2026");
88767
+ document = await fetchProjectDocument(workspace);
88768
+ nextCursor = document.revision === void 0 ? null : cursorFromRevision(document.revision);
88769
+ }
87965
88770
  const plans = /* @__PURE__ */ new Map();
87966
88771
  let mergedCount = 0;
87967
88772
  let conflictCount = 0;
@@ -88081,7 +88886,11 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
88081
88886
  conflictKeys,
88082
88887
  localStatus,
88083
88888
  destructive,
88084
- regenerateSourceNames: destructive || options.regenerateSourceNames
88889
+ regenerateSourceNames: destructive || options.regenerateSourceNames,
88890
+ changedRecordKeys,
88891
+ nextCursor,
88892
+ observedHeadTransactionHash,
88893
+ progress
88085
88894
  });
88086
88895
  }
88087
88896
  async function runResetPull(workspace) {
@@ -88111,10 +88920,17 @@ async function runResetPull(workspace) {
88111
88920
  projectId: workspace.config.projectId,
88112
88921
  versionId: workspace.config.versionId
88113
88922
  });
88114
- workspace.state.headTransactionHash = signal?.transactionHash ?? null;
88923
+ workspace.state.headTransactionHash = document.revision !== void 0 && signal?.transactionId === document.revision.latestTransactionId ? signal.transactionHash : null;
88115
88924
  } catch {
88116
88925
  workspace.state.headTransactionHash = null;
88117
88926
  }
88927
+ if (document.revision !== void 0) {
88928
+ workspace.state.documentRevisionCursor = mutableCursor(
88929
+ cursorFromRevision(document.revision)
88930
+ );
88931
+ } else {
88932
+ delete workspace.state.documentRevisionCursor;
88933
+ }
88118
88934
  writeWorkspaceState(workspace.root, workspace.state);
88119
88935
  progress.succeed(
88120
88936
  `Pulled ${document.records.size} records \u2014 ${reset.written} file(s) updated \u2014 ${reset.removed} removed.`
@@ -88134,8 +88950,30 @@ async function finishFormat4Pull(args) {
88134
88950
  conflictKeys,
88135
88951
  localStatus,
88136
88952
  destructive,
88137
- regenerateSourceNames
88953
+ regenerateSourceNames,
88954
+ changedRecordKeys,
88955
+ nextCursor,
88956
+ observedHeadTransactionHash,
88957
+ progress
88138
88958
  } = args;
88959
+ if (changedRecordKeys !== null && !regenerateSourceNames && conflictCount === 0 && localStatus !== null && !deltaRequiresSourceProjectionV4({
88960
+ workspace,
88961
+ document,
88962
+ plans,
88963
+ localStatus,
88964
+ changedRecordKeys
88965
+ })) {
88966
+ finishRecordOnlyDeltaPull({
88967
+ workspace,
88968
+ document,
88969
+ changedRecordKeys,
88970
+ nextCursor,
88971
+ observedHeadTransactionHash,
88972
+ progress
88973
+ });
88974
+ return;
88975
+ }
88976
+ progress.update("Regenerating affected Neo sources\u2026");
88139
88977
  const plannedLocalRecords = buildEmitRecordSet(document, plans, "emit");
88140
88978
  for (const [key, record3] of staticValueSeedEmitRecords(
88141
88979
  localStatus,
@@ -88150,7 +88988,7 @@ async function finishFormat4Pull(args) {
88150
88988
  )
88151
88989
  );
88152
88990
  const localResult = emitProjectDocumentFilesV4(localRecords);
88153
- const serverResult = emitProjectDocumentFilesV4(
88991
+ const serverResult = conflictCount === 0 ? null : emitProjectDocumentFilesV4(
88154
88992
  buildEmitRecordSet(document, plans, "server")
88155
88993
  );
88156
88994
  const binaries = await pullProjectBinariesV4({
@@ -88164,11 +89002,11 @@ async function finishFormat4Pull(args) {
88164
89002
  localResult.files.map((file) => [file.path, file])
88165
89003
  );
88166
89004
  const serverByPath = new Map(
88167
- serverResult.files.map((file) => [file.path, file])
89005
+ (serverResult?.files ?? []).map((file) => [file.path, file])
88168
89006
  );
88169
89007
  const conflictPaths = /* @__PURE__ */ new Set();
88170
89008
  for (const key of conflictKeys) {
88171
- const path = localResult.recordFiles.get(key) ?? serverResult.recordFiles.get(key);
89009
+ const path = localResult.recordFiles.get(key) ?? serverResult?.recordFiles.get(key);
88172
89010
  if (path) conflictPaths.add(path);
88173
89011
  }
88174
89012
  const emittedPaths = /* @__PURE__ */ new Set([
@@ -88180,7 +89018,7 @@ async function finishFormat4Pull(args) {
88180
89018
  localStatus,
88181
89019
  plans,
88182
89020
  localRecordFiles: localResult.recordFiles,
88183
- serverRecordFiles: serverResult.recordFiles,
89021
+ serverRecordFiles: serverResult?.recordFiles ?? /* @__PURE__ */ new Map(),
88184
89022
  previousRecords: workspace.state.records,
88185
89023
  conflictPaths,
88186
89024
  emittedPaths,
@@ -88230,7 +89068,7 @@ async function finishFormat4Pull(args) {
88230
89068
  if (baseState) records2[key] = { ...baseState };
88231
89069
  continue;
88232
89070
  }
88233
- const file = localResult.recordFiles.get(key) ?? serverResult.recordFiles.get(key);
89071
+ const file = localResult.recordFiles.get(key) ?? serverResult?.recordFiles.get(key) ?? baseState?.file;
88234
89072
  records2[key] = plan.conflicted ? {
88235
89073
  recordKind,
88236
89074
  recordId,
@@ -88249,7 +89087,7 @@ async function finishFormat4Pull(args) {
88249
89087
  }
88250
89088
  for (const [key, serverRecord] of document.records) {
88251
89089
  if (serverRecord.deleted || records2[key]) continue;
88252
- const file = localResult.recordFiles.get(key) ?? serverResult.recordFiles.get(key);
89090
+ const file = localResult.recordFiles.get(key) ?? serverResult?.recordFiles.get(key);
88253
89091
  records2[key] = {
88254
89092
  recordKind: serverRecord.recordKind,
88255
89093
  recordId: serverRecord.recordId,
@@ -88263,30 +89101,37 @@ async function finishFormat4Pull(args) {
88263
89101
  if (record3) record3.projectBinary = state;
88264
89102
  }
88265
89103
  workspace.state.records = records2;
88266
- try {
88267
- const convex = await createConvexClient(workspace);
88268
- const signal = await convex.query(api2.projectExportData.schemaSignal, {
88269
- projectId: workspace.config.projectId,
88270
- versionId: workspace.config.versionId
88271
- });
88272
- workspace.state.headTransactionHash = signal?.transactionHash ?? null;
88273
- } catch {
88274
- workspace.state.headTransactionHash = null;
89104
+ if (nextCursor !== null) {
89105
+ workspace.state.documentRevisionCursor = mutableCursor(nextCursor);
89106
+ }
89107
+ if (observedHeadTransactionHash !== void 0) {
89108
+ workspace.state.headTransactionHash = observedHeadTransactionHash;
89109
+ } else {
89110
+ try {
89111
+ const convex = await createConvexClient(workspace);
89112
+ const signal = await convex.query(api2.projectExportData.schemaSignal, {
89113
+ projectId: workspace.config.projectId,
89114
+ versionId: workspace.config.versionId
89115
+ });
89116
+ workspace.state.headTransactionHash = document.revision !== void 0 && signal?.transactionId === document.revision.latestTransactionId ? signal.transactionHash : null;
89117
+ } catch {
89118
+ workspace.state.headTransactionHash = null;
89119
+ }
88275
89120
  }
88276
89121
  writeWorkspaceState(workspace.root, workspace.state);
88277
89122
  if (conflictCount === 0) {
88278
89123
  writeProjectSourceAnalysisCacheV4(workspace.root, localResult.analysis);
88279
- writeMaterializedConstructionBuildCacheV1(
88280
- workspace.root,
88281
- workspace.state,
88282
- // The cache is a baseline for workspace.state, not the merged authored
88283
- // tree. Retaining a local constructor edit here would bless it as the
88284
- // pulled construction and bypass the P61 recreate-conflict check.
88285
- serverResult.materializedConstructors
88286
- );
89124
+ if (localStatus === null || localStatus.changes.length === 0) {
89125
+ writeMaterializedConstructionBuildCacheV1(
89126
+ workspace.root,
89127
+ workspace.state,
89128
+ localResult.materializedConstructors
89129
+ );
89130
+ }
88287
89131
  }
89132
+ const pulledRecords = changedRecordKeys === null ? `Pulled ${document.records.size} records` : `Pulled ${changedRecordKeys.size} changed record(s)`;
88288
89133
  const summary = [
88289
- `Pulled ${document.records.size} records`,
89134
+ pulledRecords,
88290
89135
  `${written} file(s) updated`,
88291
89136
  `${removed} removed`
88292
89137
  ];
@@ -88297,7 +89142,7 @@ async function finishFormat4Pull(args) {
88297
89142
  if (mergedCount > 0)
88298
89143
  summary.push(color.green(`${mergedCount} merged cleanly`));
88299
89144
  if (conflictCount > 0) summary.push(color.red(`${conflictCount} CONFLICTED`));
88300
- console.log(`${summary.join(" \u2014 ")}.`);
89145
+ progress.succeed(`${summary.join(" \u2014 ")}.`);
88301
89146
  if (conflictCount > 0) {
88302
89147
  warn(
88303
89148
  'Conflict markers were written into the affected files. Edit them to the desired final state and push \u2014 the push is the resolution. To keep one side everywhere, use "neo resolve --mine" or "neo resolve --theirs".'
@@ -88311,6 +89156,98 @@ async function finishFormat4Pull(args) {
88311
89156
  for (const path of binaries.conflicts) console.log(` ${sym.fail} ${path}`);
88312
89157
  }
88313
89158
  }
89159
+ function deltaRequiresSourceProjectionV4(args) {
89160
+ const mainLocale = workspaceMainLocale(args.workspace.state.records);
89161
+ for (const key of args.changedRecordKeys) {
89162
+ const previous = args.workspace.state.records[key];
89163
+ const local = args.localStatus.reconstructed.get(key)?.fullData;
89164
+ const plan = args.plans.get(key);
89165
+ const server = args.document.records.get(key);
89166
+ if (server === void 0) {
89167
+ if (previous?.file !== void 0 || local !== void 0) return true;
89168
+ continue;
89169
+ }
89170
+ if (local === void 0 || plan?.emitData === void 0) {
89171
+ if (previous?.file !== void 0 || previous === void 0) return true;
89172
+ continue;
89173
+ }
89174
+ if (!sourceAuthoredRecordsSemanticallyEqual(
89175
+ server.recordKind,
89176
+ plan.emitData,
89177
+ local,
89178
+ mainLocale
89179
+ )) {
89180
+ return true;
89181
+ }
89182
+ }
89183
+ return false;
89184
+ }
89185
+ function finishRecordOnlyDeltaPull(args) {
89186
+ const cachedExpressions = readMaterializedConstructionBuildCacheV1(
89187
+ args.workspace.root,
89188
+ args.workspace.state
89189
+ );
89190
+ const records2 = { ...args.workspace.state.records };
89191
+ for (const key of args.changedRecordKeys) {
89192
+ const server = args.document.records.get(key);
89193
+ if (server === void 0) {
89194
+ delete records2[key];
89195
+ continue;
89196
+ }
89197
+ const previous = records2[key];
89198
+ records2[key] = {
89199
+ recordKind: server.recordKind,
89200
+ recordId: server.recordId,
89201
+ contentHash: server.contentHash,
89202
+ data: server.data,
89203
+ ...previous?.file === void 0 ? {} : { file: previous.file },
89204
+ ...previous?.projectBinary === void 0 ? {} : { projectBinary: previous.projectBinary }
89205
+ };
89206
+ }
89207
+ args.workspace.state.records = records2;
89208
+ if (args.nextCursor !== null) {
89209
+ args.workspace.state.documentRevisionCursor = mutableCursor(
89210
+ args.nextCursor
89211
+ );
89212
+ }
89213
+ if (args.observedHeadTransactionHash !== void 0) {
89214
+ args.workspace.state.headTransactionHash = args.observedHeadTransactionHash;
89215
+ }
89216
+ writeWorkspaceState(args.workspace.root, args.workspace.state);
89217
+ if (cachedExpressions !== null) {
89218
+ writeMaterializedConstructionBuildCacheV1(
89219
+ args.workspace.root,
89220
+ args.workspace.state,
89221
+ cachedExpressions
89222
+ );
89223
+ }
89224
+ args.progress.succeed(
89225
+ `Pulled ${args.changedRecordKeys.size} changed record(s) \u2014 0 file(s) updated \u2014 0 removed.`
89226
+ );
89227
+ }
89228
+ function cursorFromRevision(revision) {
89229
+ return {
89230
+ createdAt: revision.latestTransactionCreatedAt,
89231
+ transactionIds: revision.latestTransactionId === null ? [] : [revision.latestTransactionId],
89232
+ versionsStamp: revision.versionsStamp
89233
+ };
89234
+ }
89235
+ function mutableCursor(cursor) {
89236
+ return {
89237
+ createdAt: cursor.createdAt,
89238
+ transactionIds: [...cursor.transactionIds],
89239
+ versionsStamp: cursor.versionsStamp
89240
+ };
89241
+ }
89242
+ function cursorsEqual(left, right) {
89243
+ if (left === void 0) return false;
89244
+ if (left.createdAt !== right.createdAt) return false;
89245
+ if (left.versionsStamp !== right.versionsStamp) return false;
89246
+ if (left.transactionIds.length !== right.transactionIds.length) return false;
89247
+ return left.transactionIds.every(
89248
+ (transactionId, index) => transactionId === right.transactionIds[index]
89249
+ );
89250
+ }
88314
89251
  function projectSourcePathsRequiringRewriteV4(args) {
88315
89252
  if (args.destructive || args.localStatus === null) {
88316
89253
  return new Set(args.emittedPaths);