@neocompose/cli 0.35.0 → 0.35.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.35.1] - 2026-08-19
4
+
5
+ ### Fixed
6
+
7
+ - Treat `Partial<T>` values as sparse deltas throughout lowering and emission,
8
+ without invoking or reconstructing `T`'s required constructor.
9
+ - Materialize complete Unity defaults for template-less image and audio
10
+ registry entries instead of writing an invalid template override shape.
11
+ - Keep declarations inside variant delegate closures out of the global-child
12
+ registry, so separate `initialize` and `apply` closures may reuse local names.
13
+
3
14
  ## [0.35.0] - 2026-08-19
4
15
 
5
16
  ### Added
package/dist/neo.mjs CHANGED
@@ -18907,6 +18907,14 @@ function collectGlobalChildEntries(sourceText, declaration) {
18907
18907
  let pendingAnnotations = [];
18908
18908
  for (let index = 0; index < tokens.length; index++) {
18909
18909
  const token = tokens[index];
18910
+ if (token.text === "(" || token.text === "[") {
18911
+ groupDepth++;
18912
+ continue;
18913
+ }
18914
+ if (token.text === ")" || token.text === "]") {
18915
+ groupDepth--;
18916
+ continue;
18917
+ }
18910
18918
  if (token.text === "{") {
18911
18919
  braceDepth++;
18912
18920
  continue;
@@ -18916,14 +18924,6 @@ function collectGlobalChildEntries(sourceText, declaration) {
18916
18924
  continue;
18917
18925
  }
18918
18926
  if (braceDepth !== 1) continue;
18919
- if (token.text === "(" || token.text === "[") {
18920
- groupDepth++;
18921
- continue;
18922
- }
18923
- if (token.text === ")" || token.text === "]") {
18924
- groupDepth--;
18925
- continue;
18926
- }
18927
18927
  if (groupDepth !== 0) continue;
18928
18928
  if (token.text === ";") {
18929
18929
  pendingAnnotations = [];
@@ -48137,6 +48137,20 @@ function buildDefaultUnityTexture2DImportSettings() {
48137
48137
  }
48138
48138
  };
48139
48139
  }
48140
+ function buildDefaultUnityAudioClipImportSettings() {
48141
+ return {
48142
+ forceToMono: false,
48143
+ normalize: true,
48144
+ loadInBackground: false,
48145
+ ambisonic: false,
48146
+ loadType: "decompress-on-load" /* DecompressOnLoad */,
48147
+ compressionFormat: "vorbis" /* Vorbis */,
48148
+ quality: 1,
48149
+ sampleRateSetting: "preserve-sample-rate" /* PreserveSampleRate */,
48150
+ overrideSampleRate: null,
48151
+ preloadAudioData: true
48152
+ };
48153
+ }
48140
48154
  function isUnityVector2(value) {
48141
48155
  const v = value;
48142
48156
  if (!isObject(value)) return false;
@@ -53024,6 +53038,20 @@ var init_project_file_registry = __esm({
53024
53038
  });
53025
53039
 
53026
53040
  // src/project-source/project-file-source.ts
53041
+ function projectFileUnityImportSettingsV4(kind, templateId) {
53042
+ if (templateId === null) {
53043
+ return {
53044
+ ...kind === "image" ? buildDefaultUnityTexture2DImportSettings() : buildDefaultUnityAudioClipImportSettings(),
53045
+ templateId: null
53046
+ };
53047
+ }
53048
+ return {
53049
+ ...kind === "image" ? { type: "texture-2d" } : {},
53050
+ templateId,
53051
+ overridePaths: [],
53052
+ values: {}
53053
+ };
53054
+ }
53027
53055
  function emitProjectFileRegistrySourcesV4(records2) {
53028
53056
  const liveFiles = [...records2.values()].filter((record3) => record3.recordKind === "project-file" && !record3.deleted).map((record3) => ({ record: record3, data: requireFileData(record3) }));
53029
53057
  assertUniqueProjectBinaryPaths(liveFiles);
@@ -53142,12 +53170,10 @@ function lowerTrustedProjectFileRegistrySourcesV4(state, analysis, trustedPendin
53142
53170
  });
53143
53171
  }
53144
53172
  if (importSettingsChanged) {
53145
- next[settingsField] = {
53146
- ...declaration.kind === "image" ? { type: "texture-2d" } : {},
53147
- templateId: declaration.templateId,
53148
- overridePaths: [],
53149
- values: {}
53150
- };
53173
+ next[settingsField] = projectFileUnityImportSettingsV4(
53174
+ declaration.kind,
53175
+ declaration.templateId
53176
+ );
53151
53177
  }
53152
53178
  return {
53153
53179
  recordKind: "project-file",
@@ -53445,6 +53471,7 @@ var init_project_file_source = __esm({
53445
53471
  init_source_format();
53446
53472
  init_project_file_registry();
53447
53473
  init_members();
53474
+ init_unity_import_settings();
53448
53475
  REGISTRY_ENTRY = /(?:@id\(\s*("(?:[^"\\]|\\.)*")\s*\)\s*)?(?:@settings\(([\s\S]*?)\)\s*)?(NeoImage|NeoAudioClip)\s+([A-Za-z_][A-Za-z0-9_]*)\s*=\s*new\(\s*("(?:[^"\\]|\\.)*")\s*\)\s*;/gy;
53449
53476
  assignDeterministicFileSymbols = assignDeterministicProjectFileSymbols;
53450
53477
  }
@@ -98181,11 +98208,11 @@ function lowerMemberDefaultSourcesV4(state, analysis, manifest, options = {}) {
98181
98208
  context.parsedInitializers,
98182
98209
  declaration.initializer
98183
98210
  );
98184
- const requiresEvaluation = initializerRequiresEvaluation(
98185
- context.declaredConstructors,
98211
+ const requiresEvaluation = memberInitializerRequiresEvaluation(
98212
+ context,
98213
+ member,
98186
98214
  annotatedValue(expression).expression,
98187
- memberClassName(context, member),
98188
- bindingRuntimeIdentifiers(context, binding)
98215
+ binding
98189
98216
  );
98190
98217
  const baseData3 = stateData(context, "member", memberId);
98191
98218
  const annotatedExpression = annotatedValue(expression).expression;
@@ -98676,12 +98703,7 @@ function declaredCollectionMemberIds(context, collectionMemberId) {
98676
98703
  }
98677
98704
  function defaultRequiresOwnedRows(context, member, sourceExpression, source) {
98678
98705
  const expression = annotatedValue(sourceExpression).expression;
98679
- if (initializerRequiresEvaluation(
98680
- context.declaredConstructors,
98681
- expression,
98682
- memberClassName(context, member),
98683
- bindingRuntimeIdentifiers(context, source)
98684
- )) {
98706
+ if (memberInitializerRequiresEvaluation(context, member, expression, source)) {
98685
98707
  return false;
98686
98708
  }
98687
98709
  if (member.kind === "class") return expression.kind === "new";
@@ -98693,6 +98715,15 @@ function defaultRequiresOwnedRows(context, member, sourceExpression, source) {
98693
98715
  }
98694
98716
  return false;
98695
98717
  }
98718
+ function memberInitializerRequiresEvaluation(context, member, expression, source) {
98719
+ if (member.kind === "class" && member.partial === true) return false;
98720
+ return initializerRequiresEvaluation(
98721
+ context.declaredConstructors,
98722
+ expression,
98723
+ memberClassName(context, member),
98724
+ bindingRuntimeIdentifiers(context, source)
98725
+ );
98726
+ }
98696
98727
  function indexInitAuthoredRowIds(context, initSource, owner) {
98697
98728
  indexAuthoredRowIds(context.initAuthoredRowIds, initSource, owner);
98698
98729
  }
@@ -99240,7 +99271,7 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
99240
99271
  member,
99241
99272
  inheritedEnvironment
99242
99273
  );
99243
- if (context.structuralConstruction && resolvedMember.kind === "class" && expression.kind === "new" && structurallyConstructedClassId(context, resolvedMember, expression) !== null) {
99274
+ if (context.structuralConstruction && resolvedMember.kind === "class" && resolvedMember.partial !== true && expression.kind === "new" && structurallyConstructedClassId(context, resolvedMember, expression) !== null) {
99244
99275
  return lowerStructuralConstructionRow(
99245
99276
  context,
99246
99277
  resolvedMember,
@@ -99255,11 +99286,11 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
99255
99286
  authoredSlice
99256
99287
  );
99257
99288
  }
99258
- if (!isStoredCallableLiteral(resolvedMember.kind, expression) && initializerRequiresEvaluation(
99259
- context.declaredConstructors,
99289
+ if (!isStoredCallableLiteral(resolvedMember.kind, expression) && memberInitializerRequiresEvaluation(
99290
+ context,
99291
+ resolvedMember,
99260
99292
  expression,
99261
- memberClassName(context, resolvedMember),
99262
- bindingRuntimeIdentifiers(context, source)
99293
+ source
99263
99294
  )) {
99264
99295
  const unattachedId = annotated.id === null ? unattachedAuthoredRowId(authoredSlice) : null;
99265
99296
  if (unattachedId !== null) {
@@ -99321,7 +99352,8 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
99321
99352
  if (effectiveClass === void 0) {
99322
99353
  throw new Error(`Unknown value class ${resolvedMember.classId}.`);
99323
99354
  }
99324
- if (effectiveClass.declarationModifier === "abstract") {
99355
+ const partial = resolvedMember.partial === true;
99356
+ if (!partial && effectiveClass.declarationModifier === "abstract") {
99325
99357
  throw new Error(
99326
99358
  `Cannot instantiate abstract class ${effectiveClass.name} for ${path}. Use a concrete descendant instead.`
99327
99359
  );
@@ -99339,13 +99371,15 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
99339
99371
  expression,
99340
99372
  declaredEnvironment
99341
99373
  );
99342
- validateConstructedGenericArguments(
99343
- context,
99344
- effectiveClass,
99345
- expression,
99346
- environment,
99347
- path
99348
- );
99374
+ if (!partial) {
99375
+ validateConstructedGenericArguments(
99376
+ context,
99377
+ effectiveClass,
99378
+ expression,
99379
+ environment,
99380
+ path
99381
+ );
99382
+ }
99349
99383
  genericBindings = animationChildOverrideSeedBindings(
99350
99384
  context,
99351
99385
  effectiveClass,
@@ -99355,19 +99389,20 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
99355
99389
  );
99356
99390
  const body = {};
99357
99391
  const argumentSlices = constructorArgumentValueSlices(authoredSlice);
99358
- for (const {
99359
- projectedMember,
99360
- schemaKey,
99361
- argument: argument2,
99362
- argumentIndex
99363
- } of resolveConstructorProjectionArguments(
99392
+ const projectedArguments = partial ? [] : resolveConstructorProjectionArguments(
99364
99393
  context,
99365
99394
  effectiveClass,
99366
99395
  expression,
99367
99396
  valueId,
99368
99397
  environment,
99369
99398
  source
99370
- )) {
99399
+ );
99400
+ for (const {
99401
+ projectedMember,
99402
+ schemaKey,
99403
+ argument: argument2,
99404
+ argumentIndex
99405
+ } of projectedArguments) {
99371
99406
  const childPath = `${path}.${schemaKey}`;
99372
99407
  const childValueId = pendingNestedValueId(source, childPath);
99373
99408
  if (rows.has(childValueId)) {
@@ -99413,7 +99448,7 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
99413
99448
  effectiveClass.id,
99414
99449
  assignment.name
99415
99450
  );
99416
- if (inheritedLegacyConstructorProjections(
99451
+ if (!partial && inheritedLegacyConstructorProjections(
99417
99452
  context.classes,
99418
99453
  effectiveClass.id
99419
99454
  ).some((projection) => projection.memberId === childMember.id)) {
@@ -99853,11 +99888,11 @@ function lowerValueRow(context, member, sourceExpression, expectedValueId, sourc
99853
99888
  member,
99854
99889
  environment
99855
99890
  );
99856
- if (!isStoredCallableLiteral(resolvedMember.kind, expression) && initializerRequiresEvaluation(
99857
- context.declaredConstructors,
99891
+ if (!isStoredCallableLiteral(resolvedMember.kind, expression) && memberInitializerRequiresEvaluation(
99892
+ context,
99893
+ resolvedMember,
99858
99894
  expression,
99859
- memberClassName(context, resolvedMember),
99860
- bindingRuntimeIdentifiers(context, source)
99895
+ source
99861
99896
  )) {
99862
99897
  const code = initializerExpressionSlice(authoredSlice);
99863
99898
  if (code === void 0) {
@@ -100075,7 +100110,8 @@ function lowerClassValue(context, member, expression, base, source, outerEnviron
100075
100110
  const schemaClass2 = context.classes.get(classId);
100076
100111
  if (schemaClass2 === void 0)
100077
100112
  throw new Error(`Unknown value class ${classId}.`);
100078
- if (schemaClass2.declarationModifier === "abstract") {
100113
+ const partial = member.partial === true;
100114
+ if (!partial && schemaClass2.declarationModifier === "abstract") {
100079
100115
  throw new Error(
100080
100116
  `Cannot instantiate abstract class ${schemaClass2.name} for value ${String(base.id)}. Use a concrete descendant instead.`
100081
100117
  );
@@ -100090,13 +100126,15 @@ function lowerClassValue(context, member, expression, base, source, outerEnviron
100090
100126
  expression,
100091
100127
  declaredEnvironment
100092
100128
  );
100093
- validateConstructedGenericArguments(
100094
- context,
100095
- schemaClass2,
100096
- expression,
100097
- environment,
100098
- String(base.id ?? member.name)
100099
- );
100129
+ if (!partial) {
100130
+ validateConstructedGenericArguments(
100131
+ context,
100132
+ schemaClass2,
100133
+ expression,
100134
+ environment,
100135
+ String(base.id ?? member.name)
100136
+ );
100137
+ }
100100
100138
  const baseBody = isObjectRecord2(base.value) ? base.value : {};
100101
100139
  const body = retainedStoredClassBody(
100102
100140
  context,
@@ -100104,7 +100142,7 @@ function lowerClassValue(context, member, expression, base, source, outerEnviron
100104
100142
  baseBody
100105
100143
  );
100106
100144
  const assignmentSlices = objectInitializerSlices(authoredSlice);
100107
- if (materializedConstruction !== "preserve") {
100145
+ if (!partial && materializedConstruction !== "preserve") {
100108
100146
  lowerConstructorProjections(
100109
100147
  context,
100110
100148
  schemaClass2,
@@ -100119,7 +100157,7 @@ function lowerClassValue(context, member, expression, base, source, outerEnviron
100119
100157
  }
100120
100158
  for (const assignment of expression.initializer ?? []) {
100121
100159
  const childMember = classMemberByName(context, classId, assignment.name);
100122
- if (inheritedLegacyConstructorProjections(
100160
+ if (!partial && inheritedLegacyConstructorProjections(
100123
100161
  context.classes,
100124
100162
  schemaClass2.id
100125
100163
  ).some((projection) => projection.memberId === childMember.id)) {
@@ -102173,7 +102211,7 @@ function classValue(context, member, value, visited, targetTyped, outerEnvironme
102173
102211
  const hasStoredConstruction = isObjectRecord2(value.constructorArgs);
102174
102212
  let projection;
102175
102213
  try {
102176
- projection = hasStoredConstruction ? {
102214
+ projection = partial ? { arguments: [], memberIds: /* @__PURE__ */ new Set(), targetValueIds: [] } : hasStoredConstruction ? {
102177
102215
  arguments: [],
102178
102216
  memberIds: new Set(
102179
102217
  effectiveConstructorProjections(
@@ -102210,7 +102248,7 @@ function classValue(context, member, value, visited, targetTyped, outerEnvironme
102210
102248
  const name = classValueTypeName(context, classId, member, environment);
102211
102249
  let storedConstruction;
102212
102250
  try {
102213
- storedConstruction = storedConstructorCallSource(
102251
+ storedConstruction = partial ? null : storedConstructorCallSource(
102214
102252
  context,
102215
102253
  schemaClass2,
102216
102254
  value,
@@ -104166,12 +104204,10 @@ function lowerProjectFileRegistrySourcesV4(root, state, analysis, options = {})
104166
104204
  });
104167
104205
  }
104168
104206
  if (importSettingsChanged) {
104169
- next[settingsField] = {
104170
- ...declaration.kind === "image" ? { type: "texture-2d" } : {},
104171
- templateId: declaration.templateId,
104172
- overridePaths: [],
104173
- values: {}
104174
- };
104207
+ next[settingsField] = projectFileUnityImportSettingsV4(
104208
+ declaration.kind,
104209
+ declaration.templateId
104210
+ );
104175
104211
  }
104176
104212
  return {
104177
104213
  recordKind: "project-file",
@@ -104203,12 +104239,7 @@ function lowerDiscoveredProjectBinariesV4(root, state, analysis) {
104203
104239
  const templateId = binary.kind === "image" ? optionalString3(projectData.defaultTextureTemplateId) : optionalString3(projectData.defaultAudioClipTemplateId);
104204
104240
  const settingsField = binary.kind === "image" ? "unityTextureSettings" : "unityAudioClipSettings";
104205
104241
  const otherSettingsField = binary.kind === "image" ? "unityAudioClipSettings" : "unityTextureSettings";
104206
- const settings = {
104207
- ...binary.kind === "image" ? { type: "texture-2d" } : {},
104208
- templateId,
104209
- overridePaths: [],
104210
- values: {}
104211
- };
104242
+ const settings = projectFileUnityImportSettingsV4(binary.kind, templateId);
104212
104243
  const now = Date.now();
104213
104244
  return {
104214
104245
  recordKind: "project-file",
@@ -104581,6 +104612,7 @@ var init_project_files = __esm({
104581
104612
  init_source_format();
104582
104613
  init_members();
104583
104614
  init_project_file_registry();
104615
+ init_project_file_source();
104584
104616
  SUPPORTED_BINARY_TYPES = /* @__PURE__ */ new Map([
104585
104617
  [".png", { kind: "image", mimeType: "image/png" }],
104586
104618
  [".jpg", { kind: "image", mimeType: "image/jpeg" }],
@@ -113595,7 +113627,7 @@ var init_registry2 = __esm({
113595
113627
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
113596
113628
  formatVersion: 3,
113597
113629
  contractVersion: "3.14",
113598
- cliVersion: "0.35.0",
113630
+ cliVersion: "0.35.1",
113599
113631
  projectFileUploadBatchSize: 32,
113600
113632
  documentRecords: {
113601
113633
  member: {
@@ -120197,7 +120229,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
120197
120229
  async function main() {
120198
120230
  const args = parseArgs(process.argv.slice(2));
120199
120231
  if (args.command === "--version") {
120200
- console.log("0.35.0");
120232
+ console.log("0.35.1");
120201
120233
  return;
120202
120234
  }
120203
120235
  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.35.0",
3
+ "version": "0.35.1",
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.35.0 -->
12
+ <!-- reviewed-through-cli: 0.35.1 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -197,6 +197,8 @@ AudioClipRegistry AudioClips = new() {
197
197
  Use `Images.Sword.Slice(0)` for a sprite and `AudioClips.SwordHit` for audio.
198
198
  Renaming the registry symbol, moving the local presentation, or replacing bytes
199
199
  retains the file ID.
200
+ Omitting `@settings(template: ...)` uses the complete built-in Unity import
201
+ defaults for that file kind.
200
202
 
201
203
  ## Resolve conflicts by identity
202
204
 
@@ -50,7 +50,12 @@ NeoVariant<ExampleObject> Down = new(
50
50
  `() => new ExampleObject(.Down)` works; `apply` is void, so its expression
51
51
  body must be a call or an assignment, as in
52
52
  `(source) => source.FacingDir = .Down`. The server compiles them, so authored
53
- source carries only the code.
53
+ source carries only the code. Each closure has its own lexical scope, so
54
+ local names may be reused between `initialize` and `apply`.
55
+ - `overrides` and each child override's `overrides` value are `Partial<T>`
56
+ deltas over existing instances. They may use inferred `new { ... }` or
57
+ explicit `new Partial<T> { ... }`, and never pass arguments to or invoke
58
+ `T`'s constructor—even when `T` has a required constructor.
54
59
 
55
60
  Folders are records too, declared as their own globals and assigned per
56
61
  variant. Nesting is spelled in the path with `/`; intermediate segments are
@@ -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.35.0 -->
86
+ <!-- reviewed-through-cli: 0.35.1 -->
87
87
  ```
88
88
 
89
89
  The quoted version above is checked too, so this instruction cannot go stale
@@ -170,7 +170,8 @@ diff, and dry-run do not rewrite its registry. A successful push creates the
170
170
  record, uploads verified bytes, and materializes its declaration and ID.
171
171
 
172
172
  Edit the typed registry declaration directly when an explicit symbol or
173
- non-default template is needed before push.
173
+ non-default template is needed before push. With no template annotation, the
174
+ CLI persists the complete built-in Unity defaults for the file kind.
174
175
 
175
176
  Pull/push compare server-verified SHA-256, not storage ETags. A divergent
176
177
  binary keeps local bytes and writes the verified remote side under