@neocompose/cli 0.5.4 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/neo.mjs +309 -16
  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
  });
@@ -29066,11 +29319,12 @@ function emitInterface(context, value) {
29066
29319
  (interfaceId) => required(context.interfaces, interfaceId, "interface").name
29067
29320
  );
29068
29321
  const members = value.members.map((member) => {
29322
+ const access = member.accessModifier === "public" ? "" : `${member.accessModifier} `;
29069
29323
  if (member.kind === "property") {
29070
- return `${id(member.id)}${renderType(context, member.type)} ${member.name} { get;${member.settable ? " set;" : ""} }`;
29324
+ return `${id(member.id)}${access}${renderType(context, member.type)} ${member.name} { get;${member.settable ? " set;" : ""} }`;
29071
29325
  }
29072
29326
  const deferred = member.deferred ? "async " : "";
29073
- return `${id(member.id)}${deferred}${renderReturnType(context, member.returnType)} ${member.name}(${member.arguments.map(
29327
+ return `${id(member.id)}${access}${deferred}${renderReturnType(context, member.returnType)} ${member.name}(${member.arguments.map(
29074
29328
  (argument2) => `${renderType(context, argument2.type)} ${argument2.name}`
29075
29329
  ).join(", ")});`;
29076
29330
  });
@@ -29135,9 +29389,10 @@ ${body ? `${signature} ${body}` : abstractContract ? `${signature};` : `native $
29135
29389
  ${prefix}${type} ${member.name}${initializer === null ? ";" : ` = ${initializer};`}`;
29136
29390
  }
29137
29391
  function memberModifier3(member) {
29392
+ const accessPrefix = `${member.accessModifier} `;
29138
29393
  const staticPrefix = member.isStatic ? "static " : "";
29139
29394
  const modifier = member.modifier === "plain" ? "" : member.modifier === "abstractOverride" ? "abstract override " : member.modifier === "sealedOverride" ? "override " : `${member.modifier} `;
29140
- return `${staticPrefix}${modifier}`;
29395
+ return `${accessPrefix}${staticPrefix}${modifier}`;
29141
29396
  }
29142
29397
  function renderExtendsGenericBindings(context, schemaClass2, base) {
29143
29398
  if (base.genericParameters.length === 0) return "";
@@ -33207,6 +33462,11 @@ var init_neoscript = __esm({
33207
33462
  });
33208
33463
 
33209
33464
  // ../src/models/members/member-kinds.ts
33465
+ function isMemberAccessModifierKind(value) {
33466
+ if (value === "public") return true;
33467
+ if (value === "protected") return true;
33468
+ return value === "private";
33469
+ }
33210
33470
  function isValidCallableIdentifier(value) {
33211
33471
  if (typeof value !== "string") return false;
33212
33472
  if (!FunctionMemberNamePattern.test(value)) return false;
@@ -33650,6 +33910,7 @@ function isMemberBase(value) {
33650
33910
  if (typeof v.locked !== "boolean") return false;
33651
33911
  if (typeof v.required !== "boolean") return false;
33652
33912
  if (typeof v.isStatic !== "boolean") return false;
33913
+ if (!isMemberAccessModifierKind(v.accessModifierKind)) return false;
33653
33914
  if (v.isVirtual !== void 0 && typeof v.isVirtual !== "boolean") {
33654
33915
  return false;
33655
33916
  }
@@ -33705,6 +33966,7 @@ function isMemberOverrideBase(value) {
33705
33966
  if (v.locked !== void 0 && typeof v.locked !== "boolean") return false;
33706
33967
  if (v.required !== void 0 && typeof v.required !== "boolean") return false;
33707
33968
  if (v.isStatic !== void 0 && v.isStatic !== false) return false;
33969
+ if (!isMemberAccessModifierKind(v.accessModifierKind)) return false;
33708
33970
  if (v.isVirtual !== void 0 && typeof v.isVirtual !== "boolean") {
33709
33971
  return false;
33710
33972
  }
@@ -34212,6 +34474,9 @@ function substituteMember(member, env, members) {
34212
34474
  ...binding,
34213
34475
  name: resolved.name,
34214
34476
  locked: resolved.locked,
34477
+ // Accessibility is a slot-owned declaration field — a binding member's
34478
+ // modifier must not change the declaring slot's visibility.
34479
+ accessModifierKind: resolved.accessModifierKind,
34215
34480
  system: resolved.system ?? void 0
34216
34481
  };
34217
34482
  const slotId = getOptionalString(member, "id");
@@ -35518,6 +35783,7 @@ function isNeoInterfaceMember(value) {
35518
35783
  if (value === null) return false;
35519
35784
  const member = value;
35520
35785
  if (typeof member.id !== "string" || member.id.length === 0) return false;
35786
+ if (!isMemberAccessModifierKind(member.accessModifierKind)) return false;
35521
35787
  if (member.kind === "property") {
35522
35788
  if (!isNSTypeInfo(member.typeInfo)) return false;
35523
35789
  if (containsForbiddenMemberTypeInfo(member.typeInfo)) return false;
@@ -44882,6 +45148,29 @@ function migrateMemberStaticOwnership(data) {
44882
45148
  if (Object.prototype.hasOwnProperty.call(data, "isStatic")) return data;
44883
45149
  return { ...data, isStatic: false };
44884
45150
  }
45151
+ function migrateMemberAccessModifier(data) {
45152
+ if (!isRecord5(data)) return data;
45153
+ if (Object.prototype.hasOwnProperty.call(data, "accessModifierKind")) {
45154
+ return data;
45155
+ }
45156
+ return { ...data, accessModifierKind: "public" };
45157
+ }
45158
+ function migrateInterfaceMemberAccessModifiers(data) {
45159
+ if (!isRecord5(data)) return data;
45160
+ const members = data.members;
45161
+ if (!isRecord5(members)) return data;
45162
+ let nextMembers = members;
45163
+ for (const [memberKey, member] of Object.entries(members)) {
45164
+ if (!isRecord5(member)) continue;
45165
+ if (Object.prototype.hasOwnProperty.call(member, "accessModifierKind")) {
45166
+ continue;
45167
+ }
45168
+ if (nextMembers === members) nextMembers = { ...members };
45169
+ nextMembers[memberKey] = { ...member, accessModifierKind: "public" };
45170
+ }
45171
+ if (nextMembers === members) return data;
45172
+ return { ...data, members: nextMembers };
45173
+ }
44885
45174
  function migrateProjectRecordData(args) {
44886
45175
  const currentVersion = CURRENT_PROJECT_RECORD_DATA_SCHEMA_VERSION[args.recordKind];
44887
45176
  if (args.dataSchemaVersion > currentVersion) {
@@ -45065,12 +45354,12 @@ var init_project_record_migrations = __esm({
45065
45354
  init_neoscript_call_receiver_migration();
45066
45355
  CURRENT_PROJECT_RECORD_DATA_SCHEMA_VERSION = {
45067
45356
  [ProjectRecordKind.Project]: 1,
45068
- [ProjectRecordKind.Member]: 4,
45357
+ [ProjectRecordKind.Member]: 5,
45069
45358
  [ProjectRecordKind.Value]: 1,
45070
45359
  [ProjectRecordKind.Class]: 1,
45071
45360
  [ProjectRecordKind.InternalRecordRelation]: 1,
45072
45361
  [ProjectRecordKind.Enum]: 4,
45073
- [ProjectRecordKind.Interface]: 2,
45362
+ [ProjectRecordKind.Interface]: 3,
45074
45363
  [ProjectRecordKind.Dialogue]: 5,
45075
45364
  [ProjectRecordKind.DialogueNode]: 4,
45076
45365
  [ProjectRecordKind.DialogueGroup]: 4,
@@ -45088,7 +45377,8 @@ var init_project_record_migrations = __esm({
45088
45377
  [ProjectRecordKind.Member]: {
45089
45378
  1: migrateGeneralFunctionCallIR,
45090
45379
  2: migrateMemberStaticOwnership,
45091
- 3: migrateExplicitCallReceiverIR
45380
+ 3: migrateExplicitCallReceiverIR,
45381
+ 4: migrateMemberAccessModifier
45092
45382
  },
45093
45383
  [ProjectRecordKind.Value]: {},
45094
45384
  [ProjectRecordKind.Class]: {},
@@ -45096,7 +45386,9 @@ var init_project_record_migrations = __esm({
45096
45386
  [ProjectRecordKind.Enum]: {
45097
45387
  1: migrateEnumOptionKeyOrder
45098
45388
  },
45099
- [ProjectRecordKind.Interface]: {},
45389
+ [ProjectRecordKind.Interface]: {
45390
+ 2: migrateInterfaceMemberAccessModifiers
45391
+ },
45100
45392
  [ProjectRecordKind.Dialogue]: {
45101
45393
  1: migrateDialoguePrimaryLinkedValues,
45102
45394
  2: migrateGeneralFunctionCallIR,
@@ -53463,7 +53755,8 @@ function constructClassValue(info, scope, ctx) {
53463
53755
  classId,
53464
53756
  locked: false,
53465
53757
  required: true,
53466
- isStatic: false
53758
+ isStatic: false,
53759
+ accessModifierKind: "public"
53467
53760
  };
53468
53761
  const createdValues = [];
53469
53762
  const storageKeyDeclarations = /* @__PURE__ */ new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.5.4",
3
+ "version": "0.6.0",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",