@neocompose/cli 0.30.1 → 0.30.2
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,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.30.2] - 2026-08-13
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Pull instance-bound `NeoAction` listeners through their deterministic
|
|
8
|
+
`root.*` receiver paths and lower those paths back to the same listener
|
|
9
|
+
identity. Web-authored actions such as `[root.Assets.OnDamage]` now pull and
|
|
10
|
+
push without losing the receiver or leaving a phantom member change.
|
|
11
|
+
|
|
3
12
|
## [0.30.1] - 2026-08-13
|
|
4
13
|
|
|
5
14
|
### Fixed
|
package/dist/neo.mjs
CHANGED
|
@@ -47422,12 +47422,26 @@ function renderActionListeners(context, member, value) {
|
|
|
47422
47422
|
`NeoAction member ${member.name} listener ${index} is missing memberId.`
|
|
47423
47423
|
);
|
|
47424
47424
|
}
|
|
47425
|
-
|
|
47425
|
+
const target = required(
|
|
47426
|
+
context.members,
|
|
47427
|
+
listener.memberId,
|
|
47428
|
+
"action listener"
|
|
47429
|
+
);
|
|
47430
|
+
if (listener.valueId === null || listener.valueId === void 0) {
|
|
47431
|
+
return target.name;
|
|
47432
|
+
}
|
|
47433
|
+
if (typeof listener.valueId !== "string") {
|
|
47434
|
+
throw new Error(
|
|
47435
|
+
`NeoAction member ${member.name} listener ${index} has a non-string receiver valueId.`
|
|
47436
|
+
);
|
|
47437
|
+
}
|
|
47438
|
+
const receiver = context.collectionValuePaths.get(listener.valueId);
|
|
47439
|
+
if (receiver === void 0) {
|
|
47426
47440
|
throw new Error(
|
|
47427
|
-
`NeoAction member ${member.name} listener ${index} is
|
|
47441
|
+
`NeoAction member ${member.name} listener ${index} is bound to value ${listener.valueId}, which has no deterministic root path.`
|
|
47428
47442
|
);
|
|
47429
47443
|
}
|
|
47430
|
-
return
|
|
47444
|
+
return `${receiver}.${target.name}`;
|
|
47431
47445
|
});
|
|
47432
47446
|
return `[${names.join(", ")}]`;
|
|
47433
47447
|
}
|
|
@@ -53431,6 +53445,7 @@ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, ba
|
|
|
53431
53445
|
`NeoAction member ${ownerClass.name}.${declaration.name} cannot be nullable; an action's rest state is an empty listener list.`
|
|
53432
53446
|
);
|
|
53433
53447
|
}
|
|
53448
|
+
const baseAction = base?.kind === "action" ? base : void 0;
|
|
53434
53449
|
return {
|
|
53435
53450
|
...common,
|
|
53436
53451
|
kind: "action",
|
|
@@ -53439,7 +53454,10 @@ function lowerFieldMember(context, ownerClass, declaration, id2, commonInput, ba
|
|
|
53439
53454
|
// fixed false because nullability has no meaning here (P62 §2.1).
|
|
53440
53455
|
required: false,
|
|
53441
53456
|
arguments: fieldType.arguments.map((argumentType, index) => ({
|
|
53442
|
-
|
|
53457
|
+
// NeoAction's generic spelling carries types but no parameter names.
|
|
53458
|
+
// Preserve a pulled name when this stable declaration already exists;
|
|
53459
|
+
// `pN` remains the deterministic name for a newly authored action.
|
|
53460
|
+
name: baseAction?.arguments[index]?.name ?? `p${index + 1}`,
|
|
53443
53461
|
type: lowerType(context, argumentType, ownerClass),
|
|
53444
53462
|
default: null,
|
|
53445
53463
|
source: span(declaration),
|
|
@@ -54168,23 +54186,24 @@ function lowerActionDefault(context, expression, ownerClass, path) {
|
|
|
54168
54186
|
const listeners = [];
|
|
54169
54187
|
const identities = /* @__PURE__ */ new Set();
|
|
54170
54188
|
elements.forEach((element, index) => {
|
|
54171
|
-
const
|
|
54189
|
+
const listener = lowerActionListener(
|
|
54172
54190
|
context,
|
|
54173
54191
|
element,
|
|
54174
54192
|
ownerClass,
|
|
54175
54193
|
`${path}[${index}]`
|
|
54176
54194
|
);
|
|
54177
|
-
|
|
54195
|
+
const identity2 = `${listener.memberId}\0${listener.valueId ?? ""}`;
|
|
54196
|
+
if (identities.has(identity2)) {
|
|
54178
54197
|
throw new Error(
|
|
54179
54198
|
`NeoAction listener ${path}[${index}] repeats an earlier listener; a listener set holds each target once.`
|
|
54180
54199
|
);
|
|
54181
54200
|
}
|
|
54182
|
-
identities.add(
|
|
54183
|
-
listeners.push(
|
|
54201
|
+
identities.add(identity2);
|
|
54202
|
+
listeners.push(listener);
|
|
54184
54203
|
});
|
|
54185
54204
|
return { listeners };
|
|
54186
54205
|
}
|
|
54187
|
-
function
|
|
54206
|
+
function lowerActionListener(context, element, ownerClass, path) {
|
|
54188
54207
|
let current = element;
|
|
54189
54208
|
while (current.kind === "annotated") current = current.expression;
|
|
54190
54209
|
if (current.kind === "lambda") {
|
|
@@ -54192,21 +54211,26 @@ function lowerActionListenerId(context, element, ownerClass, path) {
|
|
|
54192
54211
|
`NeoAction listener ${path} is a lambda. A listener must be a member reference: extract the body to an NSFunction member and subscribe that member instead.`
|
|
54193
54212
|
);
|
|
54194
54213
|
}
|
|
54195
|
-
const
|
|
54196
|
-
if (
|
|
54214
|
+
const target = actionListenerTarget(context, current, ownerClass);
|
|
54215
|
+
if (target === null) {
|
|
54197
54216
|
throw new Error(
|
|
54198
|
-
`NeoAction listener ${path} must name a callable member on the current Class.`
|
|
54217
|
+
`NeoAction listener ${path} must name a callable member on the current Class or a receiver reachable through root.`
|
|
54199
54218
|
);
|
|
54200
54219
|
}
|
|
54201
|
-
const
|
|
54202
|
-
|
|
54220
|
+
const memberId = effectiveMemberIdByName(
|
|
54221
|
+
context,
|
|
54222
|
+
target.classId,
|
|
54223
|
+
target.memberName
|
|
54224
|
+
);
|
|
54203
54225
|
if (memberId === null) {
|
|
54204
54226
|
throw new Error(
|
|
54205
|
-
`NeoAction listener ${path} names ${JSON.stringify(
|
|
54227
|
+
`NeoAction listener ${path} names ${JSON.stringify(target.memberName)}, which its receiver Class does not declare or inherit.`
|
|
54206
54228
|
);
|
|
54207
54229
|
}
|
|
54208
54230
|
const declaration = context.sourceMembersById.get(memberId)?.member;
|
|
54209
|
-
if (declaration === void 0)
|
|
54231
|
+
if (declaration === void 0) {
|
|
54232
|
+
return { memberId, valueId: target.valueId };
|
|
54233
|
+
}
|
|
54210
54234
|
if (declaration.kind === "function") {
|
|
54211
54235
|
if (declaration.type.name !== "void") {
|
|
54212
54236
|
throw new Error(
|
|
@@ -54218,21 +54242,46 @@ function lowerActionListenerId(context, element, ownerClass, path) {
|
|
|
54218
54242
|
`NeoAction listener ${path} targets deferred ${declaration.name}; listeners are immediate-only.`
|
|
54219
54243
|
);
|
|
54220
54244
|
}
|
|
54221
|
-
return memberId;
|
|
54245
|
+
return { memberId, valueId: target.valueId };
|
|
54222
54246
|
}
|
|
54223
54247
|
if (declaration.type.name !== "NeoAction" && declaration.type.name !== "NeoDelegate") {
|
|
54224
54248
|
throw new Error(
|
|
54225
54249
|
`NeoAction listener ${path} targets ${declaration.name}, which is not a function, NSFunction, NSDelegate, or NeoAction member.`
|
|
54226
54250
|
);
|
|
54227
54251
|
}
|
|
54228
|
-
return memberId;
|
|
54252
|
+
return { memberId, valueId: target.valueId };
|
|
54229
54253
|
}
|
|
54230
|
-
function
|
|
54254
|
+
function actionListenerTarget(context, expression, ownerClass) {
|
|
54255
|
+
const expressionPath2 = actionListenerPath(expression);
|
|
54256
|
+
if (expressionPath2 === null) return null;
|
|
54257
|
+
if (!expressionPath2.includes(".")) {
|
|
54258
|
+
return {
|
|
54259
|
+
classId: materializedId(ownerClass, "class", ownerClass.name),
|
|
54260
|
+
memberName: expressionPath2,
|
|
54261
|
+
valueId: null
|
|
54262
|
+
};
|
|
54263
|
+
}
|
|
54264
|
+
if (expressionPath2.startsWith("this.")) {
|
|
54265
|
+
const memberName2 = expressionPath2.slice("this.".length);
|
|
54266
|
+
if (memberName2.includes(".")) return null;
|
|
54267
|
+
return {
|
|
54268
|
+
classId: materializedId(ownerClass, "class", ownerClass.name),
|
|
54269
|
+
memberName: memberName2,
|
|
54270
|
+
valueId: null
|
|
54271
|
+
};
|
|
54272
|
+
}
|
|
54273
|
+
const separator = expressionPath2.lastIndexOf(".");
|
|
54274
|
+
const receiverPath = expressionPath2.slice(0, separator);
|
|
54275
|
+
const memberName = expressionPath2.slice(separator + 1);
|
|
54276
|
+
const receiver = context.rootValueTargetsByPath.get(receiverPath);
|
|
54277
|
+
if (receiver === void 0) return null;
|
|
54278
|
+
return { ...receiver, memberName };
|
|
54279
|
+
}
|
|
54280
|
+
function actionListenerPath(expression) {
|
|
54231
54281
|
if (expression.kind === "ident") return expression.name;
|
|
54232
54282
|
if (expression.kind !== "member") return null;
|
|
54233
|
-
|
|
54234
|
-
|
|
54235
|
-
return expression.name;
|
|
54283
|
+
const receiver = actionListenerPath(expression.receiver);
|
|
54284
|
+
return receiver === null ? null : `${receiver}.${expression.name}`;
|
|
54236
54285
|
}
|
|
54237
54286
|
function lowerExpressionValue(context, expression, declaredExpected, ownerClass, path, genericEnvironment = EMPTY_GENERIC_TYPE_ENVIRONMENT, sourceText) {
|
|
54238
54287
|
const expected = substituteGenericTypeNames(
|
|
@@ -55283,6 +55332,81 @@ var init_lower_members = __esm({
|
|
|
55283
55332
|
}
|
|
55284
55333
|
});
|
|
55285
55334
|
|
|
55335
|
+
// src/project-source/root-value-paths.ts
|
|
55336
|
+
function rootValuePathsByValueId(records2) {
|
|
55337
|
+
const indexed = indexRecords(records2);
|
|
55338
|
+
const paths = /* @__PURE__ */ new Map();
|
|
55339
|
+
const queue = [];
|
|
55340
|
+
for (const [field, slot] of ROOT_PROJECT_FIELDS) {
|
|
55341
|
+
const memberId = indexed.project?.[field];
|
|
55342
|
+
const member = typeof memberId === "string" ? indexed.members.get(memberId) : void 0;
|
|
55343
|
+
const valueId = member?.valueId;
|
|
55344
|
+
if (typeof valueId === "string") {
|
|
55345
|
+
queue.push({ id: valueId, path: `root.${slot}` });
|
|
55346
|
+
}
|
|
55347
|
+
}
|
|
55348
|
+
while (queue.length > 0) {
|
|
55349
|
+
const next = queue.shift();
|
|
55350
|
+
if (next === void 0) break;
|
|
55351
|
+
if (paths.has(next.id)) continue;
|
|
55352
|
+
paths.set(next.id, next.path);
|
|
55353
|
+
const body = indexed.values.get(next.id)?.value;
|
|
55354
|
+
if (!isObjectRecord3(body)) continue;
|
|
55355
|
+
for (const [schemaKey, child] of Object.entries(body)) {
|
|
55356
|
+
if (typeof child !== "string") continue;
|
|
55357
|
+
if (!indexed.values.has(child)) continue;
|
|
55358
|
+
queue.push({ id: child, path: `${next.path}.${schemaKey}` });
|
|
55359
|
+
}
|
|
55360
|
+
}
|
|
55361
|
+
return paths;
|
|
55362
|
+
}
|
|
55363
|
+
function rootValueTargetsByPath(records2) {
|
|
55364
|
+
const allRecords = [...records2];
|
|
55365
|
+
const paths = rootValuePathsByValueId(allRecords);
|
|
55366
|
+
const values = new Map(
|
|
55367
|
+
allRecords.flatMap(
|
|
55368
|
+
(record3) => !record3.deleted && record3.recordKind === "value" && isObjectRecord3(record3.data) ? [[record3.recordId, record3.data]] : []
|
|
55369
|
+
)
|
|
55370
|
+
);
|
|
55371
|
+
const targets = /* @__PURE__ */ new Map();
|
|
55372
|
+
for (const [valueId, path] of paths) {
|
|
55373
|
+
const classId = values.get(valueId)?.classId;
|
|
55374
|
+
if (typeof classId === "string") {
|
|
55375
|
+
targets.set(path, { valueId, classId });
|
|
55376
|
+
}
|
|
55377
|
+
}
|
|
55378
|
+
return targets;
|
|
55379
|
+
}
|
|
55380
|
+
function indexRecords(records2) {
|
|
55381
|
+
let project;
|
|
55382
|
+
const members = /* @__PURE__ */ new Map();
|
|
55383
|
+
const values = /* @__PURE__ */ new Map();
|
|
55384
|
+
for (const record3 of records2) {
|
|
55385
|
+
if (record3.deleted || !isObjectRecord3(record3.data)) continue;
|
|
55386
|
+
if (record3.recordKind === "project") project ??= record3.data;
|
|
55387
|
+
else if (record3.recordKind === "member") {
|
|
55388
|
+
members.set(record3.recordId, record3.data);
|
|
55389
|
+
} else if (record3.recordKind === "value") {
|
|
55390
|
+
values.set(record3.recordId, record3.data);
|
|
55391
|
+
}
|
|
55392
|
+
}
|
|
55393
|
+
return { project, members, values };
|
|
55394
|
+
}
|
|
55395
|
+
function isObjectRecord3(value) {
|
|
55396
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
55397
|
+
}
|
|
55398
|
+
var ROOT_PROJECT_FIELDS;
|
|
55399
|
+
var init_root_value_paths = __esm({
|
|
55400
|
+
"src/project-source/root-value-paths.ts"() {
|
|
55401
|
+
"use strict";
|
|
55402
|
+
ROOT_PROJECT_FIELDS = [
|
|
55403
|
+
["rootAssetsMemberId", "Assets"],
|
|
55404
|
+
["rootSaveFileMemberId", "Save"],
|
|
55405
|
+
["rootSessionMemberId", "Session"]
|
|
55406
|
+
];
|
|
55407
|
+
}
|
|
55408
|
+
});
|
|
55409
|
+
|
|
55286
55410
|
// ../src/models/members/member-value-id.ts
|
|
55287
55411
|
function derivedMemberValueId(memberId) {
|
|
55288
55412
|
return inSystemRecordNamespaceOf(
|
|
@@ -70905,6 +71029,7 @@ function lowerProjectSchemaV4(base, analysis, options = {}) {
|
|
|
70905
71029
|
),
|
|
70906
71030
|
projectFileIdsBySymbol: options.projectFileIdsBySymbol ?? /* @__PURE__ */ new Map(),
|
|
70907
71031
|
rowBackedDefaultMemberIds: options.rowBackedDefaultMemberIds ?? /* @__PURE__ */ new Set(),
|
|
71032
|
+
rootValueTargetsByPath: options.rootValueTargetsByPath ?? /* @__PURE__ */ new Map(),
|
|
70908
71033
|
declaredConstructors: buildDeclaredConstructorIndex(analysis),
|
|
70909
71034
|
compiledFunctionBodiesByMemberId: new Map(
|
|
70910
71035
|
analysis.compiledBodies.filter((body) => body.unit === "function").map((body) => [body.memberId, body.ir])
|
|
@@ -73404,7 +73529,7 @@ function validateProjectRootEnvelopeV4(state, analysis) {
|
|
|
73404
73529
|
return { expectedIds, global, slots };
|
|
73405
73530
|
}
|
|
73406
73531
|
function rootMemberIds(project) {
|
|
73407
|
-
return
|
|
73532
|
+
return ROOT_PROJECT_FIELDS2.map((field) => {
|
|
73408
73533
|
const id2 = project[field];
|
|
73409
73534
|
if (typeof id2 !== "string" || id2.length === 0) {
|
|
73410
73535
|
throw new Error(`Project record has no ${field}.`);
|
|
@@ -73507,47 +73632,16 @@ function walkRootValuePath(path, state, registry, fail) {
|
|
|
73507
73632
|
}
|
|
73508
73633
|
return cursor;
|
|
73509
73634
|
}
|
|
73510
|
-
|
|
73511
|
-
const paths = /* @__PURE__ */ new Map();
|
|
73512
|
-
const project = [...records2.values()].find(
|
|
73513
|
-
(record3) => record3.recordKind === "project"
|
|
73514
|
-
);
|
|
73515
|
-
if (project === void 0 || !isObjectRecord2(project.data)) return paths;
|
|
73516
|
-
const queue = [];
|
|
73517
|
-
ROOT_PROJECT_FIELDS.forEach((field, index) => {
|
|
73518
|
-
const slot = PROJECT_ROOT_SOURCE_SLOTS[index];
|
|
73519
|
-
const memberId = isObjectRecord2(project.data) ? project.data[field] : void 0;
|
|
73520
|
-
if (slot === void 0 || typeof memberId !== "string") return;
|
|
73521
|
-
const member = records2.get(`member:${memberId}`);
|
|
73522
|
-
const valueId = isObjectRecord2(member?.data) ? member.data.valueId : void 0;
|
|
73523
|
-
if (typeof valueId !== "string") return;
|
|
73524
|
-
queue.push({ id: valueId, path: `root.${slot.name}` });
|
|
73525
|
-
});
|
|
73526
|
-
while (queue.length > 0) {
|
|
73527
|
-
const next = queue.shift();
|
|
73528
|
-
if (next === void 0) break;
|
|
73529
|
-
if (paths.has(next.id)) continue;
|
|
73530
|
-
paths.set(next.id, next.path);
|
|
73531
|
-
const row = records2.get(`value:${next.id}`);
|
|
73532
|
-
const body = isObjectRecord2(row?.data) ? row.data.value : void 0;
|
|
73533
|
-
if (!isObjectRecord2(body)) continue;
|
|
73534
|
-
for (const [schemaKey, child] of Object.entries(body)) {
|
|
73535
|
-
if (typeof child !== "string") continue;
|
|
73536
|
-
if (!records2.has(`value:${child}`)) continue;
|
|
73537
|
-
queue.push({ id: child, path: `${next.path}.${schemaKey}` });
|
|
73538
|
-
}
|
|
73539
|
-
}
|
|
73540
|
-
return paths;
|
|
73541
|
-
}
|
|
73542
|
-
var ROOT_PROJECT_FIELDS, ROOT_PATH_PENDING_PREFIX;
|
|
73635
|
+
var ROOT_PROJECT_FIELDS2, ROOT_PATH_PENDING_PREFIX;
|
|
73543
73636
|
var init_root_source = __esm({
|
|
73544
73637
|
"src/project-source/root-source.ts"() {
|
|
73545
73638
|
"use strict";
|
|
73546
73639
|
init_src();
|
|
73547
73640
|
init_projection();
|
|
73548
73641
|
init_value_sources();
|
|
73642
|
+
init_root_value_paths();
|
|
73549
73643
|
init_source_format();
|
|
73550
|
-
|
|
73644
|
+
ROOT_PROJECT_FIELDS2 = [
|
|
73551
73645
|
"rootAssetsMemberId",
|
|
73552
73646
|
"rootSaveFileMemberId",
|
|
73553
73647
|
"rootSessionMemberId"
|
|
@@ -75329,19 +75423,19 @@ function neoScriptSchemaContractProjection(kind, value) {
|
|
|
75329
75423
|
if (kind === "enum") ignored.add("optionKeyOrder");
|
|
75330
75424
|
if (kind === "interface") ignored.add("memberKeyOrder");
|
|
75331
75425
|
const projected = withoutFields(value, ignored);
|
|
75332
|
-
if (kind === "enum" &&
|
|
75426
|
+
if (kind === "enum" && isObjectRecord4(projected.options)) {
|
|
75333
75427
|
projected.options = Object.fromEntries(
|
|
75334
75428
|
Object.entries(projected.options).map(([id2, option]) => [
|
|
75335
75429
|
id2,
|
|
75336
|
-
|
|
75430
|
+
isObjectRecord4(option) ? { id: option.id, name: option.name } : option
|
|
75337
75431
|
])
|
|
75338
75432
|
);
|
|
75339
75433
|
}
|
|
75340
|
-
if (kind === "interface" &&
|
|
75434
|
+
if (kind === "interface" && isObjectRecord4(projected.members)) {
|
|
75341
75435
|
projected.members = Object.fromEntries(
|
|
75342
75436
|
Object.entries(projected.members).map(([key, member]) => [
|
|
75343
75437
|
key,
|
|
75344
|
-
|
|
75438
|
+
isObjectRecord4(member) ? withoutFields(member, /* @__PURE__ */ new Set(["docsText"])) : member
|
|
75345
75439
|
])
|
|
75346
75440
|
);
|
|
75347
75441
|
}
|
|
@@ -75496,7 +75590,7 @@ function selectedRecordIds(records2, explicitIds, impactedIds, impactedTypeNames
|
|
|
75496
75590
|
return selected;
|
|
75497
75591
|
}
|
|
75498
75592
|
function recordDependsOnChangedContract(record3, impactedIds, impactedTypeNames, constructedClassIds, impactedSourceNames) {
|
|
75499
|
-
const recordId =
|
|
75593
|
+
const recordId = isObjectRecord4(record3) ? record3.id : void 0;
|
|
75500
75594
|
if (typeof recordId === "string" && impactedIds.has(recordId)) return true;
|
|
75501
75595
|
if (intersects(collectCompilerReferenceIds(record3), impactedIds)) return true;
|
|
75502
75596
|
if (intersects(collectCompilerReferenceNames(record3), impactedTypeNames)) {
|
|
@@ -75572,7 +75666,7 @@ function collectDeclaredSourceNames(value, names) {
|
|
|
75572
75666
|
for (const child of value) collectDeclaredSourceNames(child, names);
|
|
75573
75667
|
return;
|
|
75574
75668
|
}
|
|
75575
|
-
if (!
|
|
75669
|
+
if (!isObjectRecord4(value)) return;
|
|
75576
75670
|
for (const [field, child] of Object.entries(value)) {
|
|
75577
75671
|
if (typeof child === "string" && (field === "name" || field === "sourceName" || field === "sourceFunctionName" || field === "declaredTypeName" || field === "typeName")) {
|
|
75578
75672
|
names.add(child);
|
|
@@ -75589,7 +75683,7 @@ function collectAuthoredNeoScriptSourceIdentifiers(value) {
|
|
|
75589
75683
|
for (const entry of child) collect(entry);
|
|
75590
75684
|
return;
|
|
75591
75685
|
}
|
|
75592
|
-
if (!
|
|
75686
|
+
if (!isObjectRecord4(child)) return;
|
|
75593
75687
|
for (const [field, nested] of Object.entries(child)) {
|
|
75594
75688
|
if ((field === "code" || field === "setterCode") && typeof nested === "string") {
|
|
75595
75689
|
const result = lex(nested);
|
|
@@ -75613,7 +75707,7 @@ function containsAuthoredNeoScriptSource(value) {
|
|
|
75613
75707
|
if (Array.isArray(value)) {
|
|
75614
75708
|
return value.some(containsAuthoredNeoScriptSource);
|
|
75615
75709
|
}
|
|
75616
|
-
if (!
|
|
75710
|
+
if (!isObjectRecord4(value)) return false;
|
|
75617
75711
|
for (const [field, child] of Object.entries(value)) {
|
|
75618
75712
|
if ((field === "code" || field === "setterCode") && typeof child === "string" && child.trim().length > 0) {
|
|
75619
75713
|
return true;
|
|
@@ -75624,13 +75718,13 @@ function containsAuthoredNeoScriptSource(value) {
|
|
|
75624
75718
|
}
|
|
75625
75719
|
function containsCompiledNeoScriptBody(value) {
|
|
75626
75720
|
if (Array.isArray(value)) return value.some(containsCompiledNeoScriptBody);
|
|
75627
|
-
if (!
|
|
75628
|
-
if (Array.isArray(value.parameters) && Array.isArray(value.instructions) &&
|
|
75721
|
+
if (!isObjectRecord4(value)) return false;
|
|
75722
|
+
if (Array.isArray(value.parameters) && Array.isArray(value.instructions) && isObjectRecord4(value.typeInfo)) {
|
|
75629
75723
|
return true;
|
|
75630
75724
|
}
|
|
75631
75725
|
return Object.values(value).some(containsCompiledNeoScriptBody);
|
|
75632
75726
|
}
|
|
75633
|
-
function
|
|
75727
|
+
function isObjectRecord4(value) {
|
|
75634
75728
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
75635
75729
|
}
|
|
75636
75730
|
function constructorOwners(document) {
|
|
@@ -86799,6 +86893,9 @@ function computeWorkspaceStatus(workspace, options) {
|
|
|
86799
86893
|
),
|
|
86800
86894
|
rowBackedDefaultMemberIds: rowBackedDefaultMemberIdsV4(
|
|
86801
86895
|
workspace.state.records
|
|
86896
|
+
),
|
|
86897
|
+
rootValueTargetsByPath: rootValueTargetsByPath(
|
|
86898
|
+
Object.values(workspace.state.records)
|
|
86802
86899
|
)
|
|
86803
86900
|
});
|
|
86804
86901
|
memberDefaults = lowerMemberDefaultSourcesV4(
|
|
@@ -87828,6 +87925,7 @@ var init_workspace_status_core = __esm({
|
|
|
87828
87925
|
init_core();
|
|
87829
87926
|
init_value_sources();
|
|
87830
87927
|
init_root_source();
|
|
87928
|
+
init_root_value_paths();
|
|
87831
87929
|
init_project_documents();
|
|
87832
87930
|
init_animation_clips();
|
|
87833
87931
|
init_classes();
|
|
@@ -89089,6 +89187,7 @@ function buildValueEmitContext(records2, manifest) {
|
|
|
89089
89187
|
localizedTexts,
|
|
89090
89188
|
mainLocale: projectMainLocale(records2),
|
|
89091
89189
|
symbolsByValueId,
|
|
89190
|
+
rootPathsByValueId: rootValuePathsByValueId(records2.values()),
|
|
89092
89191
|
symbolsByDialogueId: new Map(
|
|
89093
89192
|
[...dialogues].flatMap(
|
|
89094
89193
|
([id2, dialogue]) => typeof dialogue.sourceName === "string" ? [[id2, dialogue.sourceName]] : []
|
|
@@ -89458,6 +89557,7 @@ function buildValueLowerContext(state, manifest, options = {}) {
|
|
|
89458
89557
|
])
|
|
89459
89558
|
),
|
|
89460
89559
|
staticValueIdsBySymbol: staticTargets,
|
|
89560
|
+
rootValueTargetsByPath: rootValueTargetsByPath(Object.values(state)),
|
|
89461
89561
|
dialogueTargetsBySymbol: dialogueTargetsBySymbol(options.analysis),
|
|
89462
89562
|
projectFileIdsBySymbol: projectFileIdsBySymbol(state, options.analysis),
|
|
89463
89563
|
mainLocale: projectMainLocaleFromState(state),
|
|
@@ -93127,18 +93227,19 @@ function lowerActionValue(context, expression, ownerClassId) {
|
|
|
93127
93227
|
const listeners = [];
|
|
93128
93228
|
const identities = /* @__PURE__ */ new Set();
|
|
93129
93229
|
elements.forEach((element, index) => {
|
|
93130
|
-
const listener =
|
|
93131
|
-
|
|
93230
|
+
const listener = lowerActionListener2(context, element, ownerClassId, index);
|
|
93231
|
+
const identity2 = `${listener.memberId}\0${listener.valueId ?? ""}`;
|
|
93232
|
+
if (identities.has(identity2)) {
|
|
93132
93233
|
throw new Error(
|
|
93133
93234
|
`NeoAction listener ${index} repeats an earlier listener; a listener set holds each target once.`
|
|
93134
93235
|
);
|
|
93135
93236
|
}
|
|
93136
|
-
identities.add(
|
|
93237
|
+
identities.add(identity2);
|
|
93137
93238
|
listeners.push(listener);
|
|
93138
93239
|
});
|
|
93139
93240
|
return { listeners };
|
|
93140
93241
|
}
|
|
93141
|
-
function
|
|
93242
|
+
function lowerActionListener2(context, element, ownerClassId, index) {
|
|
93142
93243
|
const { expression } = annotatedValue(element);
|
|
93143
93244
|
if (expression.kind === "lambda") {
|
|
93144
93245
|
throw new Error(
|
|
@@ -93146,35 +93247,51 @@ function lowerActionListener(context, element, ownerClassId, index) {
|
|
|
93146
93247
|
);
|
|
93147
93248
|
}
|
|
93148
93249
|
const path = memberPath(expression);
|
|
93149
|
-
|
|
93150
|
-
if (symbol === null || symbol === void 0 || symbol.includes(".")) {
|
|
93250
|
+
if (path === null) {
|
|
93151
93251
|
throw new Error(
|
|
93152
|
-
`NeoAction listener ${index} must name a function, NSFunction, NSDelegate, or NeoAction member on the current Class.`
|
|
93252
|
+
`NeoAction listener ${index} must name a function, NSFunction, NSDelegate, or NeoAction member on the current Class or a receiver reachable through root.`
|
|
93153
93253
|
);
|
|
93154
93254
|
}
|
|
93155
|
-
|
|
93156
|
-
|
|
93157
|
-
|
|
93158
|
-
|
|
93255
|
+
const localSymbol2 = path.startsWith("this.") ? path.slice("this.".length) : path;
|
|
93256
|
+
let target;
|
|
93257
|
+
let valueId = null;
|
|
93258
|
+
if (!localSymbol2.includes(".")) {
|
|
93259
|
+
if (ownerClassId === void 0) {
|
|
93260
|
+
throw new Error(
|
|
93261
|
+
`NeoAction listener ${localSymbol2} cannot be resolved without its owning Class.`
|
|
93262
|
+
);
|
|
93263
|
+
}
|
|
93264
|
+
target = classMemberByName(context, ownerClassId, localSymbol2);
|
|
93265
|
+
} else {
|
|
93266
|
+
const separator = path.lastIndexOf(".");
|
|
93267
|
+
const receiverPath = path.slice(0, separator);
|
|
93268
|
+
const memberName = path.slice(separator + 1);
|
|
93269
|
+
const receiver = context.rootValueTargetsByPath.get(receiverPath);
|
|
93270
|
+
if (receiver === void 0) {
|
|
93271
|
+
throw new Error(
|
|
93272
|
+
`NeoAction listener ${index} receiver ${receiverPath} is not reachable through a deterministic root path.`
|
|
93273
|
+
);
|
|
93274
|
+
}
|
|
93275
|
+
target = classMemberByName(context, receiver.classId, memberName);
|
|
93276
|
+
valueId = receiver.valueId;
|
|
93159
93277
|
}
|
|
93160
|
-
|
|
93161
|
-
if (target.kind === "action") return { memberId: target.id, valueId: null };
|
|
93278
|
+
if (target.kind === "action") return { memberId: target.id, valueId };
|
|
93162
93279
|
if (target.kind !== "function" && target.kind !== "scriptFunction" && target.kind !== "delegate") {
|
|
93163
93280
|
throw new Error(
|
|
93164
|
-
`NeoAction listener ${
|
|
93281
|
+
`NeoAction listener ${path} does not resolve to a function, NSFunction, NSDelegate, or NeoAction member.`
|
|
93165
93282
|
);
|
|
93166
93283
|
}
|
|
93167
93284
|
if (target.returnType.kind !== "void") {
|
|
93168
93285
|
throw new Error(
|
|
93169
|
-
`NeoAction listener ${
|
|
93286
|
+
`NeoAction listener ${path} returns a value; a listener must be void.`
|
|
93170
93287
|
);
|
|
93171
93288
|
}
|
|
93172
93289
|
if (target.kind !== "delegate" && target.deferred) {
|
|
93173
93290
|
throw new Error(
|
|
93174
|
-
`NeoAction listener ${
|
|
93291
|
+
`NeoAction listener ${path} is deferred; listeners are immediate-only.`
|
|
93175
93292
|
);
|
|
93176
93293
|
}
|
|
93177
|
-
return { memberId: target.id, valueId
|
|
93294
|
+
return { memberId: target.id, valueId };
|
|
93178
93295
|
}
|
|
93179
93296
|
function lowerDelegateValue(context, expression, ownerClassId, authoredSlice) {
|
|
93180
93297
|
if (expression.kind === "lambda") {
|
|
@@ -94723,11 +94840,6 @@ function actionListenerName(context, listener, index) {
|
|
|
94723
94840
|
if (typeof listener.memberId !== "string") {
|
|
94724
94841
|
throw new Error(`NSAction listener ${index} is missing memberId.`);
|
|
94725
94842
|
}
|
|
94726
|
-
if (listener.valueId !== null && listener.valueId !== void 0) {
|
|
94727
|
-
throw new Error(
|
|
94728
|
-
`NSAction listener ${index} is instance-bound and cannot be represented by current project source.`
|
|
94729
|
-
);
|
|
94730
|
-
}
|
|
94731
94843
|
const target = context.members.get(listener.memberId);
|
|
94732
94844
|
if (target === void 0 || typeof target.name !== "string") {
|
|
94733
94845
|
throw new Error(`NSAction listener ${listener.memberId} was not pulled.`);
|
|
@@ -94736,7 +94848,19 @@ function actionListenerName(context, listener, index) {
|
|
|
94736
94848
|
if (kind !== 13 && kind !== 23 && kind !== 25 && kind !== 26) {
|
|
94737
94849
|
throw new Error(`NSAction listener ${listener.memberId} is not callable.`);
|
|
94738
94850
|
}
|
|
94739
|
-
|
|
94851
|
+
if (listener.valueId === null || listener.valueId === void 0) {
|
|
94852
|
+
return target.name;
|
|
94853
|
+
}
|
|
94854
|
+
if (typeof listener.valueId !== "string") {
|
|
94855
|
+
throw new Error(`NSAction listener ${index} has a non-string valueId.`);
|
|
94856
|
+
}
|
|
94857
|
+
const receiver = context.rootPathsByValueId.get(listener.valueId);
|
|
94858
|
+
if (receiver === void 0) {
|
|
94859
|
+
throw new Error(
|
|
94860
|
+
`NSAction listener ${index} is bound to value ${listener.valueId}, which has no deterministic root path.`
|
|
94861
|
+
);
|
|
94862
|
+
}
|
|
94863
|
+
return `${receiver}.${target.name}`;
|
|
94740
94864
|
}
|
|
94741
94865
|
function fileValue(context, kind, label, body, required2) {
|
|
94742
94866
|
if (body === null || body === void 0) {
|
|
@@ -94939,6 +95063,7 @@ var init_value_sources = __esm({
|
|
|
94939
95063
|
init_declared_constructors2();
|
|
94940
95064
|
init_init_source();
|
|
94941
95065
|
init_source_format();
|
|
95066
|
+
init_root_value_paths();
|
|
94942
95067
|
init_world_system_classes();
|
|
94943
95068
|
init_member_value_id();
|
|
94944
95069
|
init_members();
|
|
@@ -94981,7 +95106,7 @@ function emitProjectDocumentFilesV4(records2) {
|
|
|
94981
95106
|
defaultInitializers: memberDefaults.initializers,
|
|
94982
95107
|
fileSymbols: qualifiedProjectFileSymbolsV4(records2),
|
|
94983
95108
|
relationEndpointExpressions: relationEndpointExpressions(records2),
|
|
94984
|
-
collectionValuePaths: rootValuePathsByValueId(records2)
|
|
95109
|
+
collectionValuePaths: rootValuePathsByValueId(records2.values())
|
|
94985
95110
|
});
|
|
94986
95111
|
const source = {
|
|
94987
95112
|
...baseSource,
|
|
@@ -95110,6 +95235,7 @@ var init_project_documents = __esm({
|
|
|
95110
95235
|
init_dialogue_sources();
|
|
95111
95236
|
init_value_sources();
|
|
95112
95237
|
init_root_source();
|
|
95238
|
+
init_root_value_paths();
|
|
95113
95239
|
init_source_diagnostics();
|
|
95114
95240
|
init_source_format();
|
|
95115
95241
|
PROJECT_SOURCE_ANALYSIS_V4_CACHE_PATH = ".neo/project-source-analysis-v4.json";
|
|
@@ -101668,11 +101794,11 @@ function assertProjectFileAuthoringRecordIdentifiers(recordKind, data) {
|
|
|
101668
101794
|
if (recordKind !== "unity-texture-template" && recordKind !== "unity-audio-clip-template") {
|
|
101669
101795
|
return;
|
|
101670
101796
|
}
|
|
101671
|
-
if (!
|
|
101797
|
+
if (!isObjectRecord5(data) || typeof data.name !== "string") return;
|
|
101672
101798
|
const label = recordKind === "unity-texture-template" ? "Unity texture template name" : "Unity audio clip template name";
|
|
101673
101799
|
assertProjectFileAuthoringIdentifier(data.name, label);
|
|
101674
101800
|
}
|
|
101675
|
-
function
|
|
101801
|
+
function isObjectRecord5(value) {
|
|
101676
101802
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
101677
101803
|
}
|
|
101678
101804
|
var init_project_file_authoring_identifiers = __esm({
|
|
@@ -104614,7 +104740,7 @@ var init_registry2 = __esm({
|
|
|
104614
104740
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
104615
104741
|
formatVersion: 3,
|
|
104616
104742
|
contractVersion: "3.11",
|
|
104617
|
-
cliVersion: "0.30.
|
|
104743
|
+
cliVersion: "0.30.2",
|
|
104618
104744
|
projectFileUploadBatchSize: 32,
|
|
104619
104745
|
documentRecords: {
|
|
104620
104746
|
member: {
|
|
@@ -111182,7 +111308,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
111182
111308
|
async function main() {
|
|
111183
111309
|
const args = parseArgs(process.argv.slice(2));
|
|
111184
111310
|
if (args.command === "--version") {
|
|
111185
|
-
console.log("0.30.
|
|
111311
|
+
console.log("0.30.2");
|
|
111186
111312
|
return;
|
|
111187
111313
|
}
|
|
111188
111314
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/package.json
CHANGED
|
@@ -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.30.
|
|
86
|
+
<!-- reviewed-through-cli: 0.30.2 -->
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -110,6 +110,12 @@ empty set.
|
|
|
110
110
|
public NeoAction<int> OnDamaged = [PlayHitFlash, ApplyDamage];
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
+
An instance-bound listener reachable through a stable project root keeps its
|
|
114
|
+
receiver path, for example `public NeoAction<int> OnDamaged =
|
|
115
|
+
[root.Assets.OnDamage];`. Pull refuses a bound receiver that has no
|
|
116
|
+
deterministic `root.*` path instead of emitting a source expression that would
|
|
117
|
+
silently change the target.
|
|
118
|
+
|
|
113
119
|
Subscribe and unsubscribe with `+=` and `-=` against the member reference
|
|
114
120
|
itself; both are durable writes deduplicated by target identity, so
|
|
115
121
|
re-running a subscription cannot double-subscribe. Invoke it as a statement —
|