@neocompose/cli 0.21.1 → 0.21.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 +22 -0
- package/dist/neo.mjs +269 -133
- package/package.json +1 -1
- package/skills/neocompose-cli/SKILL.md +1 -1
- package/skills/neocompose-cli/references/animation-and-world-authoring.md +3 -0
- package/skills/neocompose-cli/references/cli-development.md +1 -1
- package/skills/neocompose-cli/references/commands-and-sync.md +4 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.21.3] - 2026-08-03
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- `neo push` paints its preparation spinner before workspace discovery,
|
|
8
|
+
lowering, and NeoScript compilation begin, so large projects no longer look
|
|
9
|
+
stalled before the push plan appears.
|
|
10
|
+
- Animation segment frame values are emitted through the required `value`
|
|
11
|
+
constructor argument. Required sprites use the canonical `SpriteInfo.Empty`
|
|
12
|
+
value; `null` is reserved for nullable `SpriteInfo?` values.
|
|
13
|
+
|
|
14
|
+
## [0.21.2] - 2026-08-03
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Canonical pull emits `@id` only for structurally ambiguous positions such
|
|
19
|
+
as list entries. Class fields, dictionary entries, and constructor arguments
|
|
20
|
+
recover their value rows from the owning value and role instead of exposing
|
|
21
|
+
redundant P61 creation or localization-link identities.
|
|
22
|
+
- Long and nested constructor calls emitted by `neo pull --reset` wrap at a
|
|
23
|
+
stable 88-column default with one named argument per indented line.
|
|
24
|
+
|
|
3
25
|
## [0.21.1] - 2026-08-03
|
|
4
26
|
|
|
5
27
|
### Fixed
|
package/dist/neo.mjs
CHANGED
|
@@ -842,7 +842,7 @@ function vectorTypes() {
|
|
|
842
842
|
members: structuredLeafFieldProperties(name)
|
|
843
843
|
}));
|
|
844
844
|
}
|
|
845
|
-
var NEOSCRIPT_KEYWORDS, NEOSCRIPT_INFERRED_LOCAL_KEYWORD, NEOSCRIPT_CONSTRUCTOR_KEYWORD, NEOSCRIPT_PRIMITIVE_TYPES, NEOSCRIPT_BUILTIN_TYPES, NEOSCRIPT_OPERATORS, NEOSCRIPT_STATEMENT_SNIPPETS, STRING_TYPE, INT_TYPE, FLOAT_TYPE, BOOL_TYPE, IMAGE_REF_TYPE, FLOAT_OPTIONAL_TYPE, NEOSCRIPT_STRUCTURED_LEAF_FIELDS, NEOSCRIPT_IMAGE_REGISTRY_TYPE, NEOSCRIPT_AUDIO_CLIP_REGISTRY_TYPE, NEOSCRIPT_PENDING_SYMBOL_ID_PREFIX, REGISTRY_ENTRY_TYPES, NEOSCRIPT_GLOBALS, NEOSCRIPT_BUILTIN_TYPE_SYMBOLS;
|
|
845
|
+
var NEOSCRIPT_KEYWORDS, NEOSCRIPT_INFERRED_LOCAL_KEYWORD, NEOSCRIPT_CONSTRUCTOR_KEYWORD, NEOSCRIPT_PRIMITIVE_TYPES, NEOSCRIPT_BUILTIN_TYPES, NEOSCRIPT_OPERATORS, NEOSCRIPT_STATEMENT_SNIPPETS, STRING_TYPE, INT_TYPE, FLOAT_TYPE, BOOL_TYPE, IMAGE_REF_TYPE, SPRITE_INFO_TYPE, FLOAT_OPTIONAL_TYPE, NEOSCRIPT_STRUCTURED_LEAF_FIELDS, NEOSCRIPT_IMAGE_REGISTRY_TYPE, NEOSCRIPT_AUDIO_CLIP_REGISTRY_TYPE, NEOSCRIPT_PENDING_SYMBOL_ID_PREFIX, REGISTRY_ENTRY_TYPES, NEOSCRIPT_GLOBALS, NEOSCRIPT_SPRITE_INFO_EMPTY_MEMBER_ID, NEOSCRIPT_SPRITE_INFO_EMPTY_VALUE, NEOSCRIPT_BUILTIN_TYPE_SYMBOLS;
|
|
846
846
|
var init_language_spec = __esm({
|
|
847
847
|
"../packages/neoscript-language/src/language-spec.ts"() {
|
|
848
848
|
"use strict";
|
|
@@ -1006,6 +1006,10 @@ var init_language_spec = __esm({
|
|
|
1006
1006
|
kind: "primitive",
|
|
1007
1007
|
name: "ImageRef"
|
|
1008
1008
|
};
|
|
1009
|
+
SPRITE_INFO_TYPE = {
|
|
1010
|
+
kind: "primitive",
|
|
1011
|
+
name: "SpriteInfo"
|
|
1012
|
+
};
|
|
1009
1013
|
FLOAT_OPTIONAL_TYPE = {
|
|
1010
1014
|
kind: "primitive",
|
|
1011
1015
|
name: "float",
|
|
@@ -1148,12 +1152,26 @@ var init_language_spec = __esm({
|
|
|
1148
1152
|
"Returns whether a dialogue pointer has been visited."
|
|
1149
1153
|
)
|
|
1150
1154
|
];
|
|
1155
|
+
NEOSCRIPT_SPRITE_INFO_EMPTY_MEMBER_ID = "builtin:SpriteInfo:property:Empty";
|
|
1156
|
+
NEOSCRIPT_SPRITE_INFO_EMPTY_VALUE = Object.freeze({
|
|
1157
|
+
fileId: "",
|
|
1158
|
+
sliceIndex: 0
|
|
1159
|
+
});
|
|
1151
1160
|
NEOSCRIPT_BUILTIN_TYPE_SYMBOLS = [
|
|
1152
1161
|
{
|
|
1153
1162
|
id: "builtin:SpriteInfo",
|
|
1154
1163
|
name: "SpriteInfo",
|
|
1155
1164
|
kind: "builtin",
|
|
1156
1165
|
members: [
|
|
1166
|
+
{
|
|
1167
|
+
...property(
|
|
1168
|
+
"SpriteInfo",
|
|
1169
|
+
"Empty",
|
|
1170
|
+
SPRITE_INFO_TYPE,
|
|
1171
|
+
"An authored empty sprite at slice zero."
|
|
1172
|
+
),
|
|
1173
|
+
static: true
|
|
1174
|
+
},
|
|
1157
1175
|
// `FileId` and `SliceIndex` come from the field table above — they are
|
|
1158
1176
|
// the writable, addressable fields, not derived properties (D11).
|
|
1159
1177
|
...structuredLeafFieldProperties("SpriteInfo"),
|
|
@@ -9739,6 +9757,12 @@ var init_strict_resolver = __esm({
|
|
|
9739
9757
|
}
|
|
9740
9758
|
resolveMemberNatural(receiverAst, name, scope, pos, optional) {
|
|
9741
9759
|
if (receiverAst.kind === "ident" && !scope.lookup(receiverAst.name)) {
|
|
9760
|
+
if (receiverAst.name === "SpriteInfo" && name === "Empty") {
|
|
9761
|
+
return literal(
|
|
9762
|
+
{ kind: "primitive", name: "SpriteInfo" },
|
|
9763
|
+
{ ...NEOSCRIPT_SPRITE_INFO_EMPTY_VALUE }
|
|
9764
|
+
);
|
|
9765
|
+
}
|
|
9742
9766
|
const staticType = this.project.typeByName.get(receiverAst.name);
|
|
9743
9767
|
if (staticType && staticType.kind !== "enum") {
|
|
9744
9768
|
if (optional) {
|
|
@@ -9769,6 +9793,11 @@ var init_strict_resolver = __esm({
|
|
|
9769
9793
|
pos
|
|
9770
9794
|
);
|
|
9771
9795
|
}
|
|
9796
|
+
if (member.id === NEOSCRIPT_SPRITE_INFO_EMPTY_MEMBER_ID) {
|
|
9797
|
+
return literal(member.type, {
|
|
9798
|
+
...NEOSCRIPT_SPRITE_INFO_EMPTY_VALUE
|
|
9799
|
+
});
|
|
9800
|
+
}
|
|
9772
9801
|
if (member.computed === true) {
|
|
9773
9802
|
return {
|
|
9774
9803
|
pointer: {
|
|
@@ -38004,10 +38033,10 @@ function isSpriteValue(value) {
|
|
|
38004
38033
|
if (!Number.isInteger(sliceIndex)) return false;
|
|
38005
38034
|
return sliceIndex >= 0;
|
|
38006
38035
|
}
|
|
38007
|
-
function
|
|
38036
|
+
function emptySpriteValue() {
|
|
38008
38037
|
return { fileId: "", sliceIndex: 0 };
|
|
38009
38038
|
}
|
|
38010
|
-
function
|
|
38039
|
+
function isEmptySpriteValue(value) {
|
|
38011
38040
|
if (!value || typeof value !== "object") return false;
|
|
38012
38041
|
return getField(value, "fileId") === "" && getField(value, "sliceIndex") === 0;
|
|
38013
38042
|
}
|
|
@@ -38910,6 +38939,7 @@ var init_world_system_classes_generated = __esm({
|
|
|
38910
38939
|
{
|
|
38911
38940
|
memberId: "system_cbd6db9a-f473-44b5-b913-7cdc06452f35",
|
|
38912
38941
|
memberKind: "sprite",
|
|
38942
|
+
defaultValue: { fileId: "", sliceIndex: 0 },
|
|
38913
38943
|
required: true,
|
|
38914
38944
|
schemaKey: "Sprite"
|
|
38915
38945
|
},
|
|
@@ -39032,6 +39062,7 @@ var init_world_system_classes_generated = __esm({
|
|
|
39032
39062
|
{
|
|
39033
39063
|
memberId: "system_e9288ba9-f5a2-4485-8443-6afb155b31e0",
|
|
39034
39064
|
memberKind: "sprite",
|
|
39065
|
+
defaultValue: { fileId: "", sliceIndex: 0 },
|
|
39035
39066
|
required: true,
|
|
39036
39067
|
schemaKey: "Sprite"
|
|
39037
39068
|
},
|
|
@@ -39516,6 +39547,12 @@ var init_world_system_classes_generated = __esm({
|
|
|
39516
39547
|
docsText: "One value at a frame index inside a segment. It holds until the next row\nyou author, or until the segment's Duration runs out.",
|
|
39517
39548
|
extendsWorldKind: "animationFrameBase",
|
|
39518
39549
|
isAbstract: false,
|
|
39550
|
+
constructorProjections: [
|
|
39551
|
+
{
|
|
39552
|
+
memberId: "system_b71d1f73-da72-49de-ab9a-911cc9bffa43",
|
|
39553
|
+
parameterName: "value"
|
|
39554
|
+
}
|
|
39555
|
+
],
|
|
39519
39556
|
genericParams: [
|
|
39520
39557
|
{ id: "system_887b11d3-e56a-47ff-8d01-e2fcefb846a1", name: "T" }
|
|
39521
39558
|
],
|
|
@@ -42586,7 +42623,7 @@ function stampGenericBindings(value, member, args) {
|
|
|
42586
42623
|
}
|
|
42587
42624
|
function shouldSkipRequiredChildDefault(member) {
|
|
42588
42625
|
if (member.defaultValue !== void 0) return false;
|
|
42589
|
-
return
|
|
42626
|
+
return isMemberAudioBase(member);
|
|
42590
42627
|
}
|
|
42591
42628
|
function shouldMaterializeChildDefault(member) {
|
|
42592
42629
|
if (isMemberClassBase(member) && member.partial === true) return false;
|
|
@@ -42658,7 +42695,7 @@ function primitiveFallbackValue(document, member) {
|
|
|
42658
42695
|
if (isMemberLookupBase(member)) return { value: [] };
|
|
42659
42696
|
if (isMemberDialogueLookupBase(member)) return { value: [] };
|
|
42660
42697
|
if (isMemberSpriteBase(member)) {
|
|
42661
|
-
return { value:
|
|
42698
|
+
return { value: emptySpriteValue() };
|
|
42662
42699
|
}
|
|
42663
42700
|
if (isMemberAudioBase(member)) {
|
|
42664
42701
|
return { value: pendingAudioValue() };
|
|
@@ -42682,7 +42719,7 @@ function primitiveFallbackValue(document, member) {
|
|
|
42682
42719
|
function isPendingFileMemberValue(member, body) {
|
|
42683
42720
|
const value = body.value;
|
|
42684
42721
|
if (isMemberSpriteBase(member)) {
|
|
42685
|
-
return
|
|
42722
|
+
return isEmptySpriteValue(value);
|
|
42686
42723
|
}
|
|
42687
42724
|
if (isMemberAudioBase(member)) {
|
|
42688
42725
|
return isPendingAudioValue(value);
|
|
@@ -42768,11 +42805,18 @@ function validateDecimalMemberValue(member, body) {
|
|
|
42768
42805
|
}
|
|
42769
42806
|
function validateSpriteMemberValue(document, member, body) {
|
|
42770
42807
|
const spriteValue = body.value;
|
|
42808
|
+
if (spriteValue === null) {
|
|
42809
|
+
if (!member.required) return;
|
|
42810
|
+
throw new Error(
|
|
42811
|
+
`Sprite member "${member.name}" is required and cannot be null.`
|
|
42812
|
+
);
|
|
42813
|
+
}
|
|
42771
42814
|
if (!isSpriteValue(spriteValue)) {
|
|
42772
42815
|
throw new Error(
|
|
42773
42816
|
"Sprite value must be { fileId: string, sliceIndex: integer >= 0 }."
|
|
42774
42817
|
);
|
|
42775
42818
|
}
|
|
42819
|
+
if (isEmptySpriteValue(spriteValue)) return;
|
|
42776
42820
|
validateSpriteFileRegistration(document, member, spriteValue.fileId);
|
|
42777
42821
|
}
|
|
42778
42822
|
function validateSpriteFileRegistration(document, member, fileId) {
|
|
@@ -44993,6 +45037,9 @@ function lowerExpressionValue(context, expression, declaredExpected, ownerClass,
|
|
|
44993
45037
|
}
|
|
44994
45038
|
switch (expression.kind) {
|
|
44995
45039
|
case "litNull":
|
|
45040
|
+
if (!expected.nullable) {
|
|
45041
|
+
throw new Error(`Required value ${path} cannot be null.`);
|
|
45042
|
+
}
|
|
44996
45043
|
return null;
|
|
44997
45044
|
case "litBool":
|
|
44998
45045
|
case "litString":
|
|
@@ -45212,6 +45259,9 @@ function lowerExpressionValue(context, expression, declaredExpected, ownerClass,
|
|
|
45212
45259
|
);
|
|
45213
45260
|
}
|
|
45214
45261
|
case "member": {
|
|
45262
|
+
if (expected.name === "SpriteInfo" && expression.name === "Empty" && expression.receiver.kind === "ident" && expression.receiver.name === "SpriteInfo") {
|
|
45263
|
+
return { fileId: "", sliceIndex: 0 };
|
|
45264
|
+
}
|
|
45215
45265
|
const fileId = projectFileIdForPath(context, expression);
|
|
45216
45266
|
if (fileId !== null) return { fileId };
|
|
45217
45267
|
if (expression.name === "Slice" || expression.receiver.kind === "call") {
|
|
@@ -75392,7 +75442,6 @@ function buildValueEmitContext(records2, manifest) {
|
|
|
75392
75442
|
)
|
|
75393
75443
|
),
|
|
75394
75444
|
fileSymbols: projectFileSymbols(records2),
|
|
75395
|
-
referencedValueIds: externallyReferencedValueIds(records2),
|
|
75396
75445
|
localizedTextIds: /* @__PURE__ */ new Set(),
|
|
75397
75446
|
constructionReplays: /* @__PURE__ */ new Map()
|
|
75398
75447
|
};
|
|
@@ -77144,7 +77193,12 @@ function lowerValueRow(context, member, sourceExpression, expectedValueId, sourc
|
|
|
77144
77193
|
}
|
|
77145
77194
|
function lowerValueBody(context, member, expression, base, source, environment, authoredSlice) {
|
|
77146
77195
|
const next = valueFileFields(base);
|
|
77147
|
-
if (expression.kind === "litNull")
|
|
77196
|
+
if (expression.kind === "litNull") {
|
|
77197
|
+
if (member.required) {
|
|
77198
|
+
throw new Error(`Required member ${member.name} cannot store null.`);
|
|
77199
|
+
}
|
|
77200
|
+
return { ...next, value: null };
|
|
77201
|
+
}
|
|
77148
77202
|
switch (member.kind) {
|
|
77149
77203
|
case "null":
|
|
77150
77204
|
return { ...next, value: null };
|
|
@@ -78128,6 +78182,9 @@ function expressionAnchorPos(expression) {
|
|
|
78128
78182
|
}
|
|
78129
78183
|
function lowerFileValue(context, member, expression) {
|
|
78130
78184
|
if (member.kind === "sprite") {
|
|
78185
|
+
if (isSpriteInfoEmptyExpression(expression)) {
|
|
78186
|
+
return { fileId: "", sliceIndex: 0 };
|
|
78187
|
+
}
|
|
78131
78188
|
if (expression.kind !== "call" || expression.callee.kind !== "member" || expression.callee.name !== "Slice") {
|
|
78132
78189
|
throw new Error(
|
|
78133
78190
|
`Sprite member ${member.name} requires Image.Slice(index).`
|
|
@@ -79115,7 +79172,8 @@ function emitValueBody(context, member, value, visited, targetTyped, environment
|
|
|
79115
79172
|
context,
|
|
79116
79173
|
kind,
|
|
79117
79174
|
`Audio member ${JSON.stringify(String(member.name ?? member.id))}`,
|
|
79118
|
-
body
|
|
79175
|
+
body,
|
|
79176
|
+
member.required === true
|
|
79119
79177
|
);
|
|
79120
79178
|
}
|
|
79121
79179
|
if (kind === 5)
|
|
@@ -79235,7 +79293,10 @@ function classValue(context, member, value, visited, targetTyped, outerEnvironme
|
|
|
79235
79293
|
`${key} = ${emitValue(context, emittedChildMember, childId, {
|
|
79236
79294
|
environment,
|
|
79237
79295
|
definitionSite: !context.symbolsByValueId.has(childId),
|
|
79238
|
-
|
|
79296
|
+
// A class slot recovers this row from the owning value and schema key.
|
|
79297
|
+
// P61 creation metadata and localization back-pointers must not turn
|
|
79298
|
+
// that structural child into an explicitly identified source value.
|
|
79299
|
+
writeIdentity: false,
|
|
79239
79300
|
visited
|
|
79240
79301
|
})}`
|
|
79241
79302
|
);
|
|
@@ -79245,7 +79306,7 @@ function classValue(context, member, value, visited, targetTyped, outerEnvironme
|
|
|
79245
79306
|
${fields.map((field) => indentNeoSourceNonEmptyLines(field, 2)).join(",\n")}
|
|
79246
79307
|
}`;
|
|
79247
79308
|
}
|
|
79248
|
-
const constructor2 = storedConstruction !== null ? storedConstruction : projection.arguments.length > 0 ? `new ${name}
|
|
79309
|
+
const constructor2 = storedConstruction !== null ? storedConstruction : projection.arguments.length > 0 ? constructorCallSource(`new ${name}`, projection.arguments) : targetTyped ? "new()" : `new ${name}()`;
|
|
79249
79310
|
return fields.length === 0 ? constructor2 : `${storedConstruction !== null || projection.arguments.length > 0 ? constructor2 : targetTyped ? "new()" : `new ${name}`} {
|
|
79250
79311
|
${fields.map((field) => indentNeoSourceNonEmptyLines(field, 2)).join(",\n")}
|
|
79251
79312
|
}`;
|
|
@@ -79322,7 +79383,16 @@ function storedConstructorCallSource(context, schemaClass2, value, className, en
|
|
|
79322
79383
|
cloneAggregateArguments
|
|
79323
79384
|
)}`;
|
|
79324
79385
|
});
|
|
79325
|
-
return argumentsValue.length === 0 && targetTyped ? "new()" : `new ${className}
|
|
79386
|
+
return argumentsValue.length === 0 && targetTyped ? "new()" : constructorCallSource(`new ${className}`, argumentsValue);
|
|
79387
|
+
}
|
|
79388
|
+
function constructorCallSource(callee, argumentsValue) {
|
|
79389
|
+
const inline = `${callee}(${argumentsValue.join(", ")})`;
|
|
79390
|
+
if (!argumentsValue.some((argument2) => argument2.includes("\n")) && inline.length <= CANONICAL_CONSTRUCTOR_INLINE_WIDTH) {
|
|
79391
|
+
return inline;
|
|
79392
|
+
}
|
|
79393
|
+
return `${callee}(
|
|
79394
|
+
${argumentsValue.map((argument2) => `${indentNeoSourceNonEmptyLines(argument2, 2)},`).join("\n")}
|
|
79395
|
+
)`;
|
|
79326
79396
|
}
|
|
79327
79397
|
function storedValueConstructor(context, schemaClass2, constructorArgs) {
|
|
79328
79398
|
const requiredId = schemaClass2.requiredConstructorId;
|
|
@@ -79353,7 +79423,12 @@ function storedValueConstructor(context, schemaClass2, constructorArgs) {
|
|
|
79353
79423
|
return selected2;
|
|
79354
79424
|
}
|
|
79355
79425
|
function storedConstructorArgumentSource(context, type, value, environment, visited, cloneAggregateArguments = false) {
|
|
79356
|
-
if (value === null)
|
|
79426
|
+
if (value === null) {
|
|
79427
|
+
if (!type.nullable) {
|
|
79428
|
+
throw new Error("Required constructor argument stores null.");
|
|
79429
|
+
}
|
|
79430
|
+
return "null";
|
|
79431
|
+
}
|
|
79357
79432
|
switch (type.kind) {
|
|
79358
79433
|
case "null":
|
|
79359
79434
|
return "null";
|
|
@@ -79385,7 +79460,8 @@ function storedConstructorArgumentSource(context, type, value, environment, visi
|
|
|
79385
79460
|
{
|
|
79386
79461
|
id: "__constructor_arg__",
|
|
79387
79462
|
name: "argument",
|
|
79388
|
-
kind: 11 /* Sprite
|
|
79463
|
+
kind: 11 /* Sprite */,
|
|
79464
|
+
required: !type.nullable
|
|
79389
79465
|
},
|
|
79390
79466
|
value
|
|
79391
79467
|
);
|
|
@@ -79394,7 +79470,8 @@ function storedConstructorArgumentSource(context, type, value, environment, visi
|
|
|
79394
79470
|
context,
|
|
79395
79471
|
12 /* Audio */,
|
|
79396
79472
|
"constructor argument",
|
|
79397
|
-
value
|
|
79473
|
+
value,
|
|
79474
|
+
!type.nullable
|
|
79398
79475
|
);
|
|
79399
79476
|
case "enum":
|
|
79400
79477
|
return enumValue(
|
|
@@ -79419,7 +79496,14 @@ function storedConstructorArgumentSource(context, type, value, environment, visi
|
|
|
79419
79496
|
if (cloneAggregateArguments) {
|
|
79420
79497
|
return storedAggregateCloneSource(context, type, value, environment);
|
|
79421
79498
|
}
|
|
79422
|
-
return storedTypedRowSource(
|
|
79499
|
+
return storedTypedRowSource(
|
|
79500
|
+
context,
|
|
79501
|
+
type,
|
|
79502
|
+
value,
|
|
79503
|
+
environment,
|
|
79504
|
+
visited,
|
|
79505
|
+
false
|
|
79506
|
+
);
|
|
79423
79507
|
}
|
|
79424
79508
|
case "interface":
|
|
79425
79509
|
case "generic":
|
|
@@ -79433,7 +79517,14 @@ function storedConstructorArgumentSource(context, type, value, environment, visi
|
|
|
79433
79517
|
if (cloneAggregateArguments) {
|
|
79434
79518
|
return storedAggregateCloneSource(context, type, value, environment);
|
|
79435
79519
|
}
|
|
79436
|
-
return storedTypedRowSource(
|
|
79520
|
+
return storedTypedRowSource(
|
|
79521
|
+
context,
|
|
79522
|
+
type,
|
|
79523
|
+
value,
|
|
79524
|
+
environment,
|
|
79525
|
+
visited,
|
|
79526
|
+
false
|
|
79527
|
+
);
|
|
79437
79528
|
case "lookup":
|
|
79438
79529
|
return referenceValue(
|
|
79439
79530
|
context,
|
|
@@ -79552,7 +79643,7 @@ function storedSchemaTypeName(context, type, environment, valueId) {
|
|
|
79552
79643
|
return "null";
|
|
79553
79644
|
}
|
|
79554
79645
|
}
|
|
79555
|
-
function storedTypedRowSource(context, type, valueId, environment, visited) {
|
|
79646
|
+
function storedTypedRowSource(context, type, valueId, environment, visited, writeIdentity) {
|
|
79556
79647
|
const symbol = context.symbolsByValueId.get(valueId);
|
|
79557
79648
|
if (symbol !== void 0) return symbol;
|
|
79558
79649
|
const row = context.values.get(valueId);
|
|
@@ -79575,32 +79666,34 @@ function storedTypedRowSource(context, type, valueId, environment, visited) {
|
|
|
79575
79666
|
`Stored ${type.kind} constructor argument ${valueId} has no concrete class.`
|
|
79576
79667
|
);
|
|
79577
79668
|
}
|
|
79578
|
-
return
|
|
79579
|
-
|
|
79580
|
-
|
|
79581
|
-
|
|
79582
|
-
|
|
79583
|
-
|
|
79584
|
-
|
|
79585
|
-
|
|
79586
|
-
|
|
79587
|
-
|
|
79588
|
-
|
|
79589
|
-
|
|
79590
|
-
|
|
79591
|
-
|
|
79592
|
-
|
|
79593
|
-
|
|
79669
|
+
return storedRowIdentitySource(
|
|
79670
|
+
valueId,
|
|
79671
|
+
writeIdentity,
|
|
79672
|
+
classValue(
|
|
79673
|
+
context,
|
|
79674
|
+
{
|
|
79675
|
+
id: `__constructor_arg__:${valueId}`,
|
|
79676
|
+
name: "argument",
|
|
79677
|
+
kind: 7 /* Class */,
|
|
79678
|
+
classId,
|
|
79679
|
+
classArguments: {},
|
|
79680
|
+
partial: false
|
|
79681
|
+
},
|
|
79682
|
+
row,
|
|
79683
|
+
visited,
|
|
79684
|
+
false,
|
|
79685
|
+
environment
|
|
79686
|
+
)
|
|
79687
|
+
);
|
|
79594
79688
|
}
|
|
79595
79689
|
if (type.kind === "list") {
|
|
79596
|
-
if (row.value === null)
|
|
79690
|
+
if (row.value === null) {
|
|
79691
|
+
return storedRowIdentitySource(valueId, writeIdentity, "null");
|
|
79692
|
+
}
|
|
79597
79693
|
const ids = Array.isArray(row.value) ? row.value.filter(
|
|
79598
79694
|
(entry) => typeof entry === "string"
|
|
79599
79695
|
) : [...context.values].filter(([, candidate]) => candidate.containerId === valueId).map(([id2]) => id2).sort(compareCodePoints);
|
|
79600
|
-
|
|
79601
|
-
[]`;
|
|
79602
|
-
return `@id(${quote4(valueId)})
|
|
79603
|
-
[
|
|
79696
|
+
const expression = ids.length === 0 ? "[]" : `[
|
|
79604
79697
|
${ids.map(
|
|
79605
79698
|
(id2) => indentNeoSourceNonEmptyLines(
|
|
79606
79699
|
storedTypedRowSource(
|
|
@@ -79608,22 +79701,26 @@ ${ids.map(
|
|
|
79608
79701
|
type.entryType,
|
|
79609
79702
|
id2,
|
|
79610
79703
|
environment,
|
|
79611
|
-
visited
|
|
79704
|
+
visited,
|
|
79705
|
+
true
|
|
79612
79706
|
),
|
|
79613
79707
|
2
|
|
79614
79708
|
)
|
|
79615
79709
|
).join(",\n\n")}
|
|
79616
79710
|
]`;
|
|
79711
|
+
return storedRowIdentitySource(valueId, writeIdentity, expression);
|
|
79617
79712
|
}
|
|
79618
79713
|
if (type.kind === "dictionary") {
|
|
79619
|
-
if (row.value === null)
|
|
79620
|
-
|
|
79714
|
+
if (row.value === null) {
|
|
79715
|
+
return storedRowIdentitySource(valueId, writeIdentity, "null");
|
|
79716
|
+
}
|
|
79717
|
+
if (!isObjectRecord2(row.value)) {
|
|
79718
|
+
return storedRowIdentitySource(valueId, writeIdentity, "{}");
|
|
79719
|
+
}
|
|
79621
79720
|
const entries = Object.entries(row.value).sort(
|
|
79622
79721
|
([left], [right]) => compareCodePoints(left, right)
|
|
79623
79722
|
);
|
|
79624
|
-
|
|
79625
|
-
{}` : `@id(${quote4(valueId)})
|
|
79626
|
-
{
|
|
79723
|
+
const expression = entries.length === 0 ? "{}" : `{
|
|
79627
79724
|
${entries.flatMap(
|
|
79628
79725
|
([key, id2]) => typeof id2 === "string" ? [
|
|
79629
79726
|
indentNeoSourceNonEmptyLines(
|
|
@@ -79632,53 +79729,71 @@ ${entries.flatMap(
|
|
|
79632
79729
|
type.entryType,
|
|
79633
79730
|
id2,
|
|
79634
79731
|
environment,
|
|
79635
|
-
visited
|
|
79732
|
+
visited,
|
|
79733
|
+
false
|
|
79636
79734
|
)}`,
|
|
79637
79735
|
2
|
|
79638
79736
|
)
|
|
79639
79737
|
] : []
|
|
79640
79738
|
).join(",\n")}
|
|
79641
79739
|
}`;
|
|
79740
|
+
return storedRowIdentitySource(valueId, writeIdentity, expression);
|
|
79642
79741
|
}
|
|
79643
79742
|
if (type.kind === "lookup") {
|
|
79644
|
-
return
|
|
79645
|
-
|
|
79646
|
-
|
|
79647
|
-
|
|
79648
|
-
|
|
79649
|
-
|
|
79650
|
-
|
|
79651
|
-
|
|
79652
|
-
|
|
79653
|
-
|
|
79654
|
-
|
|
79655
|
-
|
|
79743
|
+
return storedRowIdentitySource(
|
|
79744
|
+
valueId,
|
|
79745
|
+
writeIdentity,
|
|
79746
|
+
referenceValue(
|
|
79747
|
+
context,
|
|
79748
|
+
{
|
|
79749
|
+
id: `__constructor_arg__:${valueId}`,
|
|
79750
|
+
name: "argument",
|
|
79751
|
+
kind: 9 /* Lookup */,
|
|
79752
|
+
collectionMemberId: type.collectionMemberId,
|
|
79753
|
+
collectionValueId: type.collectionValueId,
|
|
79754
|
+
multiselect: false
|
|
79755
|
+
},
|
|
79756
|
+
row.value,
|
|
79757
|
+
false
|
|
79758
|
+
)
|
|
79656
79759
|
);
|
|
79657
79760
|
}
|
|
79658
79761
|
if (type.kind === "dialogueLookup") {
|
|
79659
|
-
return
|
|
79660
|
-
|
|
79661
|
-
|
|
79662
|
-
|
|
79663
|
-
|
|
79664
|
-
|
|
79665
|
-
|
|
79666
|
-
|
|
79667
|
-
|
|
79668
|
-
|
|
79762
|
+
return storedRowIdentitySource(
|
|
79763
|
+
valueId,
|
|
79764
|
+
writeIdentity,
|
|
79765
|
+
referenceValue(
|
|
79766
|
+
context,
|
|
79767
|
+
{
|
|
79768
|
+
id: `__constructor_arg__:${valueId}`,
|
|
79769
|
+
name: "argument",
|
|
79770
|
+
kind: 18 /* DialogueLookup */,
|
|
79771
|
+
multiselect: false
|
|
79772
|
+
},
|
|
79773
|
+
row.value,
|
|
79774
|
+
true
|
|
79775
|
+
)
|
|
79669
79776
|
);
|
|
79670
79777
|
}
|
|
79671
|
-
return
|
|
79672
|
-
|
|
79673
|
-
|
|
79674
|
-
|
|
79675
|
-
|
|
79676
|
-
|
|
79778
|
+
return storedRowIdentitySource(
|
|
79779
|
+
valueId,
|
|
79780
|
+
writeIdentity,
|
|
79781
|
+
storedConstructorArgumentSource(
|
|
79782
|
+
context,
|
|
79783
|
+
type,
|
|
79784
|
+
row.value,
|
|
79785
|
+
environment,
|
|
79786
|
+
visited
|
|
79787
|
+
)
|
|
79677
79788
|
);
|
|
79678
79789
|
} finally {
|
|
79679
79790
|
visited.delete(valueId);
|
|
79680
79791
|
}
|
|
79681
79792
|
}
|
|
79793
|
+
function storedRowIdentitySource(valueId, writeIdentity, expression) {
|
|
79794
|
+
return `${writeIdentity ? `@id(${quote4(valueId)})
|
|
79795
|
+
` : ""}${expression}`;
|
|
79796
|
+
}
|
|
79682
79797
|
function storedVectorSource(value, name, keys) {
|
|
79683
79798
|
if (!isObjectRecord2(value)) {
|
|
79684
79799
|
throw new Error(`Stored ${name} constructor argument is not an object.`);
|
|
@@ -80001,7 +80116,9 @@ ${entries.flatMap(
|
|
|
80001
80116
|
`${quote4(key)}: ${emitValue(context, entryMember, id2, {
|
|
80002
80117
|
environment,
|
|
80003
80118
|
definitionSite: !context.symbolsByValueId.has(id2),
|
|
80004
|
-
|
|
80119
|
+
// Dictionary keys, like class schema keys, recover entry
|
|
80120
|
+
// identity from the owning row. Only list entries need an id.
|
|
80121
|
+
writeIdentity: false,
|
|
80005
80122
|
visited
|
|
80006
80123
|
})}`,
|
|
80007
80124
|
2
|
|
@@ -80129,8 +80246,13 @@ function delegateValue(context, body) {
|
|
|
80129
80246
|
}
|
|
80130
80247
|
return target.name;
|
|
80131
80248
|
}
|
|
80132
|
-
function fileValue(context, kind, label, body) {
|
|
80133
|
-
if (body === null || body === void 0)
|
|
80249
|
+
function fileValue(context, kind, label, body, required2) {
|
|
80250
|
+
if (body === null || body === void 0) {
|
|
80251
|
+
if (required2) {
|
|
80252
|
+
throw new Error(`${label} is required and cannot store null.`);
|
|
80253
|
+
}
|
|
80254
|
+
return "null";
|
|
80255
|
+
}
|
|
80134
80256
|
if (!isObjectRecord2(body)) {
|
|
80135
80257
|
throw new Error(
|
|
80136
80258
|
`${label} stores ${JSON.stringify(body)}, which is not a file value record.`
|
|
@@ -80142,12 +80264,18 @@ function fileValue(context, kind, label, body) {
|
|
|
80142
80264
|
);
|
|
80143
80265
|
}
|
|
80144
80266
|
if (body.fileId.length === 0) {
|
|
80145
|
-
|
|
80267
|
+
if (kind === 11 && numberOr2(body.sliceIndex, 0) === 0) {
|
|
80268
|
+
return "SpriteInfo.Empty";
|
|
80269
|
+
}
|
|
80270
|
+
throw new Error(`${label} stores an invalid empty file value.`);
|
|
80146
80271
|
}
|
|
80147
80272
|
const base = fileRegistrySource(context, kind, body.fileId);
|
|
80148
80273
|
if (kind !== 11) return base;
|
|
80149
80274
|
return `${base}.Slice(${numberOr2(body.sliceIndex, 0)})`;
|
|
80150
80275
|
}
|
|
80276
|
+
function isSpriteInfoEmptyExpression(expression) {
|
|
80277
|
+
return expression.kind === "member" && expression.name === "Empty" && expression.receiver.kind === "ident" && expression.receiver.name === "SpriteInfo";
|
|
80278
|
+
}
|
|
80151
80279
|
function fileRegistrySource(context, kind, fileId) {
|
|
80152
80280
|
const symbol = context.fileSymbols.get(fileId);
|
|
80153
80281
|
if (symbol !== void 0) {
|
|
@@ -80172,7 +80300,9 @@ function structuredLeafSource(context, kind, member, body) {
|
|
|
80172
80300
|
${assignments.map((entry) => indentNeoSourceNonEmptyLines(entry, 2)).join(",\n")}
|
|
80173
80301
|
}`;
|
|
80174
80302
|
}
|
|
80175
|
-
if (kind === 11 /* Sprite */)
|
|
80303
|
+
if (kind === 11 /* Sprite */) {
|
|
80304
|
+
return fileValue(context, 11, label, body, member.required === true);
|
|
80305
|
+
}
|
|
80176
80306
|
if (body === null) return "null";
|
|
80177
80307
|
if (!isObjectRecord2(body)) return "new()";
|
|
80178
80308
|
return `new(${structuredLeafFieldKeys(kind).map((key) => scalar(body[key])).join(", ")})`;
|
|
@@ -80215,33 +80345,6 @@ function projectFileSymbols(records2) {
|
|
|
80215
80345
|
});
|
|
80216
80346
|
return assignDeterministicFileSymbols(files);
|
|
80217
80347
|
}
|
|
80218
|
-
function externallyReferencedValueIds(records2) {
|
|
80219
|
-
const counts = /* @__PURE__ */ new Map();
|
|
80220
|
-
const visit = (value) => {
|
|
80221
|
-
if (typeof value === "string") {
|
|
80222
|
-
if (records2.has(`value:${value}`))
|
|
80223
|
-
counts.set(value, (counts.get(value) ?? 0) + 1);
|
|
80224
|
-
return;
|
|
80225
|
-
}
|
|
80226
|
-
if (Array.isArray(value)) {
|
|
80227
|
-
value.forEach((entry) => visit(entry));
|
|
80228
|
-
return;
|
|
80229
|
-
}
|
|
80230
|
-
if (isObjectRecord2(value)) {
|
|
80231
|
-
for (const [childKey, child] of Object.entries(value)) {
|
|
80232
|
-
if (childKey === "id") continue;
|
|
80233
|
-
if (childKey === "sourceValueId") continue;
|
|
80234
|
-
visit(child);
|
|
80235
|
-
}
|
|
80236
|
-
}
|
|
80237
|
-
};
|
|
80238
|
-
for (const record3 of records2.values()) {
|
|
80239
|
-
if (!record3.deleted) visit(record3.data);
|
|
80240
|
-
}
|
|
80241
|
-
return new Set(
|
|
80242
|
-
[...counts].filter(([, count]) => count > 1).map(([id2]) => id2)
|
|
80243
|
-
);
|
|
80244
|
-
}
|
|
80245
80348
|
function projectMainLocale(records2) {
|
|
80246
80349
|
const config = [...records2.values()].find(
|
|
80247
80350
|
(record3) => !record3.deleted && record3.recordKind === "localization-config"
|
|
@@ -80330,7 +80433,7 @@ function memberDefaultBody(member) {
|
|
|
80330
80433
|
if (!("value" in defaultValue)) return null;
|
|
80331
80434
|
return defaultValue.value;
|
|
80332
80435
|
}
|
|
80333
|
-
var INFERRED_GENERIC_CLASS_PREFIX, MEMBER_KIND_DICTIONARY, MEMBER_KIND_LIST, MEMBER_KIND_CLASS;
|
|
80436
|
+
var INFERRED_GENERIC_CLASS_PREFIX, MEMBER_KIND_DICTIONARY, MEMBER_KIND_LIST, MEMBER_KIND_CLASS, CANONICAL_CONSTRUCTOR_INLINE_WIDTH;
|
|
80334
80437
|
var init_value_sources = __esm({
|
|
80335
80438
|
"src/project-source/value-sources.ts"() {
|
|
80336
80439
|
"use strict";
|
|
@@ -80356,6 +80459,7 @@ var init_value_sources = __esm({
|
|
|
80356
80459
|
MEMBER_KIND_DICTIONARY = 5;
|
|
80357
80460
|
MEMBER_KIND_LIST = 6;
|
|
80358
80461
|
MEMBER_KIND_CLASS = 7;
|
|
80462
|
+
CANONICAL_CONSTRUCTOR_INLINE_WIDTH = 88;
|
|
80359
80463
|
}
|
|
80360
80464
|
});
|
|
80361
80465
|
|
|
@@ -94833,7 +94937,7 @@ async function downloadProjectVersionTransactionResult(args) {
|
|
|
94833
94937
|
cursor = page.continueCursor;
|
|
94834
94938
|
}
|
|
94835
94939
|
}
|
|
94836
|
-
async function
|
|
94940
|
+
async function preparePushStatus(workspace, options) {
|
|
94837
94941
|
const status = computeWorkspaceStatus(workspace);
|
|
94838
94942
|
if (status.conflictedFiles.length > 0) {
|
|
94839
94943
|
throw new Error(
|
|
@@ -94862,22 +94966,7 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
94862
94966
|
changes: status.changes,
|
|
94863
94967
|
binaryChanges: status.binaryChanges ?? []
|
|
94864
94968
|
});
|
|
94865
|
-
if (status.changes.length === 0)
|
|
94866
|
-
if (options.json === true) {
|
|
94867
|
-
console.log(
|
|
94868
|
-
JSON.stringify({
|
|
94869
|
-
type: "push-plan",
|
|
94870
|
-
dryRun: options.dryRun,
|
|
94871
|
-
changeCount: 0,
|
|
94872
|
-
staticValueSeedCount: 0,
|
|
94873
|
-
changes: []
|
|
94874
|
-
})
|
|
94875
|
-
);
|
|
94876
|
-
} else {
|
|
94877
|
-
console.log("Nothing to push \u2014 working copy is clean.");
|
|
94878
|
-
}
|
|
94879
|
-
return;
|
|
94880
|
-
}
|
|
94969
|
+
if (status.changes.length === 0) return status;
|
|
94881
94970
|
const initConversions = status.initConversions ?? [];
|
|
94882
94971
|
if (initConversions.length > 0 && options.json !== true) {
|
|
94883
94972
|
for (const line of describeInitConversions(initConversions)) warn(line);
|
|
@@ -94949,8 +95038,40 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
94949
95038
|
} catch (error) {
|
|
94950
95039
|
reportDryRunFailure(error, options.json === true);
|
|
94951
95040
|
process.exitCode = 1;
|
|
94952
|
-
return;
|
|
95041
|
+
return null;
|
|
95042
|
+
}
|
|
95043
|
+
}
|
|
95044
|
+
return status;
|
|
95045
|
+
}
|
|
95046
|
+
async function runPush(workspace, options, preparationOverride) {
|
|
95047
|
+
const preparation = preparationOverride === void 0 ? process.stdout.isTTY === true && options.json !== true ? spinner("Preparing push\u2026") : null : preparationOverride;
|
|
95048
|
+
let status;
|
|
95049
|
+
try {
|
|
95050
|
+
status = await preparePushStatus(workspace, options);
|
|
95051
|
+
} catch (error) {
|
|
95052
|
+
preparation?.fail("Push preparation failed.");
|
|
95053
|
+
throw error;
|
|
95054
|
+
}
|
|
95055
|
+
if (status === null) {
|
|
95056
|
+
preparation?.fail("Push preparation failed.");
|
|
95057
|
+
return;
|
|
95058
|
+
}
|
|
95059
|
+
preparation?.stop();
|
|
95060
|
+
if (status.changes.length === 0) {
|
|
95061
|
+
if (options.json === true) {
|
|
95062
|
+
console.log(
|
|
95063
|
+
JSON.stringify({
|
|
95064
|
+
type: "push-plan",
|
|
95065
|
+
dryRun: options.dryRun,
|
|
95066
|
+
changeCount: 0,
|
|
95067
|
+
staticValueSeedCount: 0,
|
|
95068
|
+
changes: []
|
|
95069
|
+
})
|
|
95070
|
+
);
|
|
95071
|
+
} else {
|
|
95072
|
+
console.log("Nothing to push \u2014 working copy is clean.");
|
|
94953
95073
|
}
|
|
95074
|
+
return;
|
|
94954
95075
|
}
|
|
94955
95076
|
if (options.json === true) {
|
|
94956
95077
|
console.log(
|
|
@@ -98075,14 +98196,29 @@ async function main() {
|
|
|
98075
98196
|
return;
|
|
98076
98197
|
}
|
|
98077
98198
|
case "push": {
|
|
98078
|
-
const
|
|
98079
|
-
const
|
|
98080
|
-
|
|
98081
|
-
|
|
98082
|
-
|
|
98083
|
-
|
|
98084
|
-
|
|
98085
|
-
|
|
98199
|
+
const json = boolFlag(args, "json");
|
|
98200
|
+
const preparation = process.stdout.isTTY === true && json !== true ? spinner("Preparing push\u2026") : null;
|
|
98201
|
+
let handedOffPreparation = false;
|
|
98202
|
+
try {
|
|
98203
|
+
const workspace = loadWorkspaceForCommand(args);
|
|
98204
|
+
const { runPush: runPush2 } = await Promise.resolve().then(() => (init_push(), push_exports));
|
|
98205
|
+
handedOffPreparation = true;
|
|
98206
|
+
await runPush2(
|
|
98207
|
+
workspace,
|
|
98208
|
+
{
|
|
98209
|
+
dryRun: boolFlag(args, "dry-run"),
|
|
98210
|
+
summary: stringFlag(args, "summary"),
|
|
98211
|
+
acceptBump: boolFlag(args, "accept-bump"),
|
|
98212
|
+
json
|
|
98213
|
+
},
|
|
98214
|
+
preparation
|
|
98215
|
+
);
|
|
98216
|
+
} catch (error) {
|
|
98217
|
+
if (!handedOffPreparation) {
|
|
98218
|
+
preparation?.fail("Push preparation failed.");
|
|
98219
|
+
}
|
|
98220
|
+
throw error;
|
|
98221
|
+
}
|
|
98086
98222
|
return;
|
|
98087
98223
|
}
|
|
98088
98224
|
case "status": {
|
package/package.json
CHANGED
|
@@ -66,12 +66,15 @@ Use complete values in normal member initialization:
|
|
|
66
66
|
|
|
67
67
|
```neo
|
|
68
68
|
Sprite = Images.Hero.Slice(0);
|
|
69
|
+
Placeholder = SpriteInfo.Empty;
|
|
69
70
|
Position = new(0, 0, 0);
|
|
70
71
|
Tint = Color(1, 1, 1, 1);
|
|
71
72
|
```
|
|
72
73
|
|
|
73
74
|
A bare `Images.Hero` yields a file ID only in a file-valued field context.
|
|
74
75
|
Use `.Slice(index)` for a complete `SpriteInfo`.
|
|
76
|
+
Use `SpriteInfo.Empty` for an authored non-null empty sprite. Use `null` only
|
|
77
|
+
when the declared type is nullable `SpriteInfo?`.
|
|
75
78
|
|
|
76
79
|
NeoScript may read or write structured fields when the receiver's effective
|
|
77
80
|
storage permits it:
|
|
@@ -73,7 +73,7 @@ wrappers.
|
|
|
73
73
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
74
74
|
|
|
75
75
|
```html
|
|
76
|
-
<!-- reviewed-through-cli: 0.21.
|
|
76
|
+
<!-- reviewed-through-cli: 0.21.3 -->
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -37,6 +37,10 @@ validation — so a rejection that used to cost a real push and return an opaque
|
|
|
37
37
|
`preparation-failed` now reports before anything is sent. It does not prompt,
|
|
38
38
|
upload, commit, or rewrite source.
|
|
39
39
|
|
|
40
|
+
Interactive pushes show `Preparing push…` before workspace discovery,
|
|
41
|
+
lowering, and compilation begin. JSON and non-TTY output remain structured and
|
|
42
|
+
do not emit that terminal-only spinner.
|
|
43
|
+
|
|
40
44
|
A clean dry-run does not promise a clean push. The workspace holds its
|
|
41
45
|
last-pulled state, so everything that grades the live head is still server-only:
|
|
42
46
|
re-verification of the uploaded bundle bytes, project-file staging, the
|