@neocompose/cli 0.5.4 → 0.6.1

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/neo.mjs +383 -51
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.6.0] - 2026-07-19
4
+
5
+ ### Added
6
+
7
+ - Member access modifiers. Class and interface members now carry a required
8
+ `accessModifier` (`public` / `protected` / `private`); the source lowering
9
+ and emitter read and write the keyword, defaulting to `private` on classes
10
+ and `public` on interfaces when omitted, mirroring C#. The schema-commit
11
+ path enforces the same access rules as the web app.
12
+
3
13
  ## [0.5.4] - 2026-07-19
4
14
 
5
15
  ### Fixed
package/dist/neo.mjs CHANGED
@@ -829,6 +829,7 @@ var init_document_contracts = __esm({
829
829
  "isStatic",
830
830
  "isVirtual",
831
831
  "isAbstract",
832
+ "accessModifierKind",
832
833
  "defaultValue",
833
834
  "extendsMemberId",
834
835
  "system",
@@ -1528,6 +1529,11 @@ function memberFromDocument(record3, members, owners, classNames, context) {
1528
1529
  owner: owners.get(record3.recordId) ?? { kind: "loose" },
1529
1530
  name: requiredString(data, "name", record3),
1530
1531
  isStatic: booleanValue(data.isStatic, record3, "isStatic"),
1532
+ accessModifier: accessModifierValue(
1533
+ data.accessModifierKind,
1534
+ record3,
1535
+ "accessModifierKind"
1536
+ ),
1531
1537
  modifier,
1532
1538
  locked: booleanValue(field("locked", false), record3, "locked"),
1533
1539
  required: booleanValue(field("required", false), record3, "required"),
@@ -1770,7 +1776,8 @@ function memberToDocumentFields(member, baseData3) {
1770
1776
  kind,
1771
1777
  locked: member.locked,
1772
1778
  required: member.required,
1773
- isStatic: member.isStatic
1779
+ isStatic: member.isStatic,
1780
+ accessModifierKind: member.accessModifier
1774
1781
  };
1775
1782
  applyModifier(fields, member, baseData3);
1776
1783
  if (member.defaultValue !== null) {
@@ -2370,6 +2377,16 @@ function optionalNumberOrNull(value, record3, path) {
2370
2377
  if (value === void 0 || value === null) return null;
2371
2378
  return requiredNumberValue(value, record3, path);
2372
2379
  }
2380
+ function accessModifierValue(value, record3, path) {
2381
+ if (value !== "public" && value !== "protected" && value !== "private") {
2382
+ throw invalidDocument(
2383
+ record3,
2384
+ path,
2385
+ "must be public, protected, or private"
2386
+ );
2387
+ }
2388
+ return value;
2389
+ }
2373
2390
  function requiredString(value, key, record3) {
2374
2391
  return requiredStringValue(value[key], record3, key);
2375
2392
  }
@@ -2626,6 +2643,11 @@ function interfaceFromDocument(record3, context) {
2626
2643
  );
2627
2644
  const memberId = requiredString(member, "id", record3);
2628
2645
  const memberSource = nestedSource(source, "interfaceMember", memberId);
2646
+ const accessModifier = accessModifierValue(
2647
+ member.accessModifierKind,
2648
+ record3,
2649
+ `members.${name}.accessModifierKind`
2650
+ );
2629
2651
  if (member.kind === "property") {
2630
2652
  return {
2631
2653
  id: memberId,
@@ -2641,6 +2663,7 @@ function interfaceFromDocument(record3, context) {
2641
2663
  record3,
2642
2664
  `members.${name}.settable`
2643
2665
  ),
2666
+ accessModifier,
2644
2667
  source: memberSource
2645
2668
  };
2646
2669
  }
@@ -2664,6 +2687,7 @@ function interfaceFromDocument(record3, context) {
2664
2687
  record3,
2665
2688
  `members.${name}.deferred`
2666
2689
  ),
2690
+ accessModifier,
2667
2691
  source: memberSource
2668
2692
  };
2669
2693
  }
@@ -2683,7 +2707,8 @@ function interfaceToDocument(neoInterface) {
2683
2707
  id: member.id,
2684
2708
  kind: "property",
2685
2709
  typeInfo: manifestTypeToDocument(member.type),
2686
- settable: member.settable
2710
+ settable: member.settable,
2711
+ accessModifierKind: member.accessModifier
2687
2712
  };
2688
2713
  } else {
2689
2714
  members[member.name] = {
@@ -2694,7 +2719,8 @@ function interfaceToDocument(neoInterface) {
2694
2719
  name: argument2.name,
2695
2720
  ...manifestTypeToDocument(argument2.type)
2696
2721
  })),
2697
- deferred: member.deferred
2722
+ deferred: member.deferred,
2723
+ accessModifierKind: member.accessModifier
2698
2724
  };
2699
2725
  }
2700
2726
  }
@@ -3480,6 +3506,9 @@ var init_language_spec = __esm({
3480
3506
  "interface",
3481
3507
  "native",
3482
3508
  "override",
3509
+ "private",
3510
+ "protected",
3511
+ "public",
3483
3512
  "return",
3484
3513
  "sealed",
3485
3514
  "static",
@@ -3779,6 +3808,66 @@ function createProjectIndex(project) {
3779
3808
  indexesByListMemberId
3780
3809
  };
3781
3810
  }
3811
+ function memberAccessFailure(args) {
3812
+ const access = args.symbol.accessModifier;
3813
+ if (access === void 0) return null;
3814
+ if (access === "public") return null;
3815
+ const declaringTypeId = args.symbol.inheritedFrom?.typeId ?? args.owner.id;
3816
+ const declaringTypeName = args.symbol.inheritedFrom?.typeName ?? args.owner.name;
3817
+ const accessing = args.context.declaringType ?? args.context.thisClass;
3818
+ const accessingTypeId = accessing?.kind === "named" ? accessing.typeId : void 0;
3819
+ if (access === "private") {
3820
+ if (accessingTypeId === declaringTypeId) return null;
3821
+ return { kind: "private", declaringTypeName };
3822
+ }
3823
+ if (args.owner.kind === "interface") {
3824
+ if (accessingTypeId !== void 0 && classFamilyImplementsInterface(
3825
+ args.project,
3826
+ accessingTypeId,
3827
+ declaringTypeId
3828
+ )) {
3829
+ return null;
3830
+ }
3831
+ return { kind: "interfaceProtected", interfaceName: declaringTypeName };
3832
+ }
3833
+ if (accessingTypeId !== void 0 && typeExtendsInclusive(args.project, accessingTypeId, declaringTypeId)) {
3834
+ return null;
3835
+ }
3836
+ return { kind: "protected", declaringTypeName };
3837
+ }
3838
+ function typeExtendsInclusive(project, typeId, ancestorTypeId) {
3839
+ const visited = /* @__PURE__ */ new Set();
3840
+ const queue = [typeId];
3841
+ while (queue.length > 0) {
3842
+ const current = queue.shift();
3843
+ if (current === ancestorTypeId) return true;
3844
+ if (visited.has(current)) continue;
3845
+ visited.add(current);
3846
+ const type = project.typeById.get(current);
3847
+ for (const baseTypeId of type?.baseTypeIds ?? []) queue.push(baseTypeId);
3848
+ }
3849
+ return false;
3850
+ }
3851
+ function classFamilyImplementsInterface(project, classTypeId, interfaceTypeId) {
3852
+ const visitedClasses = /* @__PURE__ */ new Set();
3853
+ const classQueue = [classTypeId];
3854
+ while (classQueue.length > 0) {
3855
+ const current = classQueue.shift();
3856
+ if (visitedClasses.has(current)) continue;
3857
+ visitedClasses.add(current);
3858
+ const type = project.typeById.get(current);
3859
+ if (type === void 0) continue;
3860
+ for (const interfaceId of type.interfaceTypeIds ?? []) {
3861
+ if (typeExtendsInclusive(project, interfaceId, interfaceTypeId)) {
3862
+ return true;
3863
+ }
3864
+ }
3865
+ for (const baseTypeId of type.baseTypeIds ?? []) {
3866
+ classQueue.push(baseTypeId);
3867
+ }
3868
+ }
3869
+ return false;
3870
+ }
3782
3871
  function withNullability(type, nullable) {
3783
3872
  return { ...type, nullable };
3784
3873
  }
@@ -4457,11 +4546,23 @@ function completionItemsForResolution(snapshot, resolved, word) {
4457
4546
  return resolved.staticType.members.filter((member) => member.kind === "enumMember").map((member) => symbolCompletion(member, word, snapshot));
4458
4547
  }
4459
4548
  if (resolved.staticType) {
4460
- return resolved.staticType.members.filter((member) => member.static === true).map((member) => symbolCompletion(member, word, snapshot));
4461
- }
4462
- return membersForType(snapshot, resolved.type).map(
4463
- (symbol) => symbolCompletion(symbol, word, snapshot)
4464
- );
4549
+ const staticType = resolved.staticType;
4550
+ return staticType.members.filter(
4551
+ (member) => member.static === true && isMemberCompletionAccessible(snapshot, staticType, member)
4552
+ ).map((member) => symbolCompletion(member, word, snapshot));
4553
+ }
4554
+ const owner = resolved.type.kind === "named" ? snapshot.project.typeById.get(resolved.type.typeId) : void 0;
4555
+ return membersForType(snapshot, resolved.type).filter(
4556
+ (symbol) => owner === void 0 || isMemberCompletionAccessible(snapshot, owner, symbol)
4557
+ ).map((symbol) => symbolCompletion(symbol, word, snapshot));
4558
+ }
4559
+ function isMemberCompletionAccessible(snapshot, owner, symbol) {
4560
+ return memberAccessFailure({
4561
+ project: snapshot.project,
4562
+ context: snapshot.context,
4563
+ owner,
4564
+ symbol
4565
+ }) === null;
4465
4566
  }
4466
4567
  function membersForType(snapshot, type) {
4467
4568
  if (type.kind === "named") {
@@ -9808,6 +9909,7 @@ var init_strict_resolver = __esm({
9808
9909
  pos
9809
9910
  );
9810
9911
  }
9912
+ this.assertMemberAccessible(staticType, member, pos);
9811
9913
  if (member.static !== true) {
9812
9914
  throw new CompileError(
9813
9915
  `Member '${staticType.name}.${name}' requires an instance receiver.`,
@@ -9960,6 +10062,7 @@ var init_strict_resolver = __esm({
9960
10062
  pos
9961
10063
  );
9962
10064
  }
10065
+ this.assertMemberAccessible(type, member, pos);
9963
10066
  if (member.static === true) {
9964
10067
  throw new CompileError(
9965
10068
  `Static member '${type.name}.${name}' must be accessed through the type name, not an instance.`,
@@ -10281,6 +10384,7 @@ var init_strict_resolver = __esm({
10281
10384
  pos
10282
10385
  );
10283
10386
  }
10387
+ this.assertMemberAccessible(staticType, member, pos);
10284
10388
  if (member.static !== true) {
10285
10389
  throw new CompileError(
10286
10390
  `Member '${staticType.name}.${callee.name}' requires an instance receiver.`,
@@ -10317,6 +10421,7 @@ var init_strict_resolver = __esm({
10317
10421
  (candidate) => (candidate.kind === "function" || candidate.kind === "method") && candidate.name === callee.name
10318
10422
  );
10319
10423
  if (member) {
10424
+ if (type !== void 0) this.assertMemberAccessible(type, member, pos);
10320
10425
  if (member.static === true) {
10321
10426
  throw new CompileError(
10322
10427
  `Static member '${type?.name}.${callee.name}' must be accessed through the type name, not an instance.`,
@@ -10867,6 +10972,7 @@ var init_strict_resolver = __esm({
10867
10972
  (candidate) => (candidate.kind === "function" || candidate.kind === "method") && candidate.name === memberName
10868
10973
  );
10869
10974
  if (!symbol2) return null;
10975
+ this.assertMemberAccessible(staticType, symbol2, expression.pos);
10870
10976
  if (symbol2.static !== true) {
10871
10977
  throw new CompileError(
10872
10978
  `Member '${staticType.name}.${memberName}' requires an instance receiver.`,
@@ -10908,6 +11014,9 @@ var init_strict_resolver = __esm({
10908
11014
  (candidate) => (candidate.kind === "function" || candidate.kind === "method") && candidate.name === memberName
10909
11015
  );
10910
11016
  if (!symbol) return null;
11017
+ if (type !== void 0) {
11018
+ this.assertMemberAccessible(type, symbol, expression.pos);
11019
+ }
10911
11020
  if (symbol.static === true) {
10912
11021
  throw new CompileError(
10913
11022
  `Static member '${type?.name}.${memberName}' must be accessed through the type name, not an instance.`,
@@ -11285,6 +11394,36 @@ var init_strict_resolver = __esm({
11285
11394
  describe(type) {
11286
11395
  return formatType(type, this.project);
11287
11396
  }
11397
+ /**
11398
+ * Enforces C#-style member accessibility on a resolved member. Runs after
11399
+ * the member is found so hover/definition still resolve while the strict
11400
+ * compile carries the diagnostic.
11401
+ */
11402
+ assertMemberAccessible(owner, symbol, pos) {
11403
+ const failure = memberAccessFailure({
11404
+ project: this.project,
11405
+ context: this.context,
11406
+ owner,
11407
+ symbol
11408
+ });
11409
+ if (failure === null) return;
11410
+ if (failure.kind === "private") {
11411
+ throw new CompileError(
11412
+ `'${symbol.name}' is private to ${failure.declaringTypeName}.`,
11413
+ pos
11414
+ );
11415
+ }
11416
+ if (failure.kind === "interfaceProtected") {
11417
+ throw new CompileError(
11418
+ `'${symbol.name}' is protected; through an ${failure.interfaceName} reference it is accessible only from classes that implement ${failure.interfaceName} and their derived classes.`,
11419
+ pos
11420
+ );
11421
+ }
11422
+ throw new CompileError(
11423
+ `'${symbol.name}' is protected; accessible only from ${failure.declaringTypeName} and derived classes.`,
11424
+ pos
11425
+ );
11426
+ }
11288
11427
  symbolValue(symbol) {
11289
11428
  if (symbol.kind === "root" || symbol.kind === "parameter" || symbol.kind === "value") {
11290
11429
  return {
@@ -11307,6 +11446,13 @@ var init_strict_resolver = __esm({
11307
11446
  if (this.context.staticMember === true && symbol.static !== true) {
11308
11447
  return null;
11309
11448
  }
11449
+ const accessFailure = memberAccessFailure({
11450
+ project: this.project,
11451
+ context: this.context,
11452
+ owner,
11453
+ symbol
11454
+ });
11455
+ if (accessFailure !== null) return null;
11310
11456
  return { owner, symbol };
11311
11457
  }
11312
11458
  nextCallSite(pos) {
@@ -12355,6 +12501,14 @@ var init_parity_contract = __esm({
12355
12501
  });
12356
12502
 
12357
12503
  // ../packages/neoscript-language/src/project-source-ast.ts
12504
+ function isNeoSourceAccessModifier(value) {
12505
+ return value === "public" || value === "protected" || value === "private";
12506
+ }
12507
+ function effectiveSourceAccessModifier(modifiers, ownerKind) {
12508
+ const explicit = modifiers.find(isNeoSourceAccessModifier);
12509
+ if (explicit !== void 0) return explicit;
12510
+ return ownerKind === "interface" ? "public" : "private";
12511
+ }
12358
12512
  var init_project_source_ast = __esm({
12359
12513
  "../packages/neoscript-language/src/project-source-ast.ts"() {
12360
12514
  "use strict";
@@ -12822,6 +12976,7 @@ function validateDeclarationSemantics(declarations, diagnostics) {
12822
12976
  message: `Member '${member.name}' repeats the '${modifier}' modifier.`
12823
12977
  });
12824
12978
  }
12979
+ validateMemberAccessModifiers(declaration, member, diagnostics);
12825
12980
  if (member.kind !== "function") continue;
12826
12981
  if (declaration.kind === "interface") {
12827
12982
  if (member.body) {
@@ -12867,6 +13022,61 @@ function validateDeclarationSemantics(declarations, diagnostics) {
12867
13022
  }
12868
13023
  }
12869
13024
  }
13025
+ function validateMemberAccessModifiers(declaration, member, diagnostics) {
13026
+ const accessModifiers = [
13027
+ ...new Set(member.modifiers.filter(isNeoSourceAccessModifier))
13028
+ ];
13029
+ if (accessModifiers.length > 1) {
13030
+ diagnostics.push({
13031
+ range: member.nameRange,
13032
+ severity: "error",
13033
+ source: "neo-project",
13034
+ code: "conflicting-access-modifiers",
13035
+ message: `Member '${member.name}' declares more than one access modifier (${accessModifiers.join(", ")}); a member accepts at most one.`
13036
+ });
13037
+ return;
13038
+ }
13039
+ const accessModifier = accessModifiers[0];
13040
+ if (accessModifier === void 0) return;
13041
+ if (declaration.kind === "interface" && accessModifier === "private") {
13042
+ diagnostics.push({
13043
+ range: member.nameRange,
13044
+ severity: "error",
13045
+ source: "neo-project",
13046
+ code: "private-interface-member",
13047
+ message: `Interface member '${member.name}' cannot be private; private interface members are not yet supported. Use public or protected.`
13048
+ });
13049
+ return;
13050
+ }
13051
+ if (accessModifier !== "private") return;
13052
+ if (member.modifiers.includes("virtual")) {
13053
+ diagnostics.push({
13054
+ range: member.nameRange,
13055
+ severity: "error",
13056
+ source: "neo-project",
13057
+ code: "private-virtual-member",
13058
+ message: `Member '${member.name}' cannot be both private and virtual; a private member is never overridable.`
13059
+ });
13060
+ }
13061
+ if (member.modifiers.includes("abstract")) {
13062
+ diagnostics.push({
13063
+ range: member.nameRange,
13064
+ severity: "error",
13065
+ source: "neo-project",
13066
+ code: "private-abstract-member",
13067
+ message: `Member '${member.name}' cannot be both private and abstract; an abstract member exists to be implemented by descendants.`
13068
+ });
13069
+ }
13070
+ if (member.modifiers.includes("override")) {
13071
+ diagnostics.push({
13072
+ range: member.nameRange,
13073
+ severity: "error",
13074
+ source: "neo-project",
13075
+ code: "private-override-member",
13076
+ message: `Member '${member.name}' cannot be both private and override; an override keeps the accessibility of the member it overrides, and a private member cannot be overridden.`
13077
+ });
13078
+ }
13079
+ }
12870
13080
  function isNameToken(token) {
12871
13081
  return token !== void 0 && (token.kind === "identifier" || token.kind === "type" || token.kind === "keyword");
12872
13082
  }
@@ -12902,12 +13112,16 @@ var init_project_source_parser = __esm({
12902
13112
  "use strict";
12903
13113
  init_lexer();
12904
13114
  init_neoflow_graph_parser();
13115
+ init_project_source_ast();
12905
13116
  init_source_text();
12906
13117
  MODIFIERS = /* @__PURE__ */ new Set([
12907
13118
  "abstract",
12908
13119
  "async",
12909
13120
  "native",
12910
13121
  "override",
13122
+ "private",
13123
+ "protected",
13124
+ "public",
12911
13125
  "sealed",
12912
13126
  "static",
12913
13127
  "virtual"
@@ -12945,6 +13159,14 @@ var init_project_source_parser = __esm({
12945
13159
  const annotations = this.parseAnnotations();
12946
13160
  const modifiers = this.parseModifiers();
12947
13161
  if (this.at("class")) {
13162
+ const accessModifier = modifiers.find(isNeoSourceAccessModifier);
13163
+ if (accessModifier !== void 0) {
13164
+ throw this.failure(
13165
+ "source-class-access-modifier",
13166
+ `Access modifier '${accessModifier}' is valid only on class and interface member declarations, not on a class declaration.`,
13167
+ start
13168
+ );
13169
+ }
12948
13170
  return this.parseClass(start, annotations, modifiers);
12949
13171
  }
12950
13172
  if (this.at("interface")) {
@@ -13545,6 +13767,7 @@ var init_project_schema_contract_generated = __esm({
13545
13767
  "isStatic",
13546
13768
  "isVirtual",
13547
13769
  "isAbstract",
13770
+ "accessModifierKind",
13548
13771
  "defaultValue",
13549
13772
  "extendsMemberId",
13550
13773
  "system",
@@ -17356,6 +17579,10 @@ function sourceMemberSymbol(member, owner, typeIds, source) {
17356
17579
  type,
17357
17580
  static: staticMember,
17358
17581
  abstract: member.modifiers.includes("abstract"),
17582
+ accessModifier: effectiveSourceAccessModifier(
17583
+ member.modifiers,
17584
+ owner.declaration.kind
17585
+ ),
17359
17586
  location: location(owner.uri, member.range),
17360
17587
  selectionLocation: location(owner.uri, member.nameRange)
17361
17588
  };
@@ -17690,6 +17917,7 @@ var init_project_source_script_compiler = __esm({
17690
17917
  "use strict";
17691
17918
  init_compiler();
17692
17919
  init_language_spec();
17920
+ init_project_source_ast();
17693
17921
  init_project();
17694
17922
  init_project_root();
17695
17923
  init_source_text();
@@ -18246,6 +18474,7 @@ function validateMembers(environment, diagnostics) {
18246
18474
  }
18247
18475
  for (const modifier of member.modifiers) {
18248
18476
  if (modifier === "async" && member.kind === "function") continue;
18477
+ if (isNeoSourceAccessModifier(modifier)) continue;
18249
18478
  diagnose(
18250
18479
  diagnostics,
18251
18480
  ref.uri,
@@ -18899,6 +19128,7 @@ var init_project_source_type_checker = __esm({
18899
19128
  "../packages/neoscript-language/src/project-source-type-checker.ts"() {
18900
19129
  "use strict";
18901
19130
  init_language_spec();
19131
+ init_project_source_ast();
18902
19132
  BUILTIN_ARITY = /* @__PURE__ */ new Map([
18903
19133
  ["List", 1],
18904
19134
  ["Set", 1],
@@ -24316,6 +24546,11 @@ function assertMember2(value, path) {
24316
24546
  assertMemberOwner(member.owner, `${path}.owner`);
24317
24547
  nonEmptyString(member.name, `${path}.name`);
24318
24548
  booleanAt(member.isStatic, `${path}.isStatic`);
24549
+ stringIn(
24550
+ member.accessModifier,
24551
+ /* @__PURE__ */ new Set(["public", "protected", "private"]),
24552
+ `${path}.accessModifier`
24553
+ );
24319
24554
  stringIn(
24320
24555
  member.modifier,
24321
24556
  /* @__PURE__ */ new Set([
@@ -24746,12 +24981,14 @@ function assertInterfaceMember(value, path) {
24746
24981
  "name",
24747
24982
  "type",
24748
24983
  "settable",
24984
+ "accessModifier",
24749
24985
  "source"
24750
24986
  ]);
24751
24987
  nonEmptyString(member.id, `${path}.id`);
24752
24988
  nonEmptyString(member.name, `${path}.name`);
24753
24989
  assertType2(member.type, `${path}.type`);
24754
24990
  booleanAt(member.settable, `${path}.settable`);
24991
+ assertInterfaceMemberAccessModifier(member.accessModifier, path);
24755
24992
  assertSourceIdentity(member.source, `${path}.source`, "interfaceMember");
24756
24993
  return;
24757
24994
  }
@@ -24763,16 +25000,21 @@ function assertInterfaceMember(value, path) {
24763
25000
  "returnType",
24764
25001
  "arguments",
24765
25002
  "deferred",
25003
+ "accessModifier",
24766
25004
  "source"
24767
25005
  ]);
24768
25006
  nonEmptyString(member.id, `${path}.id`);
24769
25007
  nonEmptyString(member.name, `${path}.name`);
24770
25008
  assertFunctionSignature(member, path);
25009
+ assertInterfaceMemberAccessModifier(member.accessModifier, path);
24771
25010
  assertSourceIdentity(member.source, `${path}.source`, "interfaceMember");
24772
25011
  return;
24773
25012
  }
24774
25013
  invalid(`${path}.kind`, "must be property or function.");
24775
25014
  }
25015
+ function assertInterfaceMemberAccessModifier(value, path) {
25016
+ stringIn(value, /* @__PURE__ */ new Set(["public", "protected"]), `${path}.accessModifier`);
25017
+ }
24776
25018
  function assertEnum2(value, path) {
24777
25019
  const neoEnum = objectAt(value, path, [
24778
25020
  "id",
@@ -25518,6 +25760,7 @@ var init_validate = __esm({
25518
25760
  "owner",
25519
25761
  "name",
25520
25762
  "isStatic",
25763
+ "accessModifier",
25521
25764
  "modifier",
25522
25765
  "locked",
25523
25766
  "required",
@@ -27329,6 +27572,10 @@ function memberCommon(context, ownerClass, declaration, id2, owner, base) {
27329
27572
  owner,
27330
27573
  name: declaration.name,
27331
27574
  isStatic: declaration.modifiers.includes("static"),
27575
+ // Non-class placements (collection entries, generic arguments, loose
27576
+ // members) have no receiver type to scope visibility to; they are
27577
+ // structurally public. Class schema entries apply the C# omission default.
27578
+ accessModifier: owner.kind === "classMember" ? effectiveSourceAccessModifier(declaration.modifiers, "class") : "public",
27332
27579
  modifier: memberModifier2(declaration.modifiers, base?.modifier),
27333
27580
  locked: hasAnnotation(declaration.annotations, "locked"),
27334
27581
  required: declaration.kind === "field" ? !declaration.type.nullable : base?.required ?? false,
@@ -27546,6 +27793,10 @@ function lowerInterface(context, declaration) {
27546
27793
  `${declaration.name}.${member.name}`
27547
27794
  );
27548
27795
  const source = sourceIdentity2(member, "interfaceMember", member.name);
27796
+ const accessModifier = effectiveSourceAccessModifier(
27797
+ member.modifiers,
27798
+ "interface"
27799
+ );
27549
27800
  if (member.kind === "function") {
27550
27801
  return {
27551
27802
  id: memberId,
@@ -27559,6 +27810,7 @@ function lowerInterface(context, declaration) {
27559
27810
  selectionSpan: span(parameter3)
27560
27811
  })),
27561
27812
  deferred: member.modifiers.includes("async"),
27813
+ accessModifier,
27562
27814
  source
27563
27815
  };
27564
27816
  }
@@ -27568,6 +27820,7 @@ function lowerInterface(context, declaration) {
27568
27820
  name: member.name,
27569
27821
  type: lowerType(context, member.type),
27570
27822
  settable: /\bset\s*;/.test(member.body ?? ""),
27823
+ accessModifier,
27571
27824
  source
27572
27825
  };
27573
27826
  });
@@ -28003,29 +28256,38 @@ function genericConstraint(context, type) {
28003
28256
  };
28004
28257
  }
28005
28258
  function inheritedMemberId(context, ownerClass, name) {
28006
- const baseType = ownerClass.baseTypes.find(
28259
+ const directBase = ownerClass.baseTypes.find(
28007
28260
  (entry) => context.classIdsByName.has(entry.name)
28008
28261
  );
28009
- if (!baseType) return null;
28010
- const baseClass = context.baseClasses.get(
28011
- requiredName(context.classIdsByName, baseType.name, "class")
28012
- );
28013
- if (baseClass !== void 0) return baseClass.schema[name] ?? null;
28014
- const baseClassId = requiredName(
28015
- context.classIdsByName,
28016
- baseType.name,
28017
- "class"
28018
- );
28019
- const sourceBase = context.sourceClasses.get(baseClassId);
28020
- if (sourceBase === void 0) return null;
28021
- const sourceMember = sourceBase.members.find(
28022
- (member) => member.name === name
28023
- );
28024
- return sourceMember === void 0 ? null : materializedId(
28025
- sourceMember,
28026
- "member",
28027
- `${sourceBase.name}.${sourceMember.name}`
28028
- );
28262
+ let classId = directBase ? requiredName(context.classIdsByName, directBase.name, "class") : null;
28263
+ const visited = /* @__PURE__ */ new Set();
28264
+ while (classId !== null && !visited.has(classId)) {
28265
+ visited.add(classId);
28266
+ const sourceClass = context.sourceClasses.get(classId);
28267
+ if (sourceClass !== void 0) {
28268
+ const sourceMember = sourceClass.members.find(
28269
+ (member) => member.name === name
28270
+ );
28271
+ if (sourceMember !== void 0) {
28272
+ return materializedId(
28273
+ sourceMember,
28274
+ "member",
28275
+ `${sourceClass.name}.${sourceMember.name}`
28276
+ );
28277
+ }
28278
+ const sourceBase = sourceClass.baseTypes.find(
28279
+ (entry) => context.classIdsByName.has(entry.name)
28280
+ );
28281
+ classId = sourceBase ? requiredName(context.classIdsByName, sourceBase.name, "class") : null;
28282
+ continue;
28283
+ }
28284
+ const pulledClass = context.baseClasses.get(classId);
28285
+ if (pulledClass === void 0) return null;
28286
+ const memberId = pulledClass.schema[name];
28287
+ if (memberId !== void 0) return memberId;
28288
+ classId = pulledClass.extendsClassId;
28289
+ }
28290
+ return null;
28029
28291
  }
28030
28292
  function resolveQualifiedMemberId(context, expression) {
28031
28293
  const match = /^([A-Za-z_][A-Za-z0-9_]*)\.([A-Za-z_][A-Za-z0-9_]*)$/.exec(
@@ -29066,11 +29328,12 @@ function emitInterface(context, value) {
29066
29328
  (interfaceId) => required(context.interfaces, interfaceId, "interface").name
29067
29329
  );
29068
29330
  const members = value.members.map((member) => {
29331
+ const access = member.accessModifier === "public" ? "" : `${member.accessModifier} `;
29069
29332
  if (member.kind === "property") {
29070
- return `${id(member.id)}${renderType(context, member.type)} ${member.name} { get;${member.settable ? " set;" : ""} }`;
29333
+ return `${id(member.id)}${access}${renderType(context, member.type)} ${member.name} { get;${member.settable ? " set;" : ""} }`;
29071
29334
  }
29072
29335
  const deferred = member.deferred ? "async " : "";
29073
- return `${id(member.id)}${deferred}${renderReturnType(context, member.returnType)} ${member.name}(${member.arguments.map(
29336
+ return `${id(member.id)}${access}${deferred}${renderReturnType(context, member.returnType)} ${member.name}(${member.arguments.map(
29074
29337
  (argument2) => `${renderType(context, argument2.type)} ${argument2.name}`
29075
29338
  ).join(", ")});`;
29076
29339
  });
@@ -29135,9 +29398,10 @@ ${body ? `${signature} ${body}` : abstractContract ? `${signature};` : `native $
29135
29398
  ${prefix}${type} ${member.name}${initializer === null ? ";" : ` = ${initializer};`}`;
29136
29399
  }
29137
29400
  function memberModifier3(member) {
29401
+ const accessPrefix = `${member.accessModifier} `;
29138
29402
  const staticPrefix = member.isStatic ? "static " : "";
29139
29403
  const modifier = member.modifier === "plain" ? "" : member.modifier === "abstractOverride" ? "abstract override " : member.modifier === "sealedOverride" ? "override " : `${member.modifier} `;
29140
- return `${staticPrefix}${modifier}`;
29404
+ return `${accessPrefix}${staticPrefix}${modifier}`;
29141
29405
  }
29142
29406
  function renderExtendsGenericBindings(context, schemaClass2, base) {
29143
29407
  if (base.genericParameters.length === 0) return "";
@@ -33207,6 +33471,11 @@ var init_neoscript = __esm({
33207
33471
  });
33208
33472
 
33209
33473
  // ../src/models/members/member-kinds.ts
33474
+ function isMemberAccessModifierKind(value) {
33475
+ if (value === "public") return true;
33476
+ if (value === "protected") return true;
33477
+ return value === "private";
33478
+ }
33210
33479
  function isValidCallableIdentifier(value) {
33211
33480
  if (typeof value !== "string") return false;
33212
33481
  if (!FunctionMemberNamePattern.test(value)) return false;
@@ -33650,6 +33919,7 @@ function isMemberBase(value) {
33650
33919
  if (typeof v.locked !== "boolean") return false;
33651
33920
  if (typeof v.required !== "boolean") return false;
33652
33921
  if (typeof v.isStatic !== "boolean") return false;
33922
+ if (!isMemberAccessModifierKind(v.accessModifierKind)) return false;
33653
33923
  if (v.isVirtual !== void 0 && typeof v.isVirtual !== "boolean") {
33654
33924
  return false;
33655
33925
  }
@@ -33705,6 +33975,7 @@ function isMemberOverrideBase(value) {
33705
33975
  if (v.locked !== void 0 && typeof v.locked !== "boolean") return false;
33706
33976
  if (v.required !== void 0 && typeof v.required !== "boolean") return false;
33707
33977
  if (v.isStatic !== void 0 && v.isStatic !== false) return false;
33978
+ if (!isMemberAccessModifierKind(v.accessModifierKind)) return false;
33708
33979
  if (v.isVirtual !== void 0 && typeof v.isVirtual !== "boolean") {
33709
33980
  return false;
33710
33981
  }
@@ -34212,6 +34483,9 @@ function substituteMember(member, env, members) {
34212
34483
  ...binding,
34213
34484
  name: resolved.name,
34214
34485
  locked: resolved.locked,
34486
+ // Accessibility is a slot-owned declaration field — a binding member's
34487
+ // modifier must not change the declaring slot's visibility.
34488
+ accessModifierKind: resolved.accessModifierKind,
34215
34489
  system: resolved.system ?? void 0
34216
34490
  };
34217
34491
  const slotId = getOptionalString(member, "id");
@@ -35518,6 +35792,7 @@ function isNeoInterfaceMember(value) {
35518
35792
  if (value === null) return false;
35519
35793
  const member = value;
35520
35794
  if (typeof member.id !== "string" || member.id.length === 0) return false;
35795
+ if (!isMemberAccessModifierKind(member.accessModifierKind)) return false;
35521
35796
  if (member.kind === "property") {
35522
35797
  if (!isNSTypeInfo(member.typeInfo)) return false;
35523
35798
  if (containsForbiddenMemberTypeInfo(member.typeInfo)) return false;
@@ -39462,6 +39737,7 @@ function lowerMemberDefaultSourcesV4(state, analysis, manifest) {
39462
39737
  if (record3.recordKind === "value") pulledValueIds.add(record3.recordId);
39463
39738
  }
39464
39739
  const memberDefaultValues = /* @__PURE__ */ new Map();
39740
+ const seeds = /* @__PURE__ */ new Map();
39465
39741
  for (const sourceClass of analysis.schema.classes) {
39466
39742
  for (const declaration of sourceClass.members) {
39467
39743
  if (declaration.kind !== "field" || declaration.initializer === null) {
@@ -39470,13 +39746,6 @@ function lowerMemberDefaultSourcesV4(state, analysis, manifest) {
39470
39746
  if (declaration.modifiers.includes("static")) continue;
39471
39747
  const label = `${sourceClass.name}.${declaration.name}`;
39472
39748
  const memberId = sourceIdentityId(declaration, "member", label);
39473
- const baseData3 = stateData(context, "member", memberId);
39474
- if (baseData3 === null) continue;
39475
- const backed = rowBackedDefaultBody(
39476
- baseData3,
39477
- (id2) => pulledValueIds.has(id2)
39478
- );
39479
- if (backed === null) continue;
39480
39749
  const member = context.members.get(memberId);
39481
39750
  if (member === void 0) continue;
39482
39751
  const binding = {
@@ -39485,17 +39754,52 @@ function lowerMemberDefaultSourcesV4(state, analysis, manifest) {
39485
39754
  source: declaration.source,
39486
39755
  label
39487
39756
  };
39488
- memberDefaultValues.set(
39489
- memberId,
39490
- lowerRowBackedDefault(context, member, backed, baseData3, binding)
39757
+ const baseData3 = stateData(context, "member", memberId);
39758
+ const backed = baseData3 === null ? null : rowBackedDefaultBody(baseData3, (id2) => pulledValueIds.has(id2));
39759
+ if (backed !== null && baseData3 !== null) {
39760
+ memberDefaultValues.set(
39761
+ memberId,
39762
+ lowerRowBackedDefault(context, member, backed, baseData3, binding)
39763
+ );
39764
+ continue;
39765
+ }
39766
+ const expression = parseCachedInitializer(
39767
+ context.parsedInitializers,
39768
+ declaration.initializer
39491
39769
  );
39770
+ if (!defaultRequiresOwnedRows(member, expression)) continue;
39771
+ const rootValueId = pendingValueId(binding, `${label}.default`);
39772
+ const seed = lowerStaticSeed(
39773
+ context,
39774
+ member,
39775
+ expression,
39776
+ binding,
39777
+ rootValueId
39778
+ );
39779
+ seeds.set(memberId, { ...seed, valueId: rootValueId });
39780
+ memberDefaultValues.set(memberId, {
39781
+ value: seed.value,
39782
+ classId: seed.classId
39783
+ });
39492
39784
  }
39493
39785
  }
39494
39786
  return {
39495
39787
  records: [...context.reconstructed.values()],
39496
- memberDefaultValues
39788
+ memberDefaultValues,
39789
+ seeds
39497
39790
  };
39498
39791
  }
39792
+ function defaultRequiresOwnedRows(member, sourceExpression) {
39793
+ const expression = annotatedValue(sourceExpression).expression;
39794
+ if (member.kind === "class") return expression.kind === "new";
39795
+ if (member.kind === "list") {
39796
+ return expression.kind === "litList" && expression.elements.length > 0;
39797
+ }
39798
+ if (member.kind === "dictionary") {
39799
+ return expression.kind === "litDict" && expression.entries.length > 0;
39800
+ }
39801
+ return false;
39802
+ }
39499
39803
  function lowerRowBackedDefault(context, member, backed, baseData3, binding) {
39500
39804
  const baseDefault = isObjectRecord2(baseData3.defaultValue) ? baseData3.defaultValue : {};
39501
39805
  const storedClassId = stringOrNull(baseDefault.classId);
@@ -43471,7 +43775,8 @@ function computeWorkspaceStatus(workspace, options = {}) {
43471
43775
  let staticMemberValueIds = /* @__PURE__ */ new Map();
43472
43776
  let memberDefaults = {
43473
43777
  records: [],
43474
- memberDefaultValues: /* @__PURE__ */ new Map()
43778
+ memberDefaultValues: /* @__PURE__ */ new Map(),
43779
+ seeds: /* @__PURE__ */ new Map()
43475
43780
  };
43476
43781
  let projectAnalysisV4 = null;
43477
43782
  try {
@@ -43621,7 +43926,7 @@ function computeWorkspaceStatus(workspace, options = {}) {
43621
43926
  projectAnalysisV4,
43622
43927
  manifest
43623
43928
  );
43624
- staticValueSeeds = staticValues.seeds;
43929
+ staticValueSeeds = new Map([...staticValues.seeds, ...memberDefaults.seeds]);
43625
43930
  staticMemberValueIds = staticValues.memberValueIds;
43626
43931
  const rootRecords = lowerProjectRootSourceV4(
43627
43932
  workspace.state.records,
@@ -44882,6 +45187,29 @@ function migrateMemberStaticOwnership(data) {
44882
45187
  if (Object.prototype.hasOwnProperty.call(data, "isStatic")) return data;
44883
45188
  return { ...data, isStatic: false };
44884
45189
  }
45190
+ function migrateMemberAccessModifier(data) {
45191
+ if (!isRecord5(data)) return data;
45192
+ if (Object.prototype.hasOwnProperty.call(data, "accessModifierKind")) {
45193
+ return data;
45194
+ }
45195
+ return { ...data, accessModifierKind: "public" };
45196
+ }
45197
+ function migrateInterfaceMemberAccessModifiers(data) {
45198
+ if (!isRecord5(data)) return data;
45199
+ const members = data.members;
45200
+ if (!isRecord5(members)) return data;
45201
+ let nextMembers = members;
45202
+ for (const [memberKey, member] of Object.entries(members)) {
45203
+ if (!isRecord5(member)) continue;
45204
+ if (Object.prototype.hasOwnProperty.call(member, "accessModifierKind")) {
45205
+ continue;
45206
+ }
45207
+ if (nextMembers === members) nextMembers = { ...members };
45208
+ nextMembers[memberKey] = { ...member, accessModifierKind: "public" };
45209
+ }
45210
+ if (nextMembers === members) return data;
45211
+ return { ...data, members: nextMembers };
45212
+ }
44885
45213
  function migrateProjectRecordData(args) {
44886
45214
  const currentVersion = CURRENT_PROJECT_RECORD_DATA_SCHEMA_VERSION[args.recordKind];
44887
45215
  if (args.dataSchemaVersion > currentVersion) {
@@ -45065,12 +45393,12 @@ var init_project_record_migrations = __esm({
45065
45393
  init_neoscript_call_receiver_migration();
45066
45394
  CURRENT_PROJECT_RECORD_DATA_SCHEMA_VERSION = {
45067
45395
  [ProjectRecordKind.Project]: 1,
45068
- [ProjectRecordKind.Member]: 4,
45396
+ [ProjectRecordKind.Member]: 5,
45069
45397
  [ProjectRecordKind.Value]: 1,
45070
45398
  [ProjectRecordKind.Class]: 1,
45071
45399
  [ProjectRecordKind.InternalRecordRelation]: 1,
45072
45400
  [ProjectRecordKind.Enum]: 4,
45073
- [ProjectRecordKind.Interface]: 2,
45401
+ [ProjectRecordKind.Interface]: 3,
45074
45402
  [ProjectRecordKind.Dialogue]: 5,
45075
45403
  [ProjectRecordKind.DialogueNode]: 4,
45076
45404
  [ProjectRecordKind.DialogueGroup]: 4,
@@ -45088,7 +45416,8 @@ var init_project_record_migrations = __esm({
45088
45416
  [ProjectRecordKind.Member]: {
45089
45417
  1: migrateGeneralFunctionCallIR,
45090
45418
  2: migrateMemberStaticOwnership,
45091
- 3: migrateExplicitCallReceiverIR
45419
+ 3: migrateExplicitCallReceiverIR,
45420
+ 4: migrateMemberAccessModifier
45092
45421
  },
45093
45422
  [ProjectRecordKind.Value]: {},
45094
45423
  [ProjectRecordKind.Class]: {},
@@ -45096,7 +45425,9 @@ var init_project_record_migrations = __esm({
45096
45425
  [ProjectRecordKind.Enum]: {
45097
45426
  1: migrateEnumOptionKeyOrder
45098
45427
  },
45099
- [ProjectRecordKind.Interface]: {},
45428
+ [ProjectRecordKind.Interface]: {
45429
+ 2: migrateInterfaceMemberAccessModifiers
45430
+ },
45100
45431
  [ProjectRecordKind.Dialogue]: {
45101
45432
  1: migrateDialoguePrimaryLinkedValues,
45102
45433
  2: migrateGeneralFunctionCallIR,
@@ -53463,7 +53794,8 @@ function constructClassValue(info, scope, ctx) {
53463
53794
  classId,
53464
53795
  locked: false,
53465
53796
  required: true,
53466
- isStatic: false
53797
+ isStatic: false,
53798
+ accessModifierKind: "public"
53467
53799
  };
53468
53800
  const createdValues = [];
53469
53801
  const storageKeyDeclarations = /* @__PURE__ */ new Map();
@@ -61485,7 +61817,7 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
61485
61817
  }
61486
61818
  if (status.staticValueSeeds.size > 0) {
61487
61819
  console.log(
61488
- ` ${color.dim(`create ${status.staticValueSeeds.size} static value seed(s)`)}`
61820
+ ` ${color.dim(`create ${status.staticValueSeeds.size} member value seed(s)`)}`
61489
61821
  );
61490
61822
  }
61491
61823
  if (options.dryRun) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.5.4",
3
+ "version": "0.6.1",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",