@neocompose/cli 0.48.2 → 0.48.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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.48.3] - 2026-09-10
4
+
5
+ - Show inherited generic binding defaults in implicit constructions, so sparse
6
+ instances expose their effective values and no longer warn about unsettled
7
+ required members. Matching defaults remain virtual through pull/status and
8
+ edits create ordinary sparse overrides. Recorded constructors keep their
9
+ own settlement behavior.
10
+ - Preserve hidden collection argument defaults and ordering when lowering
11
+ unchanged generic types.
12
+
3
13
  ## [0.48.2] - 2026-09-10
4
14
 
5
15
  - Emit class member defaults with contextual `new()` when they construct the declared type, while keeping an explicit concrete type for subclass defaults.
package/dist/neo.mjs CHANGED
@@ -64603,6 +64603,22 @@ function manifestTypeForMember(context, member) {
64603
64603
  }
64604
64604
  return primitive3;
64605
64605
  }
64606
+ if (member.kind === "list" || member.kind === "dictionary") {
64607
+ const entry = context.baseMembers.get(member.entryMemberId);
64608
+ if (entry === void 0)
64609
+ throw new Error(
64610
+ `Collection ${member.name} has no entry member ${member.entryMemberId}.`
64611
+ );
64612
+ const entryType = manifestTypeForMember(context, entry);
64613
+ if (member.kind === "list")
64614
+ return { name: "List", nullable: nullable2, arguments: [entryType] };
64615
+ const keyType = {
64616
+ name: member.key.kind === "string" ? "string" : context.baseEnums.get(member.key.enumId)?.name ?? "object",
64617
+ nullable: false,
64618
+ arguments: []
64619
+ };
64620
+ return { name: "Dictionary", nullable: nullable2, arguments: [keyType, entryType] };
64621
+ }
64606
64622
  if (member.kind === "class") {
64607
64623
  const schemaClass2 = context.baseClasses.get(member.classId);
64608
64624
  const classType = {
@@ -64848,6 +64864,16 @@ function lowerGenericArgument(context, ownerClass, type, memberId, genericParamI
64848
64864
  const base = context.baseMembers.get(memberId);
64849
64865
  if (base && JSON.stringify(manifestTypeForMember(context, base)) === JSON.stringify(type)) {
64850
64866
  context.loweredMembers.set(memberId, { ...base, owner });
64867
+ if (base.kind === "list" || base.kind === "dictionary") {
64868
+ lowerCollectionEntry(
64869
+ context,
64870
+ ownerClass,
64871
+ requiredTypeArgument(type, base.kind === "list" ? 0 : 1),
64872
+ base.entryMemberId,
64873
+ memberId,
64874
+ memberId
64875
+ );
64876
+ }
64851
64877
  return;
64852
64878
  }
64853
64879
  const declaration = {
@@ -113263,6 +113289,7 @@ function buildValueEmitContext(records2, manifest) {
113263
113289
  },
113264
113290
  members,
113265
113291
  classes,
113292
+ implicitGenericMembersByClassId: /* @__PURE__ */ new Map(),
113266
113293
  manifestMembers,
113267
113294
  manifestClasses: new Map(
113268
113295
  manifest.classes.map((schemaClass2) => [schemaClass2.id, schemaClass2])
@@ -116497,18 +116524,32 @@ function lowerClassValue(context, member, expression, base, source, outerEnviron
116497
116524
  `Class value ${String(base.id)}.${assignment.name} cannot place existing value ${symbolId2} into a new structural slot. Create the nested value inline so the atomic construction transaction can own it.`
116498
116525
  );
116499
116526
  }
116500
- body[assignment.name] = lowerSeedChild(
116527
+ const rows = /* @__PURE__ */ new Map();
116528
+ const localizedTexts = /* @__PURE__ */ new Map();
116529
+ const seededId = lowerSeedChild(
116501
116530
  context,
116502
116531
  recursivePartialMember(member, childMember),
116503
116532
  assignment.value,
116504
116533
  source,
116505
116534
  `${String(base.id)}.${assignment.name}`,
116506
- /* @__PURE__ */ new Map(),
116507
- /* @__PURE__ */ new Map(),
116535
+ rows,
116536
+ localizedTexts,
116508
116537
  void 0,
116509
116538
  environment,
116510
116539
  assignmentSlices.get(assignment.name)
116511
116540
  );
116541
+ if (!partial && freshChildReplaysDeclaredDefault({
116542
+ context,
116543
+ childMember,
116544
+ childId: seededId,
116545
+ rows,
116546
+ localizedTexts,
116547
+ environment
116548
+ })) {
116549
+ deleteSeedRow(context, rows, seededId);
116550
+ continue;
116551
+ }
116552
+ body[assignment.name] = seededId;
116512
116553
  continue;
116513
116554
  }
116514
116555
  const symbolId = sourceValueSymbol(context, assignment.value);
@@ -118309,23 +118350,33 @@ function freshChildReplaysDeclaredDefault(args) {
118309
118350
  if (child.instanceVariantId != null) return false;
118310
118351
  if (child.instanceVariantRowValueId != null) return false;
118311
118352
  if (context.collectionBindingMemberIds.has(childMember.id)) return false;
118312
- const defaultValue = childMember.defaultValue;
118313
- if (defaultValue === null || defaultValue === void 0) return false;
118314
- if (!("value" in defaultValue)) return false;
118315
118353
  const resolved = resolveGenericSchemaMember(
118316
118354
  context,
118317
118355
  childMember,
118318
118356
  environment
118319
118357
  );
118358
+ let defaultValue = null;
118359
+ if (resolved.defaultValue && "value" in resolved.defaultValue) {
118360
+ defaultValue = resolved.defaultValue;
118361
+ } else if (resolved.defaultValue && "serverValueId" in resolved.defaultValue) {
118362
+ const storedMember = context.state[`member:${resolved.id}`]?.data;
118363
+ const storedDefault = isObjectRecord2(storedMember) ? storedMember.defaultValue : null;
118364
+ if (isObjectRecord2(storedDefault) && "value" in storedDefault) {
118365
+ defaultValue = {
118366
+ value: storedDefault.value,
118367
+ classId: storedDefault.classId
118368
+ };
118369
+ }
118370
+ }
118371
+ if (defaultValue === null) return false;
118320
118372
  if (resolved.kind === "lookup" || resolved.kind === "dialogueLookup") {
118321
118373
  return false;
118322
118374
  }
118323
118375
  if (resolved.kind === "class") {
118324
- return freshConstructionReplaysDeclaredDefault(
118325
- resolved,
118326
- child,
118327
- defaultValue
118328
- );
118376
+ return freshConstructionReplaysDeclaredDefault(resolved, child, {
118377
+ value: defaultValue.value,
118378
+ classId: defaultValue.classId
118379
+ });
118329
118380
  }
118330
118381
  if (resolved.kind === "list") {
118331
118382
  return Array.isArray(child.value) && child.value.length === 0 && !context.pendingContainerChildCounts.has(childId) && Array.isArray(defaultValue.value) && defaultValue.value.length === 0 && child.classId == null && (child.constructorArgs == null || Object.keys(child.constructorArgs).length === 0) && child.instanceConstructorId == null;
@@ -118903,6 +118954,41 @@ function classValue(context, member, value, visited, targetTyped, outerEnvironme
118903
118954
  );
118904
118955
  overrideKeys.add(key);
118905
118956
  }
118957
+ if (!partial && value.instanceVariantId == null && value.instanceVariantRowValueId == null) {
118958
+ for (const [key, genericMember] of implicitGenericMembers(
118959
+ context,
118960
+ classId
118961
+ )) {
118962
+ if (key in value.value) continue;
118963
+ const parameterId = stringField3(genericMember, "genericParamId");
118964
+ if (!environment.has(parameterId)) continue;
118965
+ const binding = resolveGenericValueMember(
118966
+ context,
118967
+ genericMember,
118968
+ environment
118969
+ );
118970
+ const kind = numberField(binding, "kind");
118971
+ if (!IMPLICIT_GENERIC_DEFAULT_KINDS.has(kind)) continue;
118972
+ if (kind === 3 /* String */ && isLocalizedStringMember(binding))
118973
+ continue;
118974
+ if (binding.payload === 1 /* Partial */) continue;
118975
+ const defaultValue = binding.defaultValue;
118976
+ if (!isObjectRecord2(defaultValue) || !("value" in defaultValue)) continue;
118977
+ const body = defaultValue.value;
118978
+ if (body === null) continue;
118979
+ if (Array.isArray(body) && body.length > 0) continue;
118980
+ if (isObjectRecord2(body) && Object.keys(body).length > 0) continue;
118981
+ const expression = emitValueBody(
118982
+ context,
118983
+ binding,
118984
+ defaultValue,
118985
+ /* @__PURE__ */ new Set(),
118986
+ (defaultValue.classId ?? binding.classId) === binding.classId,
118987
+ environment
118988
+ );
118989
+ fields.push(`${key} = ${expression}`);
118990
+ }
118991
+ }
118906
118992
  if (partial) {
118907
118993
  return fields.length === 0 ? "new { }" : `new {
118908
118994
  ${fields.map((field) => indentNeoSourceNonEmptyLines(field, 2)).join(",\n")}
@@ -118921,6 +119007,33 @@ ${fields.map((field) => indentNeoSourceNonEmptyLines(field, 2)).join(",\n")}
118921
119007
  ${fields.map((field) => indentNeoSourceNonEmptyLines(field, 2)).join(",\n")}
118922
119008
  }`;
118923
119009
  }
119010
+ function implicitGenericMembers(context, classId) {
119011
+ const cached = context.implicitGenericMembersByClassId.get(classId);
119012
+ if (cached !== void 0) return cached;
119013
+ const result = /* @__PURE__ */ new Map();
119014
+ const seenKeys = /* @__PURE__ */ new Set();
119015
+ const seenClasses = /* @__PURE__ */ new Set();
119016
+ let current = context.manifestClasses.get(classId);
119017
+ while (current !== void 0 && !seenClasses.has(current.id)) {
119018
+ seenClasses.add(current.id);
119019
+ if (current.requiredConstructorId || current.constructorIds?.length) {
119020
+ result.clear();
119021
+ context.implicitGenericMembersByClassId.set(classId, result);
119022
+ return result;
119023
+ }
119024
+ for (const [key, memberId] of Object.entries(current.schema)) {
119025
+ if (seenKeys.has(key)) continue;
119026
+ seenKeys.add(key);
119027
+ const member = context.members.get(memberId);
119028
+ if (member?.kind === 21 /* Generic */ && !isObjectRecord2(member.init)) {
119029
+ result.set(key, member);
119030
+ }
119031
+ }
119032
+ current = current.extendsClassId === null ? void 0 : context.manifestClasses.get(current.extendsClassId);
119033
+ }
119034
+ context.implicitGenericMembersByClassId.set(classId, result);
119035
+ return result;
119036
+ }
118924
119037
  function emitsAsMemberDefaultDerivedAbsence(context, member, valueId) {
118925
119038
  const value = context.values.get(valueId);
118926
119039
  if (value === void 0) return false;
@@ -120456,7 +120569,7 @@ function memberDefaultBody(member) {
120456
120569
  if (!("value" in defaultValue)) return null;
120457
120570
  return defaultValue.value;
120458
120571
  }
120459
- var INFERRED_GENERIC_CLASS_PREFIX, MEMBER_KIND_DICTIONARY2, MEMBER_KIND_LIST2, MEMBER_KIND_CLASS2, LEADING_AUTHORED_ROW_ID, CANONICAL_CONSTRUCTOR_INLINE_WIDTH;
120572
+ var INFERRED_GENERIC_CLASS_PREFIX, MEMBER_KIND_DICTIONARY2, MEMBER_KIND_LIST2, MEMBER_KIND_CLASS2, IMPLICIT_GENERIC_DEFAULT_KINDS, LEADING_AUTHORED_ROW_ID, CANONICAL_CONSTRUCTOR_INLINE_WIDTH;
120460
120573
  var init_value_sources = __esm({
120461
120574
  "src/project-source/value-sources.ts"() {
120462
120575
  "use strict";
@@ -120496,6 +120609,16 @@ var init_value_sources = __esm({
120496
120609
  MEMBER_KIND_DICTIONARY2 = 5;
120497
120610
  MEMBER_KIND_LIST2 = 6;
120498
120611
  MEMBER_KIND_CLASS2 = 7;
120612
+ IMPLICIT_GENERIC_DEFAULT_KINDS = /* @__PURE__ */ new Set([
120613
+ 1 /* Bool */,
120614
+ 2 /* Int */,
120615
+ 4 /* Float */,
120616
+ 20 /* Decimal */,
120617
+ 3 /* String */,
120618
+ 7 /* Class */,
120619
+ 6 /* List */,
120620
+ 5 /* Dictionary */
120621
+ ]);
120499
120622
  LEADING_AUTHORED_ROW_ID = /^@id\(\s*"((?:[^"\\]|\\.)*)"\s*\)/;
120500
120623
  CANONICAL_CONSTRUCTOR_INLINE_WIDTH = 88;
120501
120624
  }
@@ -131454,7 +131577,7 @@ var init_registry2 = __esm({
131454
131577
  "schema-contract/registry.mjs"() {
131455
131578
  "use strict";
131456
131579
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
131457
- cliVersion: "0.48.2",
131580
+ cliVersion: "0.48.3",
131458
131581
  projectFileUploadBatchSize: 32,
131459
131582
  documentRecords: {
131460
131583
  member: {
@@ -138504,7 +138627,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
138504
138627
  async function main() {
138505
138628
  const args = parseArgs(process.argv.slice(2));
138506
138629
  if (args.command === "--version") {
138507
- console.log("0.48.2");
138630
+ console.log("0.48.3");
138508
138631
  return;
138509
138632
  }
138510
138633
  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.48.2",
3
+ "version": "0.48.3",
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.48.2 -->
12
+ <!-- reviewed-through-cli: 0.48.3 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -88,7 +88,7 @@ wrappers.
88
88
  The marker near the top of `SKILL.md` must exactly match the package version:
89
89
 
90
90
  ```html
91
- <!-- reviewed-through-cli: 0.48.2 -->
91
+ <!-- reviewed-through-cli: 0.48.3 -->
92
92
  ```
93
93
 
94
94
  The quoted version above is checked too, so this instruction cannot go stale
@@ -136,6 +136,12 @@ member creates a sparse override with its deterministic projected ID; removing
136
136
  that member from an existing initializer resets the override and resumes source
137
137
  tracking. Require either transition to appear in `neo diff`.
138
138
 
139
+ A concrete generic argument can carry a default that its type spelling does
140
+ not show. Pull writes nonlocalized scalar and empty aggregate binding defaults at implicit
141
+ construction sites, for example `DefaultData = new()`. Keeping that expression
142
+ unchanged or omitting it retains the virtual default; editing it creates an
143
+ override. A default that selects a subtype keeps the explicit subtype name.
144
+
139
145
  Editing an initializer updates sparse override rows in place: projected member
140
146
  IDs remain stable, and omitted virtual rows are never emitted as authored seed
141
147
  records. Spelling a declared default verbatim in a new initializer lowers to