@neocompose/cli 0.68.2 → 0.68.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.68.3] - 2026-10-05
|
|
4
|
+
|
|
5
|
+
- `neo push --dry-run` preserves valid authored UUID-v4 IDs on new nested member and dictionary values, including values named by local declarations. Previously, verification dropped the ID and failed with an internal "has no pending id assignment" error. Status and push report malformed new member-value IDs at the annotation, name the affected `Class.Member`, and suggest removing `@id` or providing an unused UUID v4 ([#1189](https://github.com/ryanbliss/neo-compose/issues/1189)).
|
|
6
|
+
|
|
7
|
+
- A stored nested class value can keep its UUID-v4 when moved between compatible empty fields on existing parents. Its old owning declaration must be removed in the same push. Unsafe ownership changes are refused with an explanation.
|
|
8
|
+
|
|
9
|
+
- Trusted verification resolves complete pending IDs inside initializer code, so `Reference<T>(key:)` can target a row created in the same push without confusing its ID with the containing value's ID.
|
|
10
|
+
|
|
11
|
+
- An override of a generic class's function passes the push-time animation check, including an override of an override, as in `class ClampedIntWatcher : MinIntWatcher` where `MinIntWatcher : ValueWatcher<int>`. Before, status warned and test and push stopped with "Prospective animation validation received an invalid member record … (\"Apply\")" in any project with animation classes.
|
|
12
|
+
|
|
3
13
|
## [0.68.2] - 2026-10-05
|
|
4
14
|
|
|
5
15
|
- Local initializer IDs may appear above the variable declaration. Formatting and pull move inline IDs there while preserving the stored row identity. Nested IDs remain on their expressions.
|
package/dist/neo.mjs
CHANGED
|
@@ -31690,7 +31690,7 @@ var init_registry = __esm({
|
|
|
31690
31690
|
"../packages/manifest/schema-contract/registry.mjs"() {
|
|
31691
31691
|
"use strict";
|
|
31692
31692
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
31693
|
-
cliVersion: "0.68.
|
|
31693
|
+
cliVersion: "0.68.3",
|
|
31694
31694
|
projectFileUploadBatchSize: 32,
|
|
31695
31695
|
documentRecords: {
|
|
31696
31696
|
member: {
|
|
@@ -116847,6 +116847,59 @@ var init_client_commit_preparation = __esm({
|
|
|
116847
116847
|
}
|
|
116848
116848
|
});
|
|
116849
116849
|
|
|
116850
|
+
// src/project-source/identity-rewriter.ts
|
|
116851
|
+
function createIdentityRewriter(assignments, onReplace) {
|
|
116852
|
+
if (assignments.size === 0) return (value) => value;
|
|
116853
|
+
const root = { children: /* @__PURE__ */ new Map() };
|
|
116854
|
+
for (const [source, replacement] of assignments) {
|
|
116855
|
+
let prefix = root;
|
|
116856
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
116857
|
+
const character = source[index];
|
|
116858
|
+
let child2 = prefix.children.get(character);
|
|
116859
|
+
if (child2 === void 0) {
|
|
116860
|
+
child2 = { children: /* @__PURE__ */ new Map() };
|
|
116861
|
+
prefix.children.set(character, child2);
|
|
116862
|
+
}
|
|
116863
|
+
prefix = child2;
|
|
116864
|
+
}
|
|
116865
|
+
prefix.replacement = replacement;
|
|
116866
|
+
}
|
|
116867
|
+
return (value) => {
|
|
116868
|
+
const exact = assignments.get(value);
|
|
116869
|
+
if (exact !== void 0) {
|
|
116870
|
+
onReplace?.(value);
|
|
116871
|
+
return exact;
|
|
116872
|
+
}
|
|
116873
|
+
const parts = [];
|
|
116874
|
+
let copiedThrough = 0;
|
|
116875
|
+
for (let start = 0; start < value.length; start += 1) {
|
|
116876
|
+
let prefix = root.children.get(value[start]);
|
|
116877
|
+
let replacement;
|
|
116878
|
+
let end = start;
|
|
116879
|
+
for (let index = start; prefix !== void 0; index += 1) {
|
|
116880
|
+
if (prefix.replacement !== void 0) {
|
|
116881
|
+
replacement = prefix.replacement;
|
|
116882
|
+
end = index + 1;
|
|
116883
|
+
}
|
|
116884
|
+
prefix = prefix.children.get(value[index + 1]);
|
|
116885
|
+
}
|
|
116886
|
+
if (replacement === void 0) continue;
|
|
116887
|
+
onReplace?.(value.slice(start, end));
|
|
116888
|
+
parts.push(value.slice(copiedThrough, start), replacement);
|
|
116889
|
+
copiedThrough = end;
|
|
116890
|
+
start = end - 1;
|
|
116891
|
+
}
|
|
116892
|
+
if (copiedThrough === 0) return value;
|
|
116893
|
+
parts.push(value.slice(copiedThrough));
|
|
116894
|
+
return parts.join("");
|
|
116895
|
+
};
|
|
116896
|
+
}
|
|
116897
|
+
var init_identity_rewriter = __esm({
|
|
116898
|
+
"src/project-source/identity-rewriter.ts"() {
|
|
116899
|
+
"use strict";
|
|
116900
|
+
}
|
|
116901
|
+
});
|
|
116902
|
+
|
|
116850
116903
|
// src/project-source/schema-source-validation.ts
|
|
116851
116904
|
function sourceDiagnosticMapper(analysis) {
|
|
116852
116905
|
const locations = /* @__PURE__ */ new Map();
|
|
@@ -124875,7 +124928,8 @@ function computeWorkspaceStatus(workspace, options) {
|
|
|
124875
124928
|
claim.message,
|
|
124876
124929
|
position.file,
|
|
124877
124930
|
position.line,
|
|
124878
|
-
position.column
|
|
124931
|
+
position.column,
|
|
124932
|
+
claim.code
|
|
124879
124933
|
)
|
|
124880
124934
|
);
|
|
124881
124935
|
}
|
|
@@ -125305,7 +125359,7 @@ function prospectiveAnimationDocumentV4(records2) {
|
|
|
125305
125359
|
let project;
|
|
125306
125360
|
const constructors = [];
|
|
125307
125361
|
const classes = [];
|
|
125308
|
-
const
|
|
125362
|
+
const memberData = [];
|
|
125309
125363
|
const values = [];
|
|
125310
125364
|
for (const record6 of candidates) {
|
|
125311
125365
|
if (record6.recordKind === "project") {
|
|
@@ -125325,16 +125379,7 @@ function prospectiveAnimationDocumentV4(records2) {
|
|
|
125325
125379
|
}
|
|
125326
125380
|
classes.push(record6.data);
|
|
125327
125381
|
} else if (record6.recordKind === "member") {
|
|
125328
|
-
|
|
125329
|
-
record6.data,
|
|
125330
|
-
memberRecords
|
|
125331
|
-
);
|
|
125332
|
-
if (!isMember(member)) {
|
|
125333
|
-
throw new Error(
|
|
125334
|
-
`Prospective animation validation received an invalid member record ${recordLabel(record6.data)}.`
|
|
125335
|
-
);
|
|
125336
|
-
}
|
|
125337
|
-
members.push(member);
|
|
125382
|
+
memberData.push(record6.data);
|
|
125338
125383
|
} else if (record6.recordKind === "value") {
|
|
125339
125384
|
if (!isMemberValue(record6.data)) {
|
|
125340
125385
|
throw new Error(
|
|
@@ -125345,6 +125390,22 @@ function prospectiveAnimationDocumentV4(records2) {
|
|
|
125345
125390
|
}
|
|
125346
125391
|
}
|
|
125347
125392
|
if (project === void 0) return null;
|
|
125393
|
+
const members = [];
|
|
125394
|
+
const inheritedCallables = [];
|
|
125395
|
+
for (const data of memberData) {
|
|
125396
|
+
const member = hydrateProspectiveMemberOverride(data, memberRecords);
|
|
125397
|
+
if (typeof data.extendsMemberId === "string" && member.returnTypeInfo !== void 0) {
|
|
125398
|
+
inheritedCallables.push(member);
|
|
125399
|
+
} else {
|
|
125400
|
+
members.push(validProspectiveMember(member));
|
|
125401
|
+
}
|
|
125402
|
+
}
|
|
125403
|
+
const closedCallables = inheritedCallables.map(
|
|
125404
|
+
(member) => validProspectiveMember(
|
|
125405
|
+
closeInheritedCallableSignature(member, classes, members)
|
|
125406
|
+
)
|
|
125407
|
+
);
|
|
125408
|
+
members.push(...closedCallables);
|
|
125348
125409
|
const classesById = new Map(
|
|
125349
125410
|
classes.map((schemaClass2) => [schemaClass2.id, schemaClass2])
|
|
125350
125411
|
);
|
|
@@ -125768,6 +125829,36 @@ function hydrateProspectiveMemberOverride(data, members) {
|
|
|
125768
125829
|
}
|
|
125769
125830
|
return hydrated;
|
|
125770
125831
|
}
|
|
125832
|
+
function validProspectiveMember(member) {
|
|
125833
|
+
if (!isMember(member)) {
|
|
125834
|
+
throw new Error(
|
|
125835
|
+
`Prospective animation validation received an invalid member record ${recordLabel(member)}.`
|
|
125836
|
+
);
|
|
125837
|
+
}
|
|
125838
|
+
return member;
|
|
125839
|
+
}
|
|
125840
|
+
function closeInheritedCallableSignature(member, classes, members) {
|
|
125841
|
+
if (typeof member.id !== "string") return member;
|
|
125842
|
+
const env = resolveDeclaringClassGenericEnv(member.id, classes);
|
|
125843
|
+
if (env.size === 0) return member;
|
|
125844
|
+
const close = (typeInfo) => substituteInheritedCallableTypeInfo(typeInfo, env, classes, members);
|
|
125845
|
+
const closed = { ...member };
|
|
125846
|
+
if (isNSFunctionReturnTypeInfo(member.returnTypeInfo)) {
|
|
125847
|
+
closed.returnTypeInfo = close(member.returnTypeInfo);
|
|
125848
|
+
}
|
|
125849
|
+
if (Array.isArray(member.argumentTypes)) {
|
|
125850
|
+
closed.argumentTypes = member.argumentTypes.map((argument2) => {
|
|
125851
|
+
if (!isNSFunctionArgumentTypeInfo(argument2)) return argument2;
|
|
125852
|
+
const { name, defaultValue } = argument2;
|
|
125853
|
+
return {
|
|
125854
|
+
...close(argument2),
|
|
125855
|
+
name,
|
|
125856
|
+
...defaultValue === void 0 ? {} : { defaultValue }
|
|
125857
|
+
};
|
|
125858
|
+
});
|
|
125859
|
+
}
|
|
125860
|
+
return closed;
|
|
125861
|
+
}
|
|
125771
125862
|
function resolveProspectiveMemberField(start, field, members) {
|
|
125772
125863
|
let current = start;
|
|
125773
125864
|
const visited = /* @__PURE__ */ new Set();
|
|
@@ -126149,6 +126240,8 @@ var init_workspace_status_core = __esm({
|
|
|
126149
126240
|
init_project_documents();
|
|
126150
126241
|
init_animation_clips();
|
|
126151
126242
|
init_classes();
|
|
126243
|
+
init_generics();
|
|
126244
|
+
init_neoscript_guards();
|
|
126152
126245
|
init_members();
|
|
126153
126246
|
init_value_row_owner_members();
|
|
126154
126247
|
init_constructors2();
|
|
@@ -126255,7 +126348,16 @@ ${blockingErrors.map((error) => error.message).join("\n")}` : `Trusted source lo
|
|
|
126255
126348
|
);
|
|
126256
126349
|
const usedAssignments = /* @__PURE__ */ new Set();
|
|
126257
126350
|
const positionless = positionIndependentAssignments(assignments);
|
|
126258
|
-
const
|
|
126351
|
+
const rewriteEmbedded = createIdentityRewriter(assignments, (id2) => {
|
|
126352
|
+
usedAssignments.add(id2);
|
|
126353
|
+
});
|
|
126354
|
+
const rewrite = (value) => rewritePending(
|
|
126355
|
+
value,
|
|
126356
|
+
assignments,
|
|
126357
|
+
usedAssignments,
|
|
126358
|
+
positionless,
|
|
126359
|
+
rewriteEmbedded
|
|
126360
|
+
);
|
|
126259
126361
|
const expectedChanges = status.changes.map((change) => {
|
|
126260
126362
|
const rewrittenData = change.nextData === void 0 ? void 0 : rewrite(change.nextData);
|
|
126261
126363
|
return {
|
|
@@ -126495,7 +126597,7 @@ function relocatedAssignment(pendingId2, assignments, byPosition, used) {
|
|
|
126495
126597
|
const relocatedVirtual = pendingVirtualValueId(relocatedRoot, sourceIdentity3);
|
|
126496
126598
|
return assignments.has(relocatedVirtual) ? relocatedVirtual : null;
|
|
126497
126599
|
}
|
|
126498
|
-
function rewritePending(value, assignments, used, positionless) {
|
|
126600
|
+
function rewritePending(value, assignments, used, positionless, rewriteEmbedded) {
|
|
126499
126601
|
if (typeof value === "string") {
|
|
126500
126602
|
const exact = assignments.get(value);
|
|
126501
126603
|
if (exact !== void 0) {
|
|
@@ -126518,28 +126620,23 @@ function rewritePending(value, assignments, used, positionless) {
|
|
|
126518
126620
|
);
|
|
126519
126621
|
}
|
|
126520
126622
|
if (!value.includes("__pending__:")) return value;
|
|
126521
|
-
|
|
126522
|
-
for (const [pendingId2, assignedId] of assignments) {
|
|
126523
|
-
if (!rewritten.includes(pendingId2)) continue;
|
|
126524
|
-
rewritten = rewritten.replaceAll(pendingId2, assignedId);
|
|
126525
|
-
used.add(pendingId2);
|
|
126526
|
-
}
|
|
126527
|
-
return rewritten;
|
|
126623
|
+
return rewriteEmbedded(value);
|
|
126528
126624
|
}
|
|
126529
126625
|
if (Array.isArray(value)) {
|
|
126530
126626
|
return value.map(
|
|
126531
|
-
(entry) => rewritePending(entry, assignments, used, positionless)
|
|
126627
|
+
(entry) => rewritePending(entry, assignments, used, positionless, rewriteEmbedded)
|
|
126532
126628
|
);
|
|
126533
126629
|
}
|
|
126534
126630
|
if (isObjectRecord2(value)) {
|
|
126535
126631
|
const result = {};
|
|
126536
126632
|
for (const [key, entry] of Object.entries(value)) {
|
|
126537
|
-
const rewrittenKey = key.startsWith("__pending__:") ? rewritePending(key, assignments, used, positionless) : key;
|
|
126633
|
+
const rewrittenKey = key.startsWith("__pending__:") ? rewritePending(key, assignments, used, positionless, rewriteEmbedded) : key;
|
|
126538
126634
|
result[rewrittenKey] = rewritePending(
|
|
126539
126635
|
entry,
|
|
126540
126636
|
assignments,
|
|
126541
126637
|
used,
|
|
126542
|
-
positionless
|
|
126638
|
+
positionless,
|
|
126639
|
+
rewriteEmbedded
|
|
126543
126640
|
);
|
|
126544
126641
|
}
|
|
126545
126642
|
return result;
|
|
@@ -126775,6 +126872,7 @@ var ProjectSourceCommitVerificationError, ABSENT_DIFFERENCE_VALUE;
|
|
|
126775
126872
|
var init_trusted_commit_verification = __esm({
|
|
126776
126873
|
"src/project-source/trusted-commit-verification.ts"() {
|
|
126777
126874
|
"use strict";
|
|
126875
|
+
init_identity_rewriter();
|
|
126778
126876
|
init_schema_source_validation();
|
|
126779
126877
|
init_projectRecordBuckets();
|
|
126780
126878
|
init_workspace_status_core();
|
|
@@ -128342,6 +128440,8 @@ function createValueLowerRegistryV4(options = {}) {
|
|
|
128342
128440
|
initAuthoredRowIds: /* @__PURE__ */ new Map(),
|
|
128343
128441
|
loweringFailures: [],
|
|
128344
128442
|
storedRowClaims: /* @__PURE__ */ new Map(),
|
|
128443
|
+
movedValueSites: /* @__PURE__ */ new Map(),
|
|
128444
|
+
storedMoveRoots: /* @__PURE__ */ new Map(),
|
|
128345
128445
|
placedStoredRowIds: /* @__PURE__ */ new Set(),
|
|
128346
128446
|
pendingValueIdentitySites: /* @__PURE__ */ new Map(),
|
|
128347
128447
|
initializerSites: /* @__PURE__ */ new Map(),
|
|
@@ -128468,6 +128568,7 @@ function buildValueLowerContext(state, manifest, options = {}) {
|
|
|
128468
128568
|
localizationConversionValueIds: registry.localizationConversionValueIds,
|
|
128469
128569
|
loweredMemberIdByValueId: /* @__PURE__ */ new Map(),
|
|
128470
128570
|
storedClassSchemaMemberIds: /* @__PURE__ */ new Map(),
|
|
128571
|
+
ordinaryMoveFields: /* @__PURE__ */ new Map(),
|
|
128471
128572
|
pendingBindingMembersByClassId: registry.pendingBindingMembersByClassId,
|
|
128472
128573
|
declaredConstructors: declaredConstructorIndex,
|
|
128473
128574
|
initAuthoredRowIds: seedInitAuthoredRowIds(
|
|
@@ -128481,6 +128582,8 @@ function buildValueLowerContext(state, manifest, options = {}) {
|
|
|
128481
128582
|
referenceObligations: registry.referenceObligations,
|
|
128482
128583
|
loweringFailures: registry.loweringFailures,
|
|
128483
128584
|
storedRowClaims: registry.storedRowClaims,
|
|
128585
|
+
movedValueSites: registry.movedValueSites,
|
|
128586
|
+
storedMoveRoots: registry.storedMoveRoots,
|
|
128484
128587
|
placedStoredRowIds: registry.placedStoredRowIds,
|
|
128485
128588
|
pendingValueIdentitySites: registry.pendingValueIdentitySites,
|
|
128486
128589
|
initializerSites: registry.initializerSites,
|
|
@@ -129131,6 +129234,21 @@ function drainValueReferenceObligationsV4(state, manifest, options) {
|
|
|
129131
129234
|
})
|
|
129132
129235
|
});
|
|
129133
129236
|
const failures = [];
|
|
129237
|
+
const movedRoots = /* @__PURE__ */ new Map();
|
|
129238
|
+
for (const [valueId, move] of options.registry.movedValueSites) {
|
|
129239
|
+
const placements = context.valuePlacements.placementsByValueId.get(valueId) ?? [];
|
|
129240
|
+
let message;
|
|
129241
|
+
if (placements.length !== 1) {
|
|
129242
|
+
message = `Value @id(${JSON.stringify(valueId)}) must have exactly one owning slot after a move; found ${placements.length}. Remove its declaration from the old parent before keeping the same ID on the new owner.`;
|
|
129243
|
+
} else if (singleSlotBindingRoot(context, valueId, movedRoots) !== move.rootValueId) {
|
|
129244
|
+
message = `Value @id(${JSON.stringify(valueId)}) cannot move: moves require one acyclic path under the same root or static binding, through non-overridden class fields with inherited storage and automatic distribution.`;
|
|
129245
|
+
} else continue;
|
|
129246
|
+
failures.push({
|
|
129247
|
+
code: "invalid-value-move",
|
|
129248
|
+
message,
|
|
129249
|
+
...composeReferenceSitePosition(move.site, options.sourceTextByUri)
|
|
129250
|
+
});
|
|
129251
|
+
}
|
|
129134
129252
|
for (const recorded of options.registry.loweringFailures) {
|
|
129135
129253
|
failures.push({
|
|
129136
129254
|
message: recorded.message,
|
|
@@ -129730,27 +129848,17 @@ function lowerRowBackedDefault(context, member, backed, baseData3, binding) {
|
|
|
129730
129848
|
const childValueMember = recursivePartialMember(member, childMember);
|
|
129731
129849
|
const childSlice = assignmentSlices.get(assignment.name);
|
|
129732
129850
|
const existingId = isObjectRecord2(baseBody) ? baseBody[assignment.name] : void 0;
|
|
129733
|
-
|
|
129734
|
-
|
|
129735
|
-
|
|
129736
|
-
|
|
129737
|
-
|
|
129738
|
-
|
|
129739
|
-
|
|
129740
|
-
|
|
129741
|
-
|
|
129742
|
-
|
|
129743
|
-
|
|
129744
|
-
childSlice
|
|
129745
|
-
);
|
|
129746
|
-
continue;
|
|
129747
|
-
}
|
|
129748
|
-
if (!isPendingId(storedId) && !isUuidV4Id(storedId)) {
|
|
129749
|
-
context.loweringFailures.push({
|
|
129750
|
-
message: `Default value ${binding.label}.${assignment.name} is annotated @id("${storedId}"), which names no existing row, and a new row's durable identity must be a UUID v4. Fix the id if it meant an existing row, or drop the @id to mint a fresh identity.`,
|
|
129751
|
-
site: referenceSite(binding, assignment.value)
|
|
129752
|
-
});
|
|
129753
|
-
}
|
|
129851
|
+
if (typeof existingId === "string") {
|
|
129852
|
+
body[assignment.name] = lowerValueRow(
|
|
129853
|
+
context,
|
|
129854
|
+
childValueMember,
|
|
129855
|
+
assignment.value,
|
|
129856
|
+
existingId,
|
|
129857
|
+
binding,
|
|
129858
|
+
environment,
|
|
129859
|
+
childSlice
|
|
129860
|
+
);
|
|
129861
|
+
continue;
|
|
129754
129862
|
}
|
|
129755
129863
|
const placedId = sourceValueSymbol(context, assignment.value);
|
|
129756
129864
|
if (placedId !== null) {
|
|
@@ -129782,6 +129890,7 @@ function lowerRowBackedDefault(context, member, backed, baseData3, binding) {
|
|
|
129782
129890
|
}
|
|
129783
129891
|
const entryMember = requiredMember(context, member.entryMemberId);
|
|
129784
129892
|
const existingIds = new Set(backed.body);
|
|
129893
|
+
const placedIds = /* @__PURE__ */ new Set();
|
|
129785
129894
|
const entrySlices = topLevelEntrySlices(binding.initializer, "[", "]");
|
|
129786
129895
|
const ids = expression.elements.map((element, index) => {
|
|
129787
129896
|
const symbolId = sourceValueSymbol(context, element);
|
|
@@ -129812,6 +129921,21 @@ function lowerRowBackedDefault(context, member, backed, baseData3, binding) {
|
|
|
129812
129921
|
entrySlices[index]
|
|
129813
129922
|
);
|
|
129814
129923
|
}
|
|
129924
|
+
if (!existingIds.has(itemId)) {
|
|
129925
|
+
context.storedRowClaims.set(itemId, {
|
|
129926
|
+
code: "invalid-value-move",
|
|
129927
|
+
message: `Value @id(${JSON.stringify(itemId)}) cannot move into another default list. Remove @id to create a new value.`,
|
|
129928
|
+
site: referenceSite(binding, element)
|
|
129929
|
+
});
|
|
129930
|
+
return itemId;
|
|
129931
|
+
}
|
|
129932
|
+
recordRepeatedRow(
|
|
129933
|
+
context,
|
|
129934
|
+
itemId,
|
|
129935
|
+
`Default list ${binding.label}`,
|
|
129936
|
+
referenceSite(binding, element),
|
|
129937
|
+
placedIds
|
|
129938
|
+
);
|
|
129815
129939
|
return lowerValueRow(
|
|
129816
129940
|
context,
|
|
129817
129941
|
entryMember,
|
|
@@ -129832,6 +129956,8 @@ function lowerRowBackedDefault(context, member, backed, baseData3, binding) {
|
|
|
129832
129956
|
const keyEnum = dictionaryKeyEnum(context, member);
|
|
129833
129957
|
const baseBody = backed.body;
|
|
129834
129958
|
const body = {};
|
|
129959
|
+
const existingIds = new Set(Object.values(baseBody));
|
|
129960
|
+
const placedIds = /* @__PURE__ */ new Set();
|
|
129835
129961
|
const entrySlices = topLevelEntrySlices(binding.initializer, "{", "}");
|
|
129836
129962
|
let entryIndex = 0;
|
|
129837
129963
|
for (const entry of expression.entries) {
|
|
@@ -129843,6 +129969,23 @@ function lowerRowBackedDefault(context, member, backed, baseData3, binding) {
|
|
|
129843
129969
|
`Default dictionary ${binding.label}[${JSON.stringify(key)}] has no existing owned value row. Creating new default rows from source is not implemented by this slice.`
|
|
129844
129970
|
);
|
|
129845
129971
|
}
|
|
129972
|
+
if (context.state[`value:${entryId}`] !== void 0 && !existingIds.has(entryId)) {
|
|
129973
|
+
context.storedRowClaims.set(entryId, {
|
|
129974
|
+
code: "invalid-value-move",
|
|
129975
|
+
message: `Value @id(${JSON.stringify(entryId)}) cannot move into another default dictionary. Remove @id to create a new value.`,
|
|
129976
|
+
site: referenceSite(binding, entry.value)
|
|
129977
|
+
});
|
|
129978
|
+
body[key] = entryId;
|
|
129979
|
+
entryIndex += 1;
|
|
129980
|
+
continue;
|
|
129981
|
+
}
|
|
129982
|
+
recordRepeatedRow(
|
|
129983
|
+
context,
|
|
129984
|
+
entryId,
|
|
129985
|
+
`Default dictionary ${binding.label}`,
|
|
129986
|
+
referenceSite(binding, entry.value),
|
|
129987
|
+
placedIds
|
|
129988
|
+
);
|
|
129846
129989
|
body[key] = lowerValueRow(
|
|
129847
129990
|
context,
|
|
129848
129991
|
entryMember,
|
|
@@ -130909,8 +131052,64 @@ function structuralMemberByParameterName(context, effectiveClass) {
|
|
|
130909
131052
|
function lowerSeedChild(context, member, expression, source, path, rows, localizedTexts, containerId, environment, authoredSlice) {
|
|
130910
131053
|
const symbolId = sourceValueSymbol(context, expression);
|
|
130911
131054
|
if (symbolId !== null) return symbolId;
|
|
130912
|
-
const
|
|
131055
|
+
const local = context.localValues.resolve(expression, source);
|
|
131056
|
+
const annotatedId = annotatedValue(local.expression).id;
|
|
131057
|
+
if (annotatedId !== null && !isPendingId(annotatedId) && context.state[`value:${annotatedId}`] === void 0 && member.owner.kind === "classMember" && !isUuidV4Id(annotatedId)) {
|
|
131058
|
+
const owner = context.classes.get(member.owner.classId)?.name;
|
|
131059
|
+
const name = owner === void 0 ? member.name : `${owner}.${member.name}`;
|
|
131060
|
+
context.loweringFailures.push({
|
|
131061
|
+
code: "invalid-new-value-id",
|
|
131062
|
+
message: `Value ${name} has @id(${JSON.stringify(annotatedId)}), which names no existing row. A new nested value requires a UUID v4. Remove @id to let Neo assign the value's identity, or provide a valid, unused UUID v4.`,
|
|
131063
|
+
site: referenceSiteAt(
|
|
131064
|
+
local.source,
|
|
131065
|
+
local.expression.kind === "annotated" ? local.expression.annotations.find((entry) => entry.name === "id")?.pos ?? local.expression.pos : local.expression.pos
|
|
131066
|
+
)
|
|
131067
|
+
});
|
|
131068
|
+
}
|
|
130913
131069
|
const valueId = annotatedId ?? context.structuralStoredIds.get(path) ?? pendingNestedValueId(source, path);
|
|
131070
|
+
if (!context.structuralConstruction && annotatedId !== null && context.state[`value:${annotatedId}`] !== void 0) {
|
|
131071
|
+
const failure = storedClassMoveFailure(
|
|
131072
|
+
context,
|
|
131073
|
+
member,
|
|
131074
|
+
annotatedId,
|
|
131075
|
+
path,
|
|
131076
|
+
containerId
|
|
131077
|
+
);
|
|
131078
|
+
if (failure !== null) {
|
|
131079
|
+
context.storedRowClaims.set(annotatedId, {
|
|
131080
|
+
code: "invalid-value-move",
|
|
131081
|
+
message: failure,
|
|
131082
|
+
site: referenceSite(local.source, local.expression)
|
|
131083
|
+
});
|
|
131084
|
+
return annotatedId;
|
|
131085
|
+
}
|
|
131086
|
+
const rootValueId = singleSlotBindingRoot(
|
|
131087
|
+
context,
|
|
131088
|
+
annotatedId,
|
|
131089
|
+
context.storedMoveRoots
|
|
131090
|
+
);
|
|
131091
|
+
if (rootValueId === null) {
|
|
131092
|
+
context.storedRowClaims.set(annotatedId, {
|
|
131093
|
+
code: "invalid-value-move",
|
|
131094
|
+
message: `Value @id(${JSON.stringify(annotatedId)}) cannot move: moves require an existing path to a root or static binding through non-overridden class fields with inherited storage and automatic distribution.`,
|
|
131095
|
+
site: referenceSite(local.source, local.expression)
|
|
131096
|
+
});
|
|
131097
|
+
return annotatedId;
|
|
131098
|
+
}
|
|
131099
|
+
context.movedValueSites.set(annotatedId, {
|
|
131100
|
+
site: referenceSite(local.source, local.expression),
|
|
131101
|
+
rootValueId
|
|
131102
|
+
});
|
|
131103
|
+
return lowerValueRow(
|
|
131104
|
+
context,
|
|
131105
|
+
member,
|
|
131106
|
+
expression,
|
|
131107
|
+
annotatedId,
|
|
131108
|
+
source,
|
|
131109
|
+
environment,
|
|
131110
|
+
authoredSlice
|
|
131111
|
+
);
|
|
131112
|
+
}
|
|
130914
131113
|
lowerSeedRow(
|
|
130915
131114
|
context,
|
|
130916
131115
|
member,
|
|
@@ -130926,6 +131125,99 @@ function lowerSeedChild(context, member, expression, source, path, rows, localiz
|
|
|
130926
131125
|
);
|
|
130927
131126
|
return valueId;
|
|
130928
131127
|
}
|
|
131128
|
+
function singleSlotBindingRoot(context, start, roots) {
|
|
131129
|
+
const placements = context.valuePlacements;
|
|
131130
|
+
const path = /* @__PURE__ */ new Set();
|
|
131131
|
+
let cursor = start;
|
|
131132
|
+
let root = null;
|
|
131133
|
+
while (!path.has(cursor)) {
|
|
131134
|
+
const cached = roots.get(cursor);
|
|
131135
|
+
if (cached !== void 0) {
|
|
131136
|
+
root = cached;
|
|
131137
|
+
break;
|
|
131138
|
+
}
|
|
131139
|
+
if (placements.memberIdsByBoundValueId.has(cursor)) {
|
|
131140
|
+
root = cursor;
|
|
131141
|
+
break;
|
|
131142
|
+
}
|
|
131143
|
+
path.add(cursor);
|
|
131144
|
+
const parents = placements.placementsByValueId.get(cursor) ?? [];
|
|
131145
|
+
const parent = parents[0];
|
|
131146
|
+
if (parents.length !== 1 || parent === void 0) break;
|
|
131147
|
+
if (parent.containerClassId === null) break;
|
|
131148
|
+
const key = `${parent.containerClassId}:${parent.schemaKey}`;
|
|
131149
|
+
let ordinary = context.ordinaryMoveFields.get(key);
|
|
131150
|
+
if (ordinary === void 0) {
|
|
131151
|
+
const member = classMemberByName(
|
|
131152
|
+
context,
|
|
131153
|
+
parent.containerClassId,
|
|
131154
|
+
parent.schemaKey
|
|
131155
|
+
);
|
|
131156
|
+
ordinary = member.overrideOf === null && member.storage === null && member.storageKey === null && member.distribution === null;
|
|
131157
|
+
context.ordinaryMoveFields.set(key, ordinary);
|
|
131158
|
+
}
|
|
131159
|
+
if (!ordinary) break;
|
|
131160
|
+
cursor = parent.containerValueId;
|
|
131161
|
+
}
|
|
131162
|
+
for (const id2 of path) roots.set(id2, root);
|
|
131163
|
+
return root;
|
|
131164
|
+
}
|
|
131165
|
+
function storedClassMoveFailure(context, member, valueId, path, containerId) {
|
|
131166
|
+
const refuse = (reason) => `Value @id(${JSON.stringify(valueId)}) cannot move: ${reason}. Remove @id to create a new value.`;
|
|
131167
|
+
if (!isUuidV4Id(valueId))
|
|
131168
|
+
return refuse("its identity is derived from its original placement");
|
|
131169
|
+
if (containerId !== void 0)
|
|
131170
|
+
return refuse("unordered-list membership is immutable");
|
|
131171
|
+
if (member.owner.kind !== "classMember")
|
|
131172
|
+
return refuse("the new owner is not a class member");
|
|
131173
|
+
if (member.kind !== "class")
|
|
131174
|
+
return refuse("only nested class values support moves");
|
|
131175
|
+
const base = valueBase(context, valueId);
|
|
131176
|
+
if (typeof base.containerId === "string")
|
|
131177
|
+
return refuse("unordered-list membership is immutable");
|
|
131178
|
+
if ((context.valuePlacements.memberIdsByBoundValueId.get(valueId)?.length ?? 0) > 0)
|
|
131179
|
+
return refuse("a root or static binding owns it");
|
|
131180
|
+
const placement = context.readStoredValuePlacements().placementByChildValueId.get(valueId);
|
|
131181
|
+
if (placement === void 0)
|
|
131182
|
+
return refuse("its old owning class slot could not be resolved");
|
|
131183
|
+
if (placement.source !== "body")
|
|
131184
|
+
return refuse("its old owner supplies it through a constructor");
|
|
131185
|
+
const parent = valueBase(context, placement.parentValueId);
|
|
131186
|
+
const targetParentId = path.slice(0, -(member.name.length + 1));
|
|
131187
|
+
if (context.state[`value:${targetParentId}`] === void 0)
|
|
131188
|
+
return refuse("the new parent is not an existing stored class value");
|
|
131189
|
+
const targetParent = valueBase(context, targetParentId);
|
|
131190
|
+
for (const row of [base, parent, targetParent]) {
|
|
131191
|
+
if (typeof row.sourceValueId === "string")
|
|
131192
|
+
return refuse("a projected value depends on its original owner");
|
|
131193
|
+
if (typeof row.mapKey === "string")
|
|
131194
|
+
return refuse("partitioned values cannot change ownership");
|
|
131195
|
+
if (isObjectRecord2(row.genericBindings) && Object.keys(row.genericBindings).length > 0)
|
|
131196
|
+
return refuse("generic value ownership cannot be changed");
|
|
131197
|
+
}
|
|
131198
|
+
if (typeof targetParent.instanceConstructorId === "string" || isObjectRecord2(targetParent.constructorArgs) && Object.keys(targetParent.constructorArgs).length > 0)
|
|
131199
|
+
return refuse("the new owner has constructor creation data");
|
|
131200
|
+
if (typeof parent.instanceConstructorId === "string" || isObjectRecord2(parent.constructorArgs) && Object.keys(parent.constructorArgs).length > 0)
|
|
131201
|
+
return refuse("its old owner has constructor creation data");
|
|
131202
|
+
const oldMember = placement.memberId === null ? void 0 : context.members.get(placement.memberId);
|
|
131203
|
+
if (oldMember?.kind !== "class")
|
|
131204
|
+
return refuse(
|
|
131205
|
+
"its old owner is not a class member containing a class value"
|
|
131206
|
+
);
|
|
131207
|
+
if (oldMember.storageKey !== member.storageKey)
|
|
131208
|
+
return refuse("the new member declares a different storage key");
|
|
131209
|
+
if (oldMember.distribution !== member.distribution)
|
|
131210
|
+
return refuse("the new member declares a different distribution");
|
|
131211
|
+
if (oldMember.storage !== member.storage)
|
|
131212
|
+
return refuse("the new member uses different storage");
|
|
131213
|
+
if (oldMember.classId !== member.classId)
|
|
131214
|
+
return refuse("the new member declares a different class type");
|
|
131215
|
+
if (Object.keys(oldMember.classArguments).length > 0)
|
|
131216
|
+
return refuse("generic member ownership cannot be changed");
|
|
131217
|
+
if (Object.keys(member.classArguments).length > 0)
|
|
131218
|
+
return refuse("the new member declares generic arguments");
|
|
131219
|
+
return null;
|
|
131220
|
+
}
|
|
130929
131221
|
function unorderedRowSubtreePath(valueId, path, containerId) {
|
|
130930
131222
|
if (containerId === void 0 || containerId === null) return path;
|
|
130931
131223
|
return valueId;
|
|
@@ -131174,7 +131466,8 @@ function lowerValueBody(context, member, expression, base, source, environment,
|
|
|
131174
131466
|
expression,
|
|
131175
131467
|
base,
|
|
131176
131468
|
source,
|
|
131177
|
-
environment
|
|
131469
|
+
environment,
|
|
131470
|
+
authoredSlice
|
|
131178
131471
|
);
|
|
131179
131472
|
default:
|
|
131180
131473
|
throw new Error(
|
|
@@ -132133,9 +132426,9 @@ function lowerListValue(context, member, expression, base, source, inheritedEnvi
|
|
|
132133
132426
|
value: member.listKind === "unordered" ? [] : ids
|
|
132134
132427
|
};
|
|
132135
132428
|
}
|
|
132136
|
-
function recordRepeatedRow(context, rowId, collection, site) {
|
|
132137
|
-
if (!
|
|
132138
|
-
|
|
132429
|
+
function recordRepeatedRow(context, rowId, collection, site, placedIds = context.placedStoredRowIds) {
|
|
132430
|
+
if (!placedIds.has(rowId)) {
|
|
132431
|
+
placedIds.add(rowId);
|
|
132139
132432
|
return;
|
|
132140
132433
|
}
|
|
132141
132434
|
context.loweringFailures.push({
|
|
@@ -132177,18 +132470,20 @@ function existingListItemIds(context, member, base) {
|
|
|
132177
132470
|
Array.isArray(base.value) ? base.value.filter((entry) => typeof entry === "string") : []
|
|
132178
132471
|
);
|
|
132179
132472
|
}
|
|
132180
|
-
function lowerDictionaryValue(context, member, expression, base, source, inheritedEnvironment) {
|
|
132473
|
+
function lowerDictionaryValue(context, member, expression, base, source, inheritedEnvironment, authoredSlice) {
|
|
132181
132474
|
if (expression.kind === "litNull")
|
|
132182
132475
|
return { ...valueFileFields(base), value: null };
|
|
132183
132476
|
if (expression.kind !== "litDict") {
|
|
132184
132477
|
throw new Error("Dictionary values require {...}.");
|
|
132185
132478
|
}
|
|
132186
132479
|
const baseBody = isObjectRecord2(base.value) ? base.value : {};
|
|
132480
|
+
const existingIds = new Set(Object.values(baseBody));
|
|
132187
132481
|
const keyEnum = dictionaryKeyEnum(context, member);
|
|
132188
132482
|
const entryMember = requiredMember(context, member.entryMemberId);
|
|
132189
132483
|
const environment = valueGenericEnvironment(base, inheritedEnvironment);
|
|
132190
132484
|
const body = {};
|
|
132191
|
-
|
|
132485
|
+
const entrySlices = authoredSlice === void 0 ? [] : topLevelEntrySlices(authoredSlice, "{", "}");
|
|
132486
|
+
for (const [entryIndex, entry] of expression.entries.entries()) {
|
|
132192
132487
|
const key = lowerDictionaryKey(entry.key, keyEnum, member.name);
|
|
132193
132488
|
const existingId = baseBody[key];
|
|
132194
132489
|
const symbolId = sourceValueSymbol(context, entry.value);
|
|
@@ -132208,6 +132503,15 @@ function lowerDictionaryValue(context, member, expression, base, source, inherit
|
|
|
132208
132503
|
`Dictionary ${member.name}[${JSON.stringify(key)}] has no existing row. New dictionary entries are not implemented by this slice.`
|
|
132209
132504
|
);
|
|
132210
132505
|
}
|
|
132506
|
+
if (context.state[`value:${valueId}`] !== void 0 && !existingIds.has(valueId)) {
|
|
132507
|
+
context.storedRowClaims.set(valueId, {
|
|
132508
|
+
code: "invalid-value-move",
|
|
132509
|
+
message: `Value @id(${JSON.stringify(valueId)}) cannot move into another dictionary. Remove @id to create a new value.`,
|
|
132510
|
+
site: referenceSite(source, entry.value)
|
|
132511
|
+
});
|
|
132512
|
+
body[key] = valueId;
|
|
132513
|
+
continue;
|
|
132514
|
+
}
|
|
132211
132515
|
recordRepeatedRow(
|
|
132212
132516
|
context,
|
|
132213
132517
|
valueId,
|
|
@@ -132220,7 +132524,8 @@ function lowerDictionaryValue(context, member, expression, base, source, inherit
|
|
|
132220
132524
|
entry.value,
|
|
132221
132525
|
valueId,
|
|
132222
132526
|
source,
|
|
132223
|
-
environment
|
|
132527
|
+
environment,
|
|
132528
|
+
dictionaryValueSlice(entrySlices[entryIndex])
|
|
132224
132529
|
);
|
|
132225
132530
|
}
|
|
132226
132531
|
return { ...valueFileFields(base), value: body };
|
|
@@ -133724,6 +134029,15 @@ function emitValue(context, member, valueId, options) {
|
|
|
133724
134029
|
);
|
|
133725
134030
|
return prefixFor(expression);
|
|
133726
134031
|
}
|
|
134032
|
+
function needsProspectiveValueIdentity(context, valueId, parentId, key) {
|
|
134033
|
+
if (pendingVirtualValueIdentity(valueId) !== null) return true;
|
|
134034
|
+
if (context.storedValueBase === void 0 || isPendingId(valueId))
|
|
134035
|
+
return false;
|
|
134036
|
+
if (typeof parentId !== "string")
|
|
134037
|
+
return !context.storedValueBase.has(valueId);
|
|
134038
|
+
const storedBody = context.storedValueBase.get(parentId)?.value;
|
|
134039
|
+
return !isObjectRecord2(storedBody) || storedBody[key] !== valueId;
|
|
134040
|
+
}
|
|
133727
134041
|
function emitValueBody(context, member, value, visited, targetTyped, environment) {
|
|
133728
134042
|
const kind = numberField(member, "kind");
|
|
133729
134043
|
const body = value.value;
|
|
@@ -133993,9 +134307,13 @@ function classValueBody(context, member, value, visited, targetTyped, outerEnvir
|
|
|
133993
134307
|
`${key} = ${emitValue(context, emittedChildMember, childId, {
|
|
133994
134308
|
environment,
|
|
133995
134309
|
definitionSite: !context.symbolsByValueId.has(childId),
|
|
133996
|
-
//
|
|
133997
|
-
|
|
133998
|
-
|
|
134310
|
+
// New and moved identities must survive repeat lowering against the old placement.
|
|
134311
|
+
writeIdentity: needsProspectiveValueIdentity(
|
|
134312
|
+
context,
|
|
134313
|
+
childId,
|
|
134314
|
+
value.id,
|
|
134315
|
+
key
|
|
134316
|
+
),
|
|
133999
134317
|
visited
|
|
134000
134318
|
})}`
|
|
134001
134319
|
);
|
|
@@ -135273,9 +135591,14 @@ ${entries.flatMap(
|
|
|
135273
135591
|
{
|
|
135274
135592
|
environment,
|
|
135275
135593
|
definitionSite: !context.symbolsByValueId.has(id2),
|
|
135276
|
-
//
|
|
135277
|
-
//
|
|
135278
|
-
writeIdentity:
|
|
135594
|
+
// Existing keys recover identity from their owning row;
|
|
135595
|
+
// new authored identities must survive repeat lowering.
|
|
135596
|
+
writeIdentity: needsProspectiveValueIdentity(
|
|
135597
|
+
context,
|
|
135598
|
+
id2,
|
|
135599
|
+
value.id,
|
|
135600
|
+
key
|
|
135601
|
+
),
|
|
135279
135602
|
visited
|
|
135280
135603
|
}
|
|
135281
135604
|
)}`,
|
|
@@ -137495,55 +137818,6 @@ var init_status_output = __esm({
|
|
|
137495
137818
|
}
|
|
137496
137819
|
});
|
|
137497
137820
|
|
|
137498
|
-
// src/project-source/identity-rewriter.ts
|
|
137499
|
-
function createIdentityRewriter(assignments) {
|
|
137500
|
-
if (assignments.size === 0) return (value) => value;
|
|
137501
|
-
const root = { children: /* @__PURE__ */ new Map() };
|
|
137502
|
-
for (const [source, replacement] of assignments) {
|
|
137503
|
-
let prefix = root;
|
|
137504
|
-
for (let index = 0; index < source.length; index += 1) {
|
|
137505
|
-
const character = source[index];
|
|
137506
|
-
let child2 = prefix.children.get(character);
|
|
137507
|
-
if (child2 === void 0) {
|
|
137508
|
-
child2 = { children: /* @__PURE__ */ new Map() };
|
|
137509
|
-
prefix.children.set(character, child2);
|
|
137510
|
-
}
|
|
137511
|
-
prefix = child2;
|
|
137512
|
-
}
|
|
137513
|
-
prefix.replacement = replacement;
|
|
137514
|
-
}
|
|
137515
|
-
return (value) => {
|
|
137516
|
-
const exact = assignments.get(value);
|
|
137517
|
-
if (exact !== void 0) return exact;
|
|
137518
|
-
const parts = [];
|
|
137519
|
-
let copiedThrough = 0;
|
|
137520
|
-
for (let start = 0; start < value.length; start += 1) {
|
|
137521
|
-
let prefix = root.children.get(value[start]);
|
|
137522
|
-
let replacement;
|
|
137523
|
-
let end = start;
|
|
137524
|
-
for (let index = start; prefix !== void 0; index += 1) {
|
|
137525
|
-
if (prefix.replacement !== void 0) {
|
|
137526
|
-
replacement = prefix.replacement;
|
|
137527
|
-
end = index + 1;
|
|
137528
|
-
}
|
|
137529
|
-
prefix = prefix.children.get(value[index + 1]);
|
|
137530
|
-
}
|
|
137531
|
-
if (replacement === void 0) continue;
|
|
137532
|
-
parts.push(value.slice(copiedThrough, start), replacement);
|
|
137533
|
-
copiedThrough = end;
|
|
137534
|
-
start = end - 1;
|
|
137535
|
-
}
|
|
137536
|
-
if (copiedThrough === 0) return value;
|
|
137537
|
-
parts.push(value.slice(copiedThrough));
|
|
137538
|
-
return parts.join("");
|
|
137539
|
-
};
|
|
137540
|
-
}
|
|
137541
|
-
var init_identity_rewriter = __esm({
|
|
137542
|
-
"src/project-source/identity-rewriter.ts"() {
|
|
137543
|
-
"use strict";
|
|
137544
|
-
}
|
|
137545
|
-
});
|
|
137546
|
-
|
|
137547
137821
|
// src/project-source/source-layout.ts
|
|
137548
137822
|
import { readFileSync as readFileSync9 } from "node:fs";
|
|
137549
137823
|
import { relative as relative4, sep as sep4 } from "node:path";
|
|
@@ -164838,7 +165112,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
164838
165112
|
async function main() {
|
|
164839
165113
|
const args = parseArgs(process.argv.slice(2));
|
|
164840
165114
|
if (args.command === "--version") {
|
|
164841
|
-
console.log("0.68.
|
|
165115
|
+
console.log("0.68.3");
|
|
164842
165116
|
return;
|
|
164843
165117
|
}
|
|
164844
165118
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/package.json
CHANGED
|
@@ -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.68.
|
|
12
|
+
<!-- reviewed-through-cli: 0.68.3 -->
|
|
13
13
|
|
|
14
14
|
# Neo Compose CLI
|
|
15
15
|
|
|
@@ -63,8 +63,9 @@ opaque JSON or guessed syntax.
|
|
|
63
63
|
values, files, or other records. `@system` is reserved for platform-owned
|
|
64
64
|
system records; authoring it can make the record uneditable.
|
|
65
65
|
- Preserve existing `@id` annotations through rename, reorder, and file moves.
|
|
66
|
-
A
|
|
67
|
-
|
|
66
|
+
A copy must get a new ID. A stored nested class value may keep its UUID-v4
|
|
67
|
+
when moved between compatible empty fields on existing parents, provided
|
|
68
|
+
its old parent no longer declares it. See the identity reference for limits.
|
|
68
69
|
- Omit `@id` on new ordinary declarations and nested rows unless a same-push
|
|
69
70
|
structural reference genuinely requires an explicit UUID. A successful push
|
|
70
71
|
assigns the durable IDs and rewrites source.
|
|
@@ -110,7 +110,7 @@ wrappers.
|
|
|
110
110
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
111
111
|
|
|
112
112
|
```html
|
|
113
|
-
<!-- reviewed-through-cli: 0.68.
|
|
113
|
+
<!-- reviewed-through-cli: 0.68.3 -->
|
|
114
114
|
```
|
|
115
115
|
|
|
116
116
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -57,9 +57,19 @@ keys as quoted IDs when their option has been deleted.
|
|
|
57
57
|
|
|
58
58
|
## Identity rules
|
|
59
59
|
|
|
60
|
-
Preserve every existing ID through rename, reorder, and file moves. A
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
Preserve every existing ID through rename, reorder, and file moves. A copy
|
|
61
|
+
must get a new ID. A stored nested class value may keep its UUID-v4 when moved
|
|
62
|
+
to an empty, compatible class field on another existing parent. Remove its
|
|
63
|
+
old owning declaration in the same push. Both fields must declare the same
|
|
64
|
+
non-generic class and storage rules. The move must leave exactly one owning
|
|
65
|
+
path to the same root or static binding through ordinary class fields.
|
|
66
|
+
Both ownership paths must use inherited storage and automatic distribution;
|
|
67
|
+
member overrides are not supported for moves. Moving
|
|
68
|
+
projected values, constructor-owned slots, partitioned values, generic
|
|
69
|
+
instances, or unordered-list entries is refused. Moves into newly constructed
|
|
70
|
+
parents are also refused; omit the ID to create a new value there.
|
|
71
|
+
|
|
72
|
+
For a new ordinary record, omit
|
|
63
73
|
`@id` and let a successful real push assign and insert it. Dry-run and failed pushes
|
|
64
74
|
leave tracked source unchanged.
|
|
65
75
|
|
|
@@ -91,6 +101,11 @@ form, an author may assign a previously unseen UUID-v4 with `@id` to the new
|
|
|
91
101
|
row and reference it in the same edit. Reusing an existing ID means update, not
|
|
92
102
|
create. The server validates authored new IDs for UUID-v4 shape and uniqueness.
|
|
93
103
|
Prefer generated IDs unless the structural reference needs an ID immediately.
|
|
104
|
+
Dry-run preserves a valid authored UUID-v4 ID on a new nested member or dictionary
|
|
105
|
+
value, including one declared as a local initializer. An unknown malformed member
|
|
106
|
+
value ID is an error at its annotation; remove `@id` to let push assign the ID,
|
|
107
|
+
or supply an unused UUID v4. This does not change the derived identity of a
|
|
108
|
+
root/static binding or an existing projected value.
|
|
94
109
|
|
|
95
110
|
Do not invent IDs for structural rows whose identities derive from an owner
|
|
96
111
|
role. Do not add a separate root/static initializer ID. A constructor argument
|