@neocompose/cli 0.31.15 → 0.31.17

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/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.31.17] - 2026-08-18
4
+
5
+ ### Fixed
6
+
7
+ - Accept runtime interface patterns on open Class hierarchies while retaining
8
+ impossible-pattern diagnostics for sealed Classes.
9
+ - Recognize typed NeoScript setters as writable from initializers and function
10
+ bodies, including compound assignments, and compile their setter bodies.
11
+ - Preserve `NeoVariant<T>` member types in the local manifest used by
12
+ `neo script check --all`, matching `neo test` candidate compilation.
13
+
14
+ ## [0.31.16] - 2026-08-18
15
+
16
+ ### Fixed
17
+
18
+ - Resolve unordered List membership from entry `containerId` rows during
19
+ NeoScript evaluation, so root-backed indexes and collection operations see
20
+ stored entries in CLI tests, web previews, and world construction.
21
+
3
22
  ## [0.31.15] - 2026-08-18
4
23
 
5
24
  ### Fixed
package/dist/neo.mjs CHANGED
@@ -8817,6 +8817,18 @@ function typesOverlap(left, right, project) {
8817
8817
  if (isNull(right)) return isNullable(left);
8818
8818
  if (isNeoScriptTypeAssignable(left, right, project) || isNeoScriptTypeAssignable(right, left, project))
8819
8819
  return true;
8820
+ if (left.kind === "named" && right.kind === "named") {
8821
+ const leftDeclaration = project.typeById.get(left.typeId);
8822
+ const rightDeclaration = project.typeById.get(right.typeId);
8823
+ if (leftDeclaration?.kind === "interface" && rightDeclaration?.kind === "interface") {
8824
+ return true;
8825
+ }
8826
+ const classDeclaration = leftDeclaration?.kind === "class" ? leftDeclaration : rightDeclaration?.kind === "class" ? rightDeclaration : null;
8827
+ const interfaceDeclaration = leftDeclaration?.kind === "interface" ? leftDeclaration : rightDeclaration?.kind === "interface" ? rightDeclaration : null;
8828
+ if (classDeclaration !== null && interfaceDeclaration !== null) {
8829
+ return classDeclaration.sealed !== true;
8830
+ }
8831
+ }
8820
8832
  return isNumeric(left) && isNumeric(right);
8821
8833
  }
8822
8834
  function isUnknown(type) {
@@ -24110,6 +24122,7 @@ function buildProjectGraph(documents) {
24110
24122
  ...interfaceTypeIds.length ? { interfaceTypeIds } : {},
24111
24123
  ...typeParameters.length ? { typeParameters } : {},
24112
24124
  ...classDeclaration?.modifiers.includes("abstract") ? { abstract: true } : {},
24125
+ ...classDeclaration?.modifiers.includes("sealed") ? { sealed: true } : {},
24113
24126
  location: location(info.uri, info.declaration.range),
24114
24127
  selectionLocation: location(info.uri, info.declaration.nameRange)
24115
24128
  };
@@ -24612,10 +24625,23 @@ function accessorBodyRange(source, bodyRange, keyword) {
24612
24625
  continue;
24613
24626
  }
24614
24627
  if (depth !== 1 || token.text !== keyword) continue;
24615
- const open = tokens[index + 1];
24628
+ let openIndex = index + 1;
24629
+ if (tokens[openIndex]?.text === "(") {
24630
+ let parameterDepth = 1;
24631
+ for (let cursor = openIndex + 1; cursor < tokens.length; cursor++) {
24632
+ const candidate = tokens[cursor];
24633
+ if (candidate.text === "(") parameterDepth++;
24634
+ if (candidate.text === ")") parameterDepth--;
24635
+ if (parameterDepth !== 0) continue;
24636
+ openIndex = cursor + 1;
24637
+ break;
24638
+ }
24639
+ if (parameterDepth !== 0) return null;
24640
+ }
24641
+ const open = tokens[openIndex];
24616
24642
  if (open?.text !== "{") return null;
24617
24643
  let accessorDepth = 1;
24618
- for (let cursor = index + 2; cursor < tokens.length; cursor++) {
24644
+ for (let cursor = openIndex + 1; cursor < tokens.length; cursor++) {
24619
24645
  const candidate = tokens[cursor];
24620
24646
  if (candidate.text === "{") accessorDepth++;
24621
24647
  if (candidate.text === "}") accessorDepth--;
@@ -31325,6 +31351,7 @@ function schemaClass(value, environment, field) {
31325
31351
  `${field}.implementsInterfaceIds`
31326
31352
  ),
31327
31353
  ...value.declarationModifier === "abstract" ? { abstract: true } : {},
31354
+ ...value.isSealed === true ? { sealed: true } : {},
31328
31355
  ...sourceLocation(value.source, environment, `${field}.source`),
31329
31356
  typeParameters: records(
31330
31357
  value.genericParameters ?? [],
@@ -31945,6 +31972,20 @@ function memberType(member, environment, visiting, field) {
31945
31972
  nullable: false
31946
31973
  };
31947
31974
  }
31975
+ if (kind === "variant") {
31976
+ const variantClass = [...environment.classes.values()].find(
31977
+ (candidate) => candidate.name === NEO_VARIANT_TYPE_NAME
31978
+ );
31979
+ if (variantClass === void 0) return { ...unknownType(), nullable };
31980
+ return {
31981
+ kind: "named",
31982
+ typeId: string2(variantClass.id, `${field}.variantClass.id`),
31983
+ typeArguments: [
31984
+ manifestType2(member.targetType, environment, `${field}.targetType`)
31985
+ ],
31986
+ nullable
31987
+ };
31988
+ }
31948
31989
  if (kind === "generic") {
31949
31990
  return typeParameter(
31950
31991
  string2(member.genericParamId, `${field}.genericParamId`),
@@ -32487,6 +32528,7 @@ var init_project_schema_manifest = __esm({
32487
32528
  "use strict";
32488
32529
  init_project();
32489
32530
  init_project_schema_contract_generated();
32531
+ init_language_spec();
32490
32532
  }
32491
32533
  });
32492
32534
 
@@ -46337,6 +46379,23 @@ var init_member_kinds_db_response = __esm({
46337
46379
  });
46338
46380
 
46339
46381
  // ../src/models/members/unordered-list-membership.ts
46382
+ function buildUnorderedListMembershipIndex(values) {
46383
+ const membersByContainerId = /* @__PURE__ */ new Map();
46384
+ for (const candidate of values) {
46385
+ const containerId = candidate.containerId;
46386
+ if (typeof containerId !== "string") continue;
46387
+ const bucket = membersByContainerId.get(containerId);
46388
+ if (bucket === void 0) {
46389
+ membersByContainerId.set(containerId, [candidate.id]);
46390
+ } else {
46391
+ bucket.push(candidate.id);
46392
+ }
46393
+ }
46394
+ for (const bucket of membersByContainerId.values()) {
46395
+ bucket.sort();
46396
+ }
46397
+ return membersByContainerId;
46398
+ }
46340
46399
  function unorderedListEntryIds(values, listValue2, membershipIndex) {
46341
46400
  if (!Array.isArray(listValue2.value)) return [];
46342
46401
  if (membershipIndex !== void 0) {
@@ -63887,9 +63946,11 @@ function makeEvaluatorLookups(members, values, options = {}) {
63887
63946
  for (const a of members) attrMap.set(a.id, a);
63888
63947
  const valMap = /* @__PURE__ */ new Map();
63889
63948
  for (const v of values) valMap.set(v.id, v);
63949
+ const unorderedListMembership = buildUnorderedListMembershipIndex(values);
63890
63950
  const lookups = {
63891
63951
  memberById: (id2) => attrMap.get(id2) ?? null,
63892
- valueById: (id2) => valMap.get(id2) ?? null
63952
+ valueById: (id2) => valMap.get(id2) ?? null,
63953
+ unorderedListEntryIds: (containerValueId) => unorderedListMembership.get(containerValueId) ?? []
63893
63954
  };
63894
63955
  if (options.includeValueGraphIndexes === true) {
63895
63956
  return {
@@ -67836,9 +67897,24 @@ function resolveValueIfIdForMember(at, member, ctx) {
67836
67897
  );
67837
67898
  if (!row) return at;
67838
67899
  ctx.valueDependencies?.add(row.id);
67900
+ if (isMemberListBase(member) && member.listKind === "unordered" && Array.isArray(row.value)) {
67901
+ return evaluatorUnorderedListEntryIds(row.id, ctx);
67902
+ }
67839
67903
  const value = resolveLocalizedRowValueForMember(row, member, ctx);
67840
67904
  return shouldUnwrapSingleLookupValue(member) ? unwrapSingleLookupValue(value, ctx) : value;
67841
67905
  }
67906
+ function evaluatorUnorderedListEntryIds(containerValueId, ctx) {
67907
+ const runtimeRows = [...ctx.__runtimeSessionValues?.values() ?? []];
67908
+ const overlayRows = [...ctx.__valueOverlay?.values() ?? []];
67909
+ const localRows = [...runtimeRows, ...overlayRows];
67910
+ const shadowedIds = new Set(localRows.map((row) => row.id));
67911
+ const baseIds = ctx.vm.databaseVM?.unorderedListEntryIds?.(containerValueId) ?? ctx.vm.values.filter((row) => row.containerId === containerValueId).map((row) => row.id);
67912
+ const ids = new Set(baseIds.filter((id2) => !shadowedIds.has(id2)));
67913
+ for (const row of localRows) {
67914
+ if (row.containerId === containerValueId) ids.add(row.id);
67915
+ }
67916
+ return [...ids].sort();
67917
+ }
67842
67918
  function shouldUnwrapSingleLookupValue(member) {
67843
67919
  if (member === null) return false;
67844
67920
  if (!isMemberLookup(member)) return false;
@@ -71980,7 +72056,7 @@ function initializerEvaluatorLookups(document) {
71980
72056
  });
71981
72057
  return lookups;
71982
72058
  }
71983
- function buildInitializerRootValue(document, lookups) {
72059
+ function buildInitializerRootValueWithLookups(document, lookups) {
71984
72060
  const rootValue = {};
71985
72061
  for (const { root, memberId } of projectRootMembersInDisplayOrder(
71986
72062
  document.project
@@ -72020,7 +72096,7 @@ function evaluateMemberInitializer(args) {
72020
72096
  databaseVM
72021
72097
  },
72022
72098
  thisValue: null,
72023
- rootValue: buildInitializerRootValue(args.document, databaseVM),
72099
+ rootValue: buildInitializerRootValueWithLookups(args.document, databaseVM),
72024
72100
  saveStaticBindings: args.saveStaticBindings,
72025
72101
  sessionStaticBindings: args.sessionStaticBindings,
72026
72102
  ...args.storedConstructionReplay === true ? {
@@ -111630,7 +111706,7 @@ var init_registry2 = __esm({
111630
111706
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
111631
111707
  formatVersion: 3,
111632
111708
  contractVersion: "3.13",
111633
- cliVersion: "0.31.15",
111709
+ cliVersion: "0.31.17",
111634
111710
  projectFileUploadBatchSize: 32,
111635
111711
  documentRecords: {
111636
111712
  member: {
@@ -118225,7 +118301,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
118225
118301
  async function main() {
118226
118302
  const args = parseArgs(process.argv.slice(2));
118227
118303
  if (args.command === "--version") {
118228
- console.log("0.31.15");
118304
+ console.log("0.31.17");
118229
118305
  return;
118230
118306
  }
118231
118307
  if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.31.15",
3
+ "version": "0.31.17",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,7 +9,7 @@ description: >-
9
9
  `@neocompose/cli` or `node cli/bin/neo.mjs` in the neo-compose repository.
10
10
  ---
11
11
 
12
- <!-- reviewed-through-cli: 0.31.15 -->
12
+ <!-- reviewed-through-cli: 0.31.17 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -83,7 +83,7 @@ wrappers.
83
83
  The marker near the top of `SKILL.md` must exactly match the package version:
84
84
 
85
85
  ```html
86
- <!-- reviewed-through-cli: 0.31.15 -->
86
+ <!-- reviewed-through-cli: 0.31.17 -->
87
87
  ```
88
88
 
89
89
  The quoted version above is checked too, so this instruction cannot go stale
@@ -56,6 +56,11 @@ or narrowing guard before the next access.
56
56
 
57
57
  Treat lookup-return values with the same nullable narrowing rules.
58
58
 
59
+ Runtime declaration patterns follow the possible runtime type, not only the
60
+ static declaration. An open Class value may match an otherwise unrelated
61
+ interface through a derived Class that implements it; a sealed Class with no
62
+ such relationship remains a compile-time impossible pattern.
63
+
59
64
  A declaration pattern introduced by `is` stays available after a guard when
60
65
  every path that falls through matched the pattern, including when the guard's
61
66
  other paths return from a nested block: