@neocompose/cli 0.65.0 → 0.66.0
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 +13 -0
- package/dist/neo.mjs +517 -78
- package/dist/test-worker.mjs +24 -22
- package/package.json +1 -1
- package/skills/neocompose-cli/SKILL.md +1 -1
- package/skills/neocompose-cli/references/cli-development.md +1 -1
- package/skills/neocompose-cli/references/declarations-and-construction.md +10 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.66.0] - 2026-10-03
|
|
4
|
+
|
|
5
|
+
- Add the 18 script runtime lifecycle interfaces from P98, such as `INeoOnLoad`, `INeoUnityUpdate`, and `INeoUnityOnTriggerEnter2D`. Every project gets them as protected system records, and pull writes them under `Interfaces/System/` with `@system(kind: .ScriptRuntime)`.
|
|
6
|
+
- Reserve the lifecycle member names, such as `OnLoad` and `Update`. A member with one must be the public, immediate instance method implementing its interface, or it reports `reserved-lifecycle-member`. This tightens valid source: a project with an unrelated member by one of these names must rename it. Push enforces the same rule on records authored in the web editor.
|
|
7
|
+
- Report `lifecycle-hook-without-object` as a warning when a class reaches an `INeoUnity*` interface without extending `NeoObjectBase`. Push still succeeds.
|
|
8
|
+
- A lifecycle hook cannot be `@effect`. It reports `invalid-effect`.
|
|
9
|
+
|
|
10
|
+
## [0.65.1] - 2026-10-03
|
|
11
|
+
|
|
12
|
+
- Pull and push reconciliation emit a stored `new NeoAnimationSegmentFrame<NeoCollider?>(value: null)`. A null constructor argument typed by a class's generic parameter now checks nullability against the row's type argument. Previously, a pushed segment holding a null frame committed, but source reconciliation failed with "Required constructor argument stores null".
|
|
13
|
+
- Pulled type arguments keep a nullable binding's `?`, in constructions, references, and declared member types. Previously `FrameBox<NeoCollider?> Box` pulled as `FrameBox<NeoCollider> Box`, and the next push made the binding required.
|
|
14
|
+
- Code compiled from stored records keeps a nullable binding's `?`. A member declared `NeoAnimationSegmentFrame<NeoCollider?>` keeps that type, so passing it where that type is expected compiles, and reading its value as a required `NeoCollider` reports an error. Previously, every bound type argument was typed as required.
|
|
15
|
+
|
|
3
16
|
## [0.65.0] - 2026-10-03
|
|
4
17
|
|
|
5
18
|
- Move `Collider` from `NeoObject` to `NeoObjectBase`, so sprite objects and layer groups can carry a box collider too. Unity codegen implements `INeoColliderSource` on `NeoObjectBase`.
|
package/dist/neo.mjs
CHANGED
|
@@ -5959,6 +5959,10 @@ var init_neoflow_graph_parser = __esm({
|
|
|
5959
5959
|
});
|
|
5960
5960
|
|
|
5961
5961
|
// ../packages/neoscript-language/src/project-source-ast.ts
|
|
5962
|
+
function neoSourceTypeText(type) {
|
|
5963
|
+
const args = type.typeArguments.length > 0 ? `<${type.typeArguments.map(neoSourceTypeText).join(", ")}>` : "";
|
|
5964
|
+
return `${type.name}${args}${type.nullable ? "?" : ""}`;
|
|
5965
|
+
}
|
|
5962
5966
|
function isNeoSourceAccessModifier(value) {
|
|
5963
5967
|
return value === "public" || value === "protected" || value === "private";
|
|
5964
5968
|
}
|
|
@@ -7892,6 +7896,9 @@ function tripleInterpolationEnd(text, start, limit) {
|
|
|
7892
7896
|
}
|
|
7893
7897
|
return null;
|
|
7894
7898
|
}
|
|
7899
|
+
function rangesEqual(left, right) {
|
|
7900
|
+
return positionCompare(left.start, right.start) === 0 && positionCompare(left.end, right.end) === 0;
|
|
7901
|
+
}
|
|
7895
7902
|
function positionCompare(left, right) {
|
|
7896
7903
|
return left.line === right.line ? left.character - right.character : left.line - right.line;
|
|
7897
7904
|
}
|
|
@@ -8367,7 +8374,8 @@ var init_project_schema_contract_generated = __esm({
|
|
|
8367
8374
|
"DialogueMemoryContainer",
|
|
8368
8375
|
"DialoguePriorityDefault",
|
|
8369
8376
|
"PolicyImmutable",
|
|
8370
|
-
"PolicyDeleteBlocked"
|
|
8377
|
+
"PolicyDeleteBlocked",
|
|
8378
|
+
"ScriptRuntime"
|
|
8371
8379
|
],
|
|
8372
8380
|
"NeoMemberRequirement": [
|
|
8373
8381
|
"Optional",
|
|
@@ -26424,6 +26432,40 @@ var init_project_source_script_compiler = __esm({
|
|
|
26424
26432
|
}
|
|
26425
26433
|
});
|
|
26426
26434
|
|
|
26435
|
+
// ../packages/neoscript-language/src/project-source-lifecycle-hooks.ts
|
|
26436
|
+
function isScriptRuntimeInterface(declaration) {
|
|
26437
|
+
const kind = declaration.annotations.find((annotation2) => annotation2.name === "system")?.arguments.find((argument2) => argument2.name === "kind")?.text.trim();
|
|
26438
|
+
return kind === ".ScriptRuntime";
|
|
26439
|
+
}
|
|
26440
|
+
function lifecycleHooksByMemberName(interfaces) {
|
|
26441
|
+
const hooks = /* @__PURE__ */ new Map();
|
|
26442
|
+
for (const declaration of interfaces) {
|
|
26443
|
+
if (!isScriptRuntimeInterface(declaration)) continue;
|
|
26444
|
+
for (const member of declaration.members) {
|
|
26445
|
+
if (member.kind !== "function") continue;
|
|
26446
|
+
hooks.set(member.name.toLowerCase(), {
|
|
26447
|
+
interfaceName: declaration.name,
|
|
26448
|
+
member,
|
|
26449
|
+
...declaration.docsText === void 0 ? {} : { docsText: declaration.docsText },
|
|
26450
|
+
unity: declaration.name.startsWith(UNITY_LIFECYCLE_INTERFACE_PREFIX)
|
|
26451
|
+
});
|
|
26452
|
+
}
|
|
26453
|
+
}
|
|
26454
|
+
return hooks;
|
|
26455
|
+
}
|
|
26456
|
+
function reservedLifecycleMemberMessage(memberName, interfaceName, owner) {
|
|
26457
|
+
const fix = owner === "class" ? "Implement the interface with a public method" : "Extend the interface";
|
|
26458
|
+
return `'${memberName}' is reserved for '${interfaceName}'. ${fix}, or rename the member.`;
|
|
26459
|
+
}
|
|
26460
|
+
var NEO_LIFECYCLE_OBJECT_CLASS_NAME, UNITY_LIFECYCLE_INTERFACE_PREFIX;
|
|
26461
|
+
var init_project_source_lifecycle_hooks = __esm({
|
|
26462
|
+
"../packages/neoscript-language/src/project-source-lifecycle-hooks.ts"() {
|
|
26463
|
+
"use strict";
|
|
26464
|
+
NEO_LIFECYCLE_OBJECT_CLASS_NAME = "NeoObjectBase";
|
|
26465
|
+
UNITY_LIFECYCLE_INTERFACE_PREFIX = "INeoUnity";
|
|
26466
|
+
}
|
|
26467
|
+
});
|
|
26468
|
+
|
|
26427
26469
|
// ../packages/neoscript-language/src/project-source-type-checker.ts
|
|
26428
26470
|
function validateProjectSourceTypes(documents) {
|
|
26429
26471
|
const diagnostics = [];
|
|
@@ -26433,6 +26475,7 @@ function validateProjectSourceTypes(documents) {
|
|
|
26433
26475
|
validateInheritanceCycles(environment, diagnostics);
|
|
26434
26476
|
validateAllTypeApplications(documents, environment, diagnostics);
|
|
26435
26477
|
validateMembers(environment, diagnostics);
|
|
26478
|
+
validateLifecycleHooks(environment, diagnostics);
|
|
26436
26479
|
return diagnostics;
|
|
26437
26480
|
}
|
|
26438
26481
|
function createEnvironment2(documents) {
|
|
@@ -26489,7 +26532,16 @@ function createEnvironment2(documents) {
|
|
|
26489
26532
|
}
|
|
26490
26533
|
}
|
|
26491
26534
|
}
|
|
26492
|
-
return {
|
|
26535
|
+
return {
|
|
26536
|
+
declarations,
|
|
26537
|
+
classes,
|
|
26538
|
+
interfaces,
|
|
26539
|
+
memberOwners,
|
|
26540
|
+
typeKinds,
|
|
26541
|
+
lifecycleHooks: lifecycleHooksByMemberName(
|
|
26542
|
+
[...interfaces.values()].map((ref) => ref.declaration)
|
|
26543
|
+
)
|
|
26544
|
+
};
|
|
26493
26545
|
}
|
|
26494
26546
|
function validatePersistedNames(documents, diagnostics) {
|
|
26495
26547
|
for (const [uri, document] of documents) {
|
|
@@ -27500,7 +27552,7 @@ function validateEffects(ref, environment, diagnostics) {
|
|
|
27500
27552
|
kind = inheritedEffectKind(inherited, member.name);
|
|
27501
27553
|
}
|
|
27502
27554
|
if (kind !== "Auto") continue;
|
|
27503
|
-
const problem = effectIneligibility(member);
|
|
27555
|
+
const problem = effectIneligibility(member) ?? (environment.lifecycleHooks.has(member.name.toLowerCase()) ? "the runtime already calls a lifecycle hook, so its first run would happen twice" : null);
|
|
27504
27556
|
if (problem === null) continue;
|
|
27505
27557
|
diagnose(
|
|
27506
27558
|
diagnostics,
|
|
@@ -27550,6 +27602,110 @@ function effectIneligibility(member) {
|
|
|
27550
27602
|
if (member.parameters.length > 0) return "an effect takes no parameters";
|
|
27551
27603
|
return null;
|
|
27552
27604
|
}
|
|
27605
|
+
function validateLifecycleHooks(environment, diagnostics) {
|
|
27606
|
+
const hooks = environment.lifecycleHooks;
|
|
27607
|
+
if (hooks.size === 0) return;
|
|
27608
|
+
for (const ref of environment.interfaces.values()) {
|
|
27609
|
+
if (isScriptRuntimeInterface(ref.declaration)) continue;
|
|
27610
|
+
for (const member of ref.declaration.members) {
|
|
27611
|
+
const hook = hooks.get(member.name.toLowerCase());
|
|
27612
|
+
if (hook === void 0) continue;
|
|
27613
|
+
diagnose(
|
|
27614
|
+
diagnostics,
|
|
27615
|
+
ref.uri,
|
|
27616
|
+
member.nameRange,
|
|
27617
|
+
"reserved-lifecycle-member",
|
|
27618
|
+
reservedLifecycleMemberMessage(
|
|
27619
|
+
member.name,
|
|
27620
|
+
hook.interfaceName,
|
|
27621
|
+
"interface"
|
|
27622
|
+
)
|
|
27623
|
+
);
|
|
27624
|
+
}
|
|
27625
|
+
}
|
|
27626
|
+
const unityHookByInterface = /* @__PURE__ */ new Map();
|
|
27627
|
+
for (const ref of environment.classes.values()) {
|
|
27628
|
+
if (ref.sourceKind === "flow") continue;
|
|
27629
|
+
let implemented;
|
|
27630
|
+
for (const member of ref.declaration.members) {
|
|
27631
|
+
const hook = hooks.get(member.name.toLowerCase());
|
|
27632
|
+
if (hook === void 0) continue;
|
|
27633
|
+
implemented ??= new Set(
|
|
27634
|
+
implementedInterfaces(ref, environment).map(
|
|
27635
|
+
(view) => view.owner.declaration.name
|
|
27636
|
+
)
|
|
27637
|
+
);
|
|
27638
|
+
if (member.kind === "function" && effectiveSourceAccessModifier(member.modifiers, "class") === "public" && !member.modifiers.includes("static") && !member.modifiers.includes("async") && implemented.has(hook.interfaceName)) {
|
|
27639
|
+
continue;
|
|
27640
|
+
}
|
|
27641
|
+
diagnose(
|
|
27642
|
+
diagnostics,
|
|
27643
|
+
ref.uri,
|
|
27644
|
+
member.nameRange,
|
|
27645
|
+
"reserved-lifecycle-member",
|
|
27646
|
+
reservedLifecycleMemberMessage(
|
|
27647
|
+
member.name,
|
|
27648
|
+
hook.interfaceName,
|
|
27649
|
+
"class"
|
|
27650
|
+
)
|
|
27651
|
+
);
|
|
27652
|
+
}
|
|
27653
|
+
let rendersObjects;
|
|
27654
|
+
for (const base of ref.declaration.baseTypes) {
|
|
27655
|
+
const target = environment.interfaces.get(base.name);
|
|
27656
|
+
if (target === void 0) continue;
|
|
27657
|
+
const unityHook = unityHookReachedBy(
|
|
27658
|
+
target,
|
|
27659
|
+
environment,
|
|
27660
|
+
unityHookByInterface
|
|
27661
|
+
);
|
|
27662
|
+
if (unityHook === null) continue;
|
|
27663
|
+
rendersObjects ??= extendsLifecycleObjectClass(ref, environment);
|
|
27664
|
+
if (rendersObjects) break;
|
|
27665
|
+
diagnostics.push({
|
|
27666
|
+
uri: ref.uri,
|
|
27667
|
+
range: base.range,
|
|
27668
|
+
severity: "warning",
|
|
27669
|
+
source: "neo-project",
|
|
27670
|
+
code: "lifecycle-hook-without-object",
|
|
27671
|
+
message: `'${unityHook}' does nothing on '${ref.declaration.name}'. Only classes that extend ${NEO_LIFECYCLE_OBJECT_CLASS_NAME} get Unity lifecycle calls.`
|
|
27672
|
+
});
|
|
27673
|
+
}
|
|
27674
|
+
}
|
|
27675
|
+
}
|
|
27676
|
+
function unityHookReachedBy(ref, environment, memo) {
|
|
27677
|
+
const name = ref.declaration.name;
|
|
27678
|
+
const known = memo.get(name);
|
|
27679
|
+
if (known !== void 0) return known;
|
|
27680
|
+
memo.set(name, null);
|
|
27681
|
+
let reached = null;
|
|
27682
|
+
if (isScriptRuntimeInterface(ref.declaration) && ref.declaration.members.some(
|
|
27683
|
+
(member) => environment.lifecycleHooks.get(member.name.toLowerCase())?.unity === true
|
|
27684
|
+
)) {
|
|
27685
|
+
reached = name;
|
|
27686
|
+
}
|
|
27687
|
+
for (const base of ref.declaration.baseTypes) {
|
|
27688
|
+
if (reached !== null) break;
|
|
27689
|
+
const target = environment.interfaces.get(base.name);
|
|
27690
|
+
if (target !== void 0) {
|
|
27691
|
+
reached = unityHookReachedBy(target, environment, memo);
|
|
27692
|
+
}
|
|
27693
|
+
}
|
|
27694
|
+
memo.set(name, reached);
|
|
27695
|
+
return reached;
|
|
27696
|
+
}
|
|
27697
|
+
function extendsLifecycleObjectClass(ref, environment) {
|
|
27698
|
+
const visited = /* @__PURE__ */ new Set();
|
|
27699
|
+
let current = ref;
|
|
27700
|
+
while (current !== null && !visited.has(current.declaration.name)) {
|
|
27701
|
+
if (current.declaration.name === NEO_LIFECYCLE_OBJECT_CLASS_NAME) {
|
|
27702
|
+
return true;
|
|
27703
|
+
}
|
|
27704
|
+
visited.add(current.declaration.name);
|
|
27705
|
+
current = classBase(current, identitySubstitution(current), environment)?.owner ?? null;
|
|
27706
|
+
}
|
|
27707
|
+
return false;
|
|
27708
|
+
}
|
|
27553
27709
|
function isPlatformImplementedSystemMember(member) {
|
|
27554
27710
|
if (!member.modifiers.includes("protected")) return false;
|
|
27555
27711
|
return member.annotations.some((entry) => entry.name === "system");
|
|
@@ -28019,6 +28175,7 @@ var init_project_source_type_checker = __esm({
|
|
|
28019
28175
|
init_strict_compile_error();
|
|
28020
28176
|
init_project_source_accessors();
|
|
28021
28177
|
init_project_source_identifiers();
|
|
28178
|
+
init_project_source_lifecycle_hooks();
|
|
28022
28179
|
BUILTIN_ARITY = /* @__PURE__ */ new Map([
|
|
28023
28180
|
["List", 1],
|
|
28024
28181
|
["Set", 1],
|
|
@@ -28208,12 +28365,12 @@ function classifyConstantExpression(expression) {
|
|
|
28208
28365
|
function defaultTypeMismatch(type, constant, enumOptions, parameterName) {
|
|
28209
28366
|
if (constant.kind === "null") {
|
|
28210
28367
|
if (type.nullable) return null;
|
|
28211
|
-
return `Parameter '${parameterName}' defaults to null, but its type '${
|
|
28368
|
+
return `Parameter '${parameterName}' defaults to null, but its type '${neoSourceTypeText(type)}' is not nullable.`;
|
|
28212
28369
|
}
|
|
28213
28370
|
const declaredEnumOptions = enumOptions.get(type.name);
|
|
28214
28371
|
if (constant.kind === "enumOption") {
|
|
28215
28372
|
if (declaredEnumOptions === void 0) {
|
|
28216
|
-
return `Parameter '${parameterName}' defaults to enum option '.${constant.optionName}', but its type '${
|
|
28373
|
+
return `Parameter '${parameterName}' defaults to enum option '.${constant.optionName}', but its type '${neoSourceTypeText(type)}' is not an enum.`;
|
|
28217
28374
|
}
|
|
28218
28375
|
if (!declaredEnumOptions.has(constant.optionName)) {
|
|
28219
28376
|
return `Parameter '${parameterName}' defaults to '.${constant.optionName}', which enum '${type.name}' does not declare.`;
|
|
@@ -28222,9 +28379,9 @@ function defaultTypeMismatch(type, constant, enumOptions, parameterName) {
|
|
|
28222
28379
|
}
|
|
28223
28380
|
if (constantKindMatchesPrimitive(type.name, constant.kind)) return null;
|
|
28224
28381
|
if (PRIMITIVE_PARAMETER_TYPES.has(type.name) || declaredEnumOptions !== void 0) {
|
|
28225
|
-
return `Parameter '${parameterName}' default is a ${describeConstant(constant)}, which does not match its declared type '${
|
|
28382
|
+
return `Parameter '${parameterName}' default is a ${describeConstant(constant)}, which does not match its declared type '${neoSourceTypeText(type)}'.`;
|
|
28226
28383
|
}
|
|
28227
|
-
return `Parameter '${parameterName}' of type '${
|
|
28384
|
+
return `Parameter '${parameterName}' of type '${neoSourceTypeText(type)}' can only default to null${type.nullable ? "" : ", and only when the type is nullable"}.`;
|
|
28228
28385
|
}
|
|
28229
28386
|
function constantKindMatchesPrimitive(typeName, kind) {
|
|
28230
28387
|
if (typeName === "bool") return kind === "bool";
|
|
@@ -28240,15 +28397,12 @@ function describeConstant(constant) {
|
|
|
28240
28397
|
if (constant.kind === "int") return "whole-number literal";
|
|
28241
28398
|
return "fractional number literal";
|
|
28242
28399
|
}
|
|
28243
|
-
function formatSourceType(type) {
|
|
28244
|
-
const argumentsText = type.typeArguments.length === 0 ? "" : `<${type.typeArguments.map(formatSourceType).join(", ")}>`;
|
|
28245
|
-
return `${type.name}${argumentsText}${type.nullable ? "?" : ""}`;
|
|
28246
|
-
}
|
|
28247
28400
|
var PARAMETER_DEFAULT_DIAGNOSTIC_CODES, DEFAULT_BEFORE_REQUIRED_PARAMETER, PARAMETER_DEFAULT_TYPE_MISMATCH, NON_CONSTANT_PARAMETER_DEFAULT, PARAMETER_DEFAULT_ON_DEFERRED_FUNCTION, PRIMITIVE_PARAMETER_TYPES;
|
|
28248
28401
|
var init_project_source_parameter_defaults = __esm({
|
|
28249
28402
|
"../packages/neoscript-language/src/project-source-parameter-defaults.ts"() {
|
|
28250
28403
|
"use strict";
|
|
28251
28404
|
init_language_spec();
|
|
28405
|
+
init_project_source_ast();
|
|
28252
28406
|
init_executable_parser();
|
|
28253
28407
|
PARAMETER_DEFAULT_DIAGNOSTIC_CODES = {
|
|
28254
28408
|
defaultBeforeRequiredParameter: "default-before-required-parameter",
|
|
@@ -29955,7 +30109,7 @@ var init_registry = __esm({
|
|
|
29955
30109
|
"../packages/manifest/schema-contract/registry.mjs"() {
|
|
29956
30110
|
"use strict";
|
|
29957
30111
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
29958
|
-
cliVersion: "0.
|
|
30112
|
+
cliVersion: "0.66.0",
|
|
29959
30113
|
projectFileUploadBatchSize: 32,
|
|
29960
30114
|
documentRecords: {
|
|
29961
30115
|
member: {
|
|
@@ -30660,7 +30814,8 @@ var init_registry = __esm({
|
|
|
30660
30814
|
"DialogueMemoryContainer",
|
|
30661
30815
|
"DialoguePriorityDefault",
|
|
30662
30816
|
"PolicyImmutable",
|
|
30663
|
-
"PolicyDeleteBlocked"
|
|
30817
|
+
"PolicyDeleteBlocked",
|
|
30818
|
+
"ScriptRuntime"
|
|
30664
30819
|
],
|
|
30665
30820
|
NeoMemberRequirement: ["Optional", "Required"],
|
|
30666
30821
|
NeoMemberMutability: ["Mutable", "ReadOnly"],
|
|
@@ -34170,7 +34325,8 @@ var init_schema_member = __esm({
|
|
|
34170
34325
|
"dialogueMemoryContainer",
|
|
34171
34326
|
"dialoguePriorityDefault",
|
|
34172
34327
|
"policyImmutable",
|
|
34173
|
-
"policyDeleteBlocked"
|
|
34328
|
+
"policyDeleteBlocked",
|
|
34329
|
+
"scriptRuntime"
|
|
34174
34330
|
]);
|
|
34175
34331
|
worldSystemClassKindSchema = picklist([
|
|
34176
34332
|
"cellPattern",
|
|
@@ -35728,7 +35884,8 @@ function isSchemaSystemMetadata(value) {
|
|
|
35728
35884
|
"dialogueMemoryContainer",
|
|
35729
35885
|
"dialoguePriorityDefault",
|
|
35730
35886
|
"policyImmutable",
|
|
35731
|
-
"policyDeleteBlocked"
|
|
35887
|
+
"policyDeleteBlocked",
|
|
35888
|
+
"scriptRuntime"
|
|
35732
35889
|
]);
|
|
35733
35890
|
const worlds = /* @__PURE__ */ new Set([
|
|
35734
35891
|
"cellPattern",
|
|
@@ -40146,7 +40303,7 @@ function isEpochMillis(value) {
|
|
|
40146
40303
|
return Number.isFinite(value);
|
|
40147
40304
|
}
|
|
40148
40305
|
function isSystemProtectionKind(value) {
|
|
40149
|
-
return value === SystemProtectionKind.WorldAuthoring || value === SystemProtectionKind.DialogueMemorySchema || value === SystemProtectionKind.DialogueMemoryContainer || value === SystemProtectionKind.DialoguePriorityDefault || value === SystemProtectionKind.PolicyImmutable || value === SystemProtectionKind.PolicyDeleteBlocked;
|
|
40306
|
+
return value === SystemProtectionKind.WorldAuthoring || value === SystemProtectionKind.DialogueMemorySchema || value === SystemProtectionKind.DialogueMemoryContainer || value === SystemProtectionKind.DialoguePriorityDefault || value === SystemProtectionKind.PolicyImmutable || value === SystemProtectionKind.PolicyDeleteBlocked || value === SystemProtectionKind.ScriptRuntime;
|
|
40150
40307
|
}
|
|
40151
40308
|
function isSystemMetadata(value) {
|
|
40152
40309
|
const v = value;
|
|
@@ -40190,7 +40347,8 @@ var init_core_types = __esm({
|
|
|
40190
40347
|
DialogueMemoryContainer: "dialogueMemoryContainer",
|
|
40191
40348
|
DialoguePriorityDefault: "dialoguePriorityDefault",
|
|
40192
40349
|
PolicyImmutable: "policyImmutable",
|
|
40193
|
-
PolicyDeleteBlocked: "policyDeleteBlocked"
|
|
40350
|
+
PolicyDeleteBlocked: "policyDeleteBlocked",
|
|
40351
|
+
ScriptRuntime: "scriptRuntime"
|
|
40194
40352
|
};
|
|
40195
40353
|
}
|
|
40196
40354
|
});
|
|
@@ -52216,7 +52374,9 @@ function emitInterface(context, value) {
|
|
|
52216
52374
|
const deferred = member.deferred ? "async " : "";
|
|
52217
52375
|
return `${emitDocsText(member.docsText)}${id(member.id)}${access}${deferred}${renderReturnType(context, member.returnType)} ${member.name}(${member.arguments.map((argument2) => renderParameter(context, argument2)).join(", ")});`;
|
|
52218
52376
|
});
|
|
52219
|
-
|
|
52377
|
+
const system = value.system ? `${systemAnnotation2(value.system)}
|
|
52378
|
+
` : "";
|
|
52379
|
+
return `${emitDocsText(value.docsText)}${id(value.id)}${system}interface ${value.name}${bases.length ? ` : ${bases.join(", ")}` : ""} {
|
|
52220
52380
|
${members.map((member) => indentNeoSourceNonEmptyLines(member, 2)).join("\n\n")}
|
|
52221
52381
|
}
|
|
52222
52382
|
`;
|
|
@@ -52525,7 +52685,7 @@ function renderMemberType(context, member, enclosingClassId, elementSettings = f
|
|
|
52525
52685
|
context,
|
|
52526
52686
|
required(context.members, boundMemberId, "generic binding"),
|
|
52527
52687
|
enclosingClassId
|
|
52528
|
-
)
|
|
52688
|
+
);
|
|
52529
52689
|
});
|
|
52530
52690
|
value = `${schemaClass2.name}${args.length ? `<${args.join(", ")}>` : ""}`;
|
|
52531
52691
|
}
|
|
@@ -65468,13 +65628,11 @@ function classArguments(member, context, seen, genericEnvironment) {
|
|
|
65468
65628
|
if (environmentEntry?.kind === "member") {
|
|
65469
65629
|
const argument3 = analyzerMemberById(context, environmentEntry.memberId);
|
|
65470
65630
|
return argument3 ? [
|
|
65471
|
-
|
|
65472
|
-
|
|
65473
|
-
|
|
65474
|
-
|
|
65475
|
-
|
|
65476
|
-
genericEnvironment
|
|
65477
|
-
)
|
|
65631
|
+
memberRuntimeType(
|
|
65632
|
+
argument3,
|
|
65633
|
+
context,
|
|
65634
|
+
new Set(seen),
|
|
65635
|
+
genericEnvironment
|
|
65478
65636
|
)
|
|
65479
65637
|
] : [];
|
|
65480
65638
|
}
|
|
@@ -65489,13 +65647,11 @@ function classArguments(member, context, seen, genericEnvironment) {
|
|
|
65489
65647
|
}
|
|
65490
65648
|
const argument2 = analyzerMemberById(context, binding.memberId);
|
|
65491
65649
|
return argument2 ? [
|
|
65492
|
-
|
|
65493
|
-
|
|
65494
|
-
|
|
65495
|
-
|
|
65496
|
-
|
|
65497
|
-
genericEnvironment
|
|
65498
|
-
)
|
|
65650
|
+
memberRuntimeType(
|
|
65651
|
+
argument2,
|
|
65652
|
+
context,
|
|
65653
|
+
new Set(seen),
|
|
65654
|
+
genericEnvironment
|
|
65499
65655
|
)
|
|
65500
65656
|
] : [];
|
|
65501
65657
|
});
|
|
@@ -65682,11 +65838,7 @@ function genericConstraintLanguageType(constraint, context, genericEnvironment,
|
|
|
65682
65838
|
];
|
|
65683
65839
|
}
|
|
65684
65840
|
const member = analyzerMemberById(context, binding.memberId);
|
|
65685
|
-
return member ? [
|
|
65686
|
-
requiredType(
|
|
65687
|
-
memberRuntimeType(member, context, /* @__PURE__ */ new Set(), genericEnvironment)
|
|
65688
|
-
)
|
|
65689
|
-
] : [];
|
|
65841
|
+
return member ? [memberRuntimeType(member, context, /* @__PURE__ */ new Set(), genericEnvironment)] : [];
|
|
65690
65842
|
});
|
|
65691
65843
|
return {
|
|
65692
65844
|
kind: "named",
|
|
@@ -109589,6 +109741,14 @@ var init_system_protection = __esm({
|
|
|
109589
109741
|
disallow: [SystemDisallowedOperation.DeleteRecord],
|
|
109590
109742
|
reasonKey: "systemProtection.reasons.policyDeleteBlocked",
|
|
109591
109743
|
serverReason: "System default policy may be edited but must keep one default row."
|
|
109744
|
+
},
|
|
109745
|
+
[SystemProtectionKind.ScriptRuntime]: {
|
|
109746
|
+
disallow: [
|
|
109747
|
+
SystemDisallowedOperation.EditRecord,
|
|
109748
|
+
SystemDisallowedOperation.DeleteRecord
|
|
109749
|
+
],
|
|
109750
|
+
reasonKey: "systemProtection.reasons.scriptRuntime",
|
|
109751
|
+
serverReason: "Lifecycle interface the Neo Compose script runtime calls."
|
|
109592
109752
|
}
|
|
109593
109753
|
};
|
|
109594
109754
|
}
|
|
@@ -127740,7 +127900,7 @@ function recordedStoredConstructorId(value, schemaClass2) {
|
|
|
127740
127900
|
}
|
|
127741
127901
|
function storedConstructorArgumentSource(context, type, value, environment, visited, cloneAggregateArguments = false, partial = false, constructorOwnsGraph = false) {
|
|
127742
127902
|
if (value === null) {
|
|
127743
|
-
if (!type.nullable) {
|
|
127903
|
+
if (!type.nullable && (type.kind !== "generic" || !storedGenericArgumentType(context, type, environment).nullable)) {
|
|
127744
127904
|
throw new Error("Required constructor argument stores null.");
|
|
127745
127905
|
}
|
|
127746
127906
|
return "null";
|
|
@@ -127830,26 +127990,10 @@ function storedConstructorArgumentSource(context, type, value, environment, visi
|
|
|
127830
127990
|
constructorOwnsGraph
|
|
127831
127991
|
);
|
|
127832
127992
|
}
|
|
127833
|
-
case "generic":
|
|
127834
|
-
const bindingId = environment.get(type.genericParamId);
|
|
127835
|
-
const inferredClassId = inferredGenericClassId(bindingId);
|
|
127836
|
-
const resolvedType = inferredClassId === null ? bindingId === void 0 ? null : schemaTypeForBindingMember(context, bindingId, environment) : {
|
|
127837
|
-
kind: "class",
|
|
127838
|
-
nullable: type.nullable,
|
|
127839
|
-
classId: inferredClassId,
|
|
127840
|
-
classArguments: {}
|
|
127841
|
-
};
|
|
127842
|
-
if (resolvedType === null) {
|
|
127843
|
-
throw new Error(
|
|
127844
|
-
`Stored Generic constructor argument cannot resolve parameter ${type.genericParamId}.`
|
|
127845
|
-
);
|
|
127846
|
-
}
|
|
127993
|
+
case "generic":
|
|
127847
127994
|
return storedConstructorArgumentSource(
|
|
127848
127995
|
context,
|
|
127849
|
-
|
|
127850
|
-
resolvedType,
|
|
127851
|
-
type.nullable || resolvedType.nullable
|
|
127852
|
-
),
|
|
127996
|
+
storedGenericArgumentType(context, type, environment),
|
|
127853
127997
|
value,
|
|
127854
127998
|
environment,
|
|
127855
127999
|
visited,
|
|
@@ -127857,7 +128001,6 @@ function storedConstructorArgumentSource(context, type, value, environment, visi
|
|
|
127857
128001
|
partial,
|
|
127858
128002
|
constructorOwnsGraph
|
|
127859
128003
|
);
|
|
127860
|
-
}
|
|
127861
128004
|
case "interface":
|
|
127862
128005
|
case "list":
|
|
127863
128006
|
case "dictionary":
|
|
@@ -127908,6 +128051,25 @@ function storedConstructorArgumentSource(context, type, value, environment, visi
|
|
|
127908
128051
|
);
|
|
127909
128052
|
}
|
|
127910
128053
|
}
|
|
128054
|
+
function storedGenericArgumentType(context, type, environment) {
|
|
128055
|
+
const bindingId = environment.get(type.genericParamId);
|
|
128056
|
+
const inferredClassId = inferredGenericClassId(bindingId);
|
|
128057
|
+
const resolvedType = inferredClassId === null ? bindingId === void 0 ? null : schemaTypeForBindingMember(context, bindingId, environment) : {
|
|
128058
|
+
kind: "class",
|
|
128059
|
+
nullable: type.nullable,
|
|
128060
|
+
classId: inferredClassId,
|
|
128061
|
+
classArguments: {}
|
|
128062
|
+
};
|
|
128063
|
+
if (resolvedType === null) {
|
|
128064
|
+
throw new Error(
|
|
128065
|
+
`Stored Generic constructor argument cannot resolve parameter ${type.genericParamId}.`
|
|
128066
|
+
);
|
|
128067
|
+
}
|
|
128068
|
+
return withSchemaTypeNullability(
|
|
128069
|
+
resolvedType,
|
|
128070
|
+
type.nullable || resolvedType.nullable
|
|
128071
|
+
);
|
|
128072
|
+
}
|
|
127911
128073
|
function schemaTypeForBindingMember(context, memberId, environment, visited = /* @__PURE__ */ new Set()) {
|
|
127912
128074
|
if (visited.has(memberId)) {
|
|
127913
128075
|
throw new Error(
|
|
@@ -128073,6 +128235,10 @@ function storedAggregateReplaySource(context, type, valueId, environment, constr
|
|
|
128073
128235
|
function isSharedConstructorArgument(context, valueId, constructorOwnsGraph) {
|
|
128074
128236
|
return !constructorOwnsGraph && context.readMaterializedGraph().independentlyOwnedValueIds.has(valueId);
|
|
128075
128237
|
}
|
|
128238
|
+
function storedTypeArgumentName(context, type, environment) {
|
|
128239
|
+
const settled = type.kind === "generic" ? storedGenericArgumentType(context, type, environment) : type;
|
|
128240
|
+
return `${storedSchemaTypeName(context, settled, environment)}${settled.nullable ? "?" : ""}`;
|
|
128241
|
+
}
|
|
128076
128242
|
function storedSchemaTypeName(context, type, environment, valueId) {
|
|
128077
128243
|
switch (type.kind) {
|
|
128078
128244
|
case "unknown":
|
|
@@ -128085,7 +128251,7 @@ function storedSchemaTypeName(context, type, environment, valueId) {
|
|
|
128085
128251
|
const argumentsValue = schemaClass2.genericParameters.flatMap(
|
|
128086
128252
|
(parameter4) => {
|
|
128087
128253
|
const argument2 = type.classArguments[parameter4.id];
|
|
128088
|
-
return argument2 === void 0 ? [] : [
|
|
128254
|
+
return argument2 === void 0 ? [] : [storedTypeArgumentName(context, argument2, environment)];
|
|
128089
128255
|
}
|
|
128090
128256
|
);
|
|
128091
128257
|
return `${schemaClass2.name}${argumentsValue.length === 0 ? "" : `<${argumentsValue.join(", ")}>`}`;
|
|
@@ -128113,10 +128279,10 @@ function storedSchemaTypeName(context, type, environment, valueId) {
|
|
|
128113
128279
|
return manifestMemberTypeName(context, member);
|
|
128114
128280
|
}
|
|
128115
128281
|
case "list":
|
|
128116
|
-
return `List<${
|
|
128282
|
+
return `List<${storedTypeArgumentName(context, type.entryType, environment)}>`;
|
|
128117
128283
|
case "dictionary": {
|
|
128118
128284
|
const keyType = type.keyEnumId === null ? "string" : stringField3(context.enums.get(type.keyEnumId) ?? {}, "name");
|
|
128119
|
-
return `Dictionary<${keyType}, ${
|
|
128285
|
+
return `Dictionary<${keyType}, ${storedTypeArgumentName(context, type.entryType, environment)}>`;
|
|
128120
128286
|
}
|
|
128121
128287
|
case "bool":
|
|
128122
128288
|
case "int":
|
|
@@ -128333,10 +128499,13 @@ function classValueTypeName(context, classId, member, environment) {
|
|
|
128333
128499
|
`Stored Class member ${String(member.name ?? member.id)} has no concrete ${parameter4.name} binding.`
|
|
128334
128500
|
);
|
|
128335
128501
|
}
|
|
128336
|
-
return
|
|
128502
|
+
return typeArgumentName(context, bindingMember);
|
|
128337
128503
|
});
|
|
128338
128504
|
return `${name}<${argumentsValue.join(", ")}>`;
|
|
128339
128505
|
}
|
|
128506
|
+
function typeArgumentName(context, member) {
|
|
128507
|
+
return `${manifestMemberTypeName(context, member)}${member.required ? "" : "?"}`;
|
|
128508
|
+
}
|
|
128340
128509
|
function manifestMemberTypeName(context, member) {
|
|
128341
128510
|
if (member.kind === "class") {
|
|
128342
128511
|
const schemaClass2 = context.manifestClasses.get(member.classId);
|
|
@@ -128357,7 +128526,7 @@ function manifestMemberTypeName(context, member) {
|
|
|
128357
128526
|
`Stored generic binding ${binding.memberId} was not pulled.`
|
|
128358
128527
|
);
|
|
128359
128528
|
}
|
|
128360
|
-
return
|
|
128529
|
+
return typeArgumentName(context, argument2);
|
|
128361
128530
|
});
|
|
128362
128531
|
return `${schemaClass2.name}<${argumentsValue.join(", ")}>`;
|
|
128363
128532
|
}
|
|
@@ -142416,6 +142585,260 @@ var init_analyzer = __esm({
|
|
|
142416
142585
|
}
|
|
142417
142586
|
});
|
|
142418
142587
|
|
|
142588
|
+
// ../packages/neoscript-language/src/project-source-lifecycle-editor.ts
|
|
142589
|
+
function projectLifecycleHooks(analysis) {
|
|
142590
|
+
let hooks = PROJECT_LIFECYCLE_HOOKS.get(analysis);
|
|
142591
|
+
if (!hooks) {
|
|
142592
|
+
const interfaces = [];
|
|
142593
|
+
for (const document of analysis.documents.values()) {
|
|
142594
|
+
for (const declaration of document.declarations) {
|
|
142595
|
+
if (declaration.kind === "interface") interfaces.push(declaration);
|
|
142596
|
+
}
|
|
142597
|
+
}
|
|
142598
|
+
hooks = lifecycleHooksByMemberName(interfaces);
|
|
142599
|
+
PROJECT_LIFECYCLE_HOOKS.set(analysis, hooks);
|
|
142600
|
+
}
|
|
142601
|
+
return hooks;
|
|
142602
|
+
}
|
|
142603
|
+
function projectLifecycleQuickFixes(analysis, document, diagnostic, findType) {
|
|
142604
|
+
if (diagnostic.code !== "reserved-lifecycle-member") return [];
|
|
142605
|
+
const source = analysis.documents.get(document.uri);
|
|
142606
|
+
if (!source) return [];
|
|
142607
|
+
for (const declaration of source.declarations) {
|
|
142608
|
+
if (declaration.kind !== "class") continue;
|
|
142609
|
+
const member = declaration.members.find(
|
|
142610
|
+
(candidate) => rangesEqual(candidate.nameRange, diagnostic.range)
|
|
142611
|
+
);
|
|
142612
|
+
if (member?.kind !== "function") continue;
|
|
142613
|
+
const hook = projectLifecycleHooks(analysis).get(member.name.toLowerCase());
|
|
142614
|
+
if (hook === void 0) return [];
|
|
142615
|
+
const text = new SourceText(document.text);
|
|
142616
|
+
const tokens = source.syntax.tokens;
|
|
142617
|
+
const edits = [];
|
|
142618
|
+
if (!classLifecycleContext(declaration, findType).implemented.has(
|
|
142619
|
+
hook.interfaceName
|
|
142620
|
+
)) {
|
|
142621
|
+
edits.push(baseListEdit(text, tokens, declaration, hook.interfaceName));
|
|
142622
|
+
}
|
|
142623
|
+
if (effectiveSourceAccessModifier(member.modifiers, "class") !== "public") {
|
|
142624
|
+
edits.push(publicAccessEdit(text, tokens, member));
|
|
142625
|
+
}
|
|
142626
|
+
if (edits.length === 0) return [];
|
|
142627
|
+
return [
|
|
142628
|
+
{
|
|
142629
|
+
title: `Implement '${hook.interfaceName}'`,
|
|
142630
|
+
kind: "quickfix",
|
|
142631
|
+
diagnostics: [diagnostic],
|
|
142632
|
+
edit: { changes: { [document.uri]: edits } },
|
|
142633
|
+
preferred: true
|
|
142634
|
+
}
|
|
142635
|
+
];
|
|
142636
|
+
}
|
|
142637
|
+
return [];
|
|
142638
|
+
}
|
|
142639
|
+
function lifecycleMemberCompletions(analysis, document, position, findType) {
|
|
142640
|
+
const hooks = projectLifecycleHooks(analysis);
|
|
142641
|
+
if (hooks.size === 0) return [];
|
|
142642
|
+
const source = analysis.documents.get(document.uri);
|
|
142643
|
+
const declaration = source?.declarations.find(
|
|
142644
|
+
(candidate) => candidate.kind === "class" && positionCompare(candidate.range.start, position) < 0 && positionCompare(position, candidate.range.end) < 0
|
|
142645
|
+
);
|
|
142646
|
+
if (!source || source.kind === "flow" || !declaration) return [];
|
|
142647
|
+
const text = new SourceText(document.text);
|
|
142648
|
+
const offset = text.offsetAt(position);
|
|
142649
|
+
const site = memberDeclarationSite(
|
|
142650
|
+
source.syntax.tokens,
|
|
142651
|
+
declaration,
|
|
142652
|
+
text,
|
|
142653
|
+
offset
|
|
142654
|
+
);
|
|
142655
|
+
if (site === null) return [];
|
|
142656
|
+
const own = new Set(
|
|
142657
|
+
declaration.members.map((member) => member.name.toLowerCase())
|
|
142658
|
+
);
|
|
142659
|
+
const context = classLifecycleContext(declaration, findType);
|
|
142660
|
+
const range2 = text.range(site.start, site.end);
|
|
142661
|
+
const typed = document.text.slice(site.start, site.modifiersEnd).trim();
|
|
142662
|
+
const items = [];
|
|
142663
|
+
for (const [key, hook] of hooks) {
|
|
142664
|
+
if (own.has(key)) continue;
|
|
142665
|
+
if (hook.unity && !context.rendersObjects) continue;
|
|
142666
|
+
const inherited = context.inherited.get(key);
|
|
142667
|
+
if (inherited !== void 0 && !isOverridable(inherited)) continue;
|
|
142668
|
+
const name = hook.member.name;
|
|
142669
|
+
const snippet = `public ${inherited === void 0 ? "" : "override "}${hookSignature(hook.member)} {
|
|
142670
|
+
$0
|
|
142671
|
+
}`;
|
|
142672
|
+
items.push({
|
|
142673
|
+
label: name,
|
|
142674
|
+
kind: "method",
|
|
142675
|
+
detail: hook.interfaceName,
|
|
142676
|
+
...hook.docsText === void 0 ? {} : { documentation: hook.docsText.split("\n")[0] },
|
|
142677
|
+
insertText: snippet,
|
|
142678
|
+
insertTextFormat: "snippet",
|
|
142679
|
+
filterText: typed.length === 0 ? name : `${typed} ${name}`,
|
|
142680
|
+
textEdit: { range: range2, newText: snippet },
|
|
142681
|
+
...context.implemented.has(hook.interfaceName) ? {} : {
|
|
142682
|
+
additionalTextEdits: [
|
|
142683
|
+
baseListEdit(
|
|
142684
|
+
text,
|
|
142685
|
+
source.syntax.tokens,
|
|
142686
|
+
declaration,
|
|
142687
|
+
hook.interfaceName
|
|
142688
|
+
)
|
|
142689
|
+
]
|
|
142690
|
+
}
|
|
142691
|
+
});
|
|
142692
|
+
}
|
|
142693
|
+
return items;
|
|
142694
|
+
}
|
|
142695
|
+
function lifecycleHoverMarkdown(analysis, memberName) {
|
|
142696
|
+
const hook = projectLifecycleHooks(analysis).get(memberName.toLowerCase());
|
|
142697
|
+
if (hook === void 0) return "";
|
|
142698
|
+
const docs = hook.docsText === void 0 ? "" : ` ${hook.docsText}`;
|
|
142699
|
+
return `
|
|
142700
|
+
|
|
142701
|
+
Lifecycle hook from \`${hook.interfaceName}\`.${docs}`;
|
|
142702
|
+
}
|
|
142703
|
+
function classLifecycleContext(declaration, findType) {
|
|
142704
|
+
const implemented = /* @__PURE__ */ new Set();
|
|
142705
|
+
const inherited = /* @__PURE__ */ new Map();
|
|
142706
|
+
const pendingInterfaces = [];
|
|
142707
|
+
const visitedClasses = /* @__PURE__ */ new Set();
|
|
142708
|
+
let rendersObjects = false;
|
|
142709
|
+
let current = declaration;
|
|
142710
|
+
while (current !== void 0 && !visitedClasses.has(current.name)) {
|
|
142711
|
+
visitedClasses.add(current.name);
|
|
142712
|
+
if (current.name === NEO_LIFECYCLE_OBJECT_CLASS_NAME) rendersObjects = true;
|
|
142713
|
+
if (current !== declaration) {
|
|
142714
|
+
for (const member of current.members) {
|
|
142715
|
+
const key = member.name.toLowerCase();
|
|
142716
|
+
if (!inherited.has(key)) inherited.set(key, member);
|
|
142717
|
+
}
|
|
142718
|
+
}
|
|
142719
|
+
let next;
|
|
142720
|
+
for (const base of current.baseTypes) {
|
|
142721
|
+
const target = findType(base.name);
|
|
142722
|
+
if (target?.kind === "class") next ??= target;
|
|
142723
|
+
else if (target?.kind === "interface") pendingInterfaces.push(target);
|
|
142724
|
+
}
|
|
142725
|
+
current = next;
|
|
142726
|
+
}
|
|
142727
|
+
while (pendingInterfaces.length > 0) {
|
|
142728
|
+
const target = pendingInterfaces.pop();
|
|
142729
|
+
if (implemented.has(target.name)) continue;
|
|
142730
|
+
implemented.add(target.name);
|
|
142731
|
+
for (const base of target.baseTypes) {
|
|
142732
|
+
const parent = findType(base.name);
|
|
142733
|
+
if (parent?.kind === "interface") pendingInterfaces.push(parent);
|
|
142734
|
+
}
|
|
142735
|
+
}
|
|
142736
|
+
return { implemented, rendersObjects, inherited };
|
|
142737
|
+
}
|
|
142738
|
+
function isOverridable(member) {
|
|
142739
|
+
if (member.modifiers.includes("sealed")) return false;
|
|
142740
|
+
return member.modifiers.includes("virtual") || member.modifiers.includes("abstract") || member.modifiers.includes("override");
|
|
142741
|
+
}
|
|
142742
|
+
function hookSignature(member) {
|
|
142743
|
+
const parameters = member.parameters.map(
|
|
142744
|
+
(parameter4) => `${neoSourceTypeText(parameter4.type)} ${parameter4.name}`
|
|
142745
|
+
).join(", ");
|
|
142746
|
+
return `${neoSourceTypeText(member.type)} ${member.name}(${parameters})`;
|
|
142747
|
+
}
|
|
142748
|
+
function baseListEdit(text, tokens, declaration, interfaceName) {
|
|
142749
|
+
const last = declaration.baseTypes[declaration.baseTypes.length - 1];
|
|
142750
|
+
if (last !== void 0) {
|
|
142751
|
+
const end = declaration.baseTypes.length === 1 && declaration.baseClause ? declaration.baseClause.range.end : last.range.end;
|
|
142752
|
+
const at4 = text.offsetAt(end);
|
|
142753
|
+
return { range: text.range(at4, at4), newText: `, ${interfaceName}` };
|
|
142754
|
+
}
|
|
142755
|
+
const at3 = headerEnd(tokens, text.offsetAt(declaration.nameRange.end));
|
|
142756
|
+
return { range: text.range(at3, at3), newText: ` : ${interfaceName}` };
|
|
142757
|
+
}
|
|
142758
|
+
function headerEnd(tokens, nameEnd) {
|
|
142759
|
+
let end = nameEnd;
|
|
142760
|
+
let depth = 0;
|
|
142761
|
+
for (const token of tokens) {
|
|
142762
|
+
if (token.start < nameEnd || token.kind === "comment") continue;
|
|
142763
|
+
if (token.text === "(") depth += 1;
|
|
142764
|
+
else if (token.text === ")") depth -= 1;
|
|
142765
|
+
else if (depth === 0 && token.text === "{") break;
|
|
142766
|
+
end = token.end;
|
|
142767
|
+
}
|
|
142768
|
+
return end;
|
|
142769
|
+
}
|
|
142770
|
+
function publicAccessEdit(text, tokens, member) {
|
|
142771
|
+
const start = text.offsetAt(member.range.start);
|
|
142772
|
+
const typeStart = text.offsetAt(member.type.range.start);
|
|
142773
|
+
let firstModifier;
|
|
142774
|
+
let depth = 0;
|
|
142775
|
+
for (const token of tokens) {
|
|
142776
|
+
if (token.start < start || token.kind === "comment") continue;
|
|
142777
|
+
if (token.start >= typeStart) break;
|
|
142778
|
+
if (token.text === "(") depth += 1;
|
|
142779
|
+
else if (token.text === ")") depth -= 1;
|
|
142780
|
+
if (depth !== 0 || token.kind !== "keyword") continue;
|
|
142781
|
+
if (isNeoSourceAccessModifier(token.text)) {
|
|
142782
|
+
return { range: token.range, newText: "public" };
|
|
142783
|
+
}
|
|
142784
|
+
firstModifier ??= token;
|
|
142785
|
+
}
|
|
142786
|
+
const at3 = firstModifier?.start ?? typeStart;
|
|
142787
|
+
return { range: text.range(at3, at3), newText: "public " };
|
|
142788
|
+
}
|
|
142789
|
+
function memberDeclarationSite(tokens, declaration, text, offset) {
|
|
142790
|
+
const headerEndOffset = text.offsetAt(
|
|
142791
|
+
declaration.baseClause?.range.end ?? declaration.nameRange.end
|
|
142792
|
+
);
|
|
142793
|
+
const classStart = text.offsetAt(declaration.range.start);
|
|
142794
|
+
const before = [];
|
|
142795
|
+
let depth = 0;
|
|
142796
|
+
for (const token of tokens) {
|
|
142797
|
+
if (token.start < classStart || token.kind === "comment") continue;
|
|
142798
|
+
if (token.kind === "eof" || token.start >= offset) break;
|
|
142799
|
+
before.push(token);
|
|
142800
|
+
if (token.start < headerEndOffset || token.interpolationHole) continue;
|
|
142801
|
+
if (token.text === "{") depth += 1;
|
|
142802
|
+
else if (token.text === "}") depth -= 1;
|
|
142803
|
+
}
|
|
142804
|
+
if (depth !== 1) return null;
|
|
142805
|
+
let index = before.length - 1;
|
|
142806
|
+
let end = offset;
|
|
142807
|
+
let word = before[index];
|
|
142808
|
+
if (word !== void 0 && (word.kind === "identifier" || word.kind === "type") && word.end === offset) {
|
|
142809
|
+
index -= 1;
|
|
142810
|
+
} else {
|
|
142811
|
+
word = void 0;
|
|
142812
|
+
}
|
|
142813
|
+
let start = word?.start ?? offset;
|
|
142814
|
+
const modifiersEnd = start;
|
|
142815
|
+
while (MEMBER_SITE_MODIFIERS.has(before[index]?.text ?? "")) {
|
|
142816
|
+
start = before[index].start;
|
|
142817
|
+
index -= 1;
|
|
142818
|
+
}
|
|
142819
|
+
const boundary = before[index]?.text;
|
|
142820
|
+
if (boundary !== "{" && boundary !== "}" && boundary !== ";") return null;
|
|
142821
|
+
if (word !== void 0) end = word.end;
|
|
142822
|
+
return { start, modifiersEnd, end };
|
|
142823
|
+
}
|
|
142824
|
+
var PROJECT_LIFECYCLE_HOOKS, MEMBER_SITE_MODIFIERS;
|
|
142825
|
+
var init_project_source_lifecycle_editor = __esm({
|
|
142826
|
+
"../packages/neoscript-language/src/project-source-lifecycle-editor.ts"() {
|
|
142827
|
+
"use strict";
|
|
142828
|
+
init_project_source_ast();
|
|
142829
|
+
init_project_source_lifecycle_hooks();
|
|
142830
|
+
init_project_source_tokens();
|
|
142831
|
+
init_source_text();
|
|
142832
|
+
PROJECT_LIFECYCLE_HOOKS = /* @__PURE__ */ new WeakMap();
|
|
142833
|
+
MEMBER_SITE_MODIFIERS = /* @__PURE__ */ new Set([
|
|
142834
|
+
"public",
|
|
142835
|
+
"protected",
|
|
142836
|
+
"private",
|
|
142837
|
+
"override"
|
|
142838
|
+
]);
|
|
142839
|
+
}
|
|
142840
|
+
});
|
|
142841
|
+
|
|
142419
142842
|
// ../packages/neoscript-language/src/quick-fixes.ts
|
|
142420
142843
|
function quickFixFor(document, diagnostic) {
|
|
142421
142844
|
if (diagnostic.code === "missing-semicolon") {
|
|
@@ -142894,6 +143317,16 @@ function projectFallbackCompletions(analysis, document, position) {
|
|
|
142894
143317
|
document,
|
|
142895
143318
|
position
|
|
142896
143319
|
);
|
|
143320
|
+
if (!expression && !classBasePosition) {
|
|
143321
|
+
for (const item of lifecycleMemberCompletions(
|
|
143322
|
+
analysis,
|
|
143323
|
+
document,
|
|
143324
|
+
position,
|
|
143325
|
+
(name) => findTypeDeclaration(analysis, name)
|
|
143326
|
+
)) {
|
|
143327
|
+
items.set(`${item.detail}.${item.label}`, item);
|
|
143328
|
+
}
|
|
143329
|
+
}
|
|
142897
143330
|
const keywords = expression ? afterNew ? [] : ["new"] : typePosition ? [] : [
|
|
142898
143331
|
"class",
|
|
142899
143332
|
"interface",
|
|
@@ -143337,7 +143770,7 @@ function declaredConstructorNamedArguments(analysis, typeName, used) {
|
|
|
143337
143770
|
function parameterArgumentField(parameter4) {
|
|
143338
143771
|
return {
|
|
143339
143772
|
name: parameter4.name,
|
|
143340
|
-
type:
|
|
143773
|
+
type: neoSourceTypeText(parameter4.type),
|
|
143341
143774
|
...parameter4.defaultValue === void 0 ? {} : { defaultText: parameter4.defaultValue.text }
|
|
143342
143775
|
};
|
|
143343
143776
|
}
|
|
@@ -143357,7 +143790,7 @@ function projectInitializerMemberCompletions(analysis, document, position) {
|
|
|
143357
143790
|
const items = unsettled.map((member) => ({
|
|
143358
143791
|
label: member.name,
|
|
143359
143792
|
kind: "property",
|
|
143360
|
-
detail: `${
|
|
143793
|
+
detail: `${neoSourceTypeText(member.member.type)} \u2014 required`,
|
|
143361
143794
|
insertText: `${member.name} = `,
|
|
143362
143795
|
// Required members sort ahead of defaulted ones: they are the only entries
|
|
143363
143796
|
// whose absence is a diagnostic.
|
|
@@ -143368,7 +143801,7 @@ function projectInitializerMemberCompletions(analysis, document, position) {
|
|
|
143368
143801
|
items.push({
|
|
143369
143802
|
label: member.name,
|
|
143370
143803
|
kind: "property",
|
|
143371
|
-
detail:
|
|
143804
|
+
detail: neoSourceTypeText(member.type),
|
|
143372
143805
|
insertText: `${member.name} = `,
|
|
143373
143806
|
sortText: `1${member.name}`
|
|
143374
143807
|
});
|
|
@@ -143406,10 +143839,6 @@ function functionParameterLabel(parameter4) {
|
|
|
143406
143839
|
const suffix = parameter4.defaultValue === void 0 ? "" : ` = ${parameter4.defaultValue.text}`;
|
|
143407
143840
|
return `${parameter4.type.name} ${parameter4.name}${suffix}`;
|
|
143408
143841
|
}
|
|
143409
|
-
function sourceTypeText(type) {
|
|
143410
|
-
const args = type.typeArguments.length > 0 ? `<${type.typeArguments.map(sourceTypeText).join(", ")}>` : "";
|
|
143411
|
-
return `${type.name}${args}${type.nullable ? "?" : ""}`;
|
|
143412
|
-
}
|
|
143413
143842
|
function projectConstructionIndex(analysis) {
|
|
143414
143843
|
const cached = CONSTRUCTION_INDEX_CACHE.get(analysis);
|
|
143415
143844
|
if (cached) return cached;
|
|
@@ -143687,9 +144116,10 @@ ${resolved.symbol.documentation}` : "";
|
|
|
143687
144116
|
ID: \`${resolved.symbol.id}\`` : "\n\nPending ID";
|
|
143688
144117
|
const detail = resolved.symbol.detail ? `: \`${resolved.symbol.detail}\`` : "";
|
|
143689
144118
|
const contract = resolved.symbol.kind === "class" ? projectConstructionContractMarkdown(analysis, resolved.symbol.name) : "";
|
|
144119
|
+
const lifecycle = resolved.symbol.kind === "member" && resolved.symbol.callable === true && resolved.symbol.static !== true && analysis.documents.get(resolved.symbol.location.uri)?.kind !== "flow" ? lifecycleHoverMarkdown(analysis, resolved.symbol.name) : "";
|
|
143690
144120
|
return {
|
|
143691
144121
|
range: resolved.token.range,
|
|
143692
|
-
markdown: `**${resolved.symbol.kind}** \`${resolved.symbol.name}\`${detail}${owner}${documentation}${contract}${id2}`
|
|
144122
|
+
markdown: `**${resolved.symbol.kind}** \`${resolved.symbol.name}\`${detail}${owner}${documentation}${lifecycle}${contract}${id2}`
|
|
143693
144123
|
};
|
|
143694
144124
|
}
|
|
143695
144125
|
function projectBuiltinSymbolAt(document, position) {
|
|
@@ -143730,7 +144160,7 @@ Construct with \`new(${parameters})\` \u2014 this class declares a required cons
|
|
|
143730
144160
|
const lines = [];
|
|
143731
144161
|
if (required2.length > 0) {
|
|
143732
144162
|
const members = required2.map(
|
|
143733
|
-
(member) => `\`${
|
|
144163
|
+
(member) => `\`${neoSourceTypeText(member.member.type)} ${member.name}\``
|
|
143734
144164
|
).join(", ");
|
|
143735
144165
|
lines.push(`Every construction path must settle ${members}.`);
|
|
143736
144166
|
}
|
|
@@ -144894,7 +145324,7 @@ function declarationConstructorParameters(declaration) {
|
|
|
144894
145324
|
}
|
|
144895
145325
|
function sourceParameterProjection(parameter4) {
|
|
144896
145326
|
return {
|
|
144897
|
-
type:
|
|
145327
|
+
type: neoSourceTypeText(parameter4.type),
|
|
144898
145328
|
name: parameter4.name,
|
|
144899
145329
|
...parameter4.defaultValue === void 0 ? {} : { defaultText: parameter4.defaultValue.text }
|
|
144900
145330
|
};
|
|
@@ -145005,6 +145435,8 @@ var init_project_source_language_features = __esm({
|
|
|
145005
145435
|
init_language_spec();
|
|
145006
145436
|
init_project_source_semantics();
|
|
145007
145437
|
init_project_source_variants();
|
|
145438
|
+
init_project_source_lifecycle_editor();
|
|
145439
|
+
init_project_source_ast();
|
|
145008
145440
|
init_project();
|
|
145009
145441
|
init_project_source_semantics();
|
|
145010
145442
|
init_project_source_settlement();
|
|
@@ -145126,7 +145558,7 @@ function localValueRefactorings(analysis, document, range2) {
|
|
|
145126
145558
|
start: { line: 0, character: 0 },
|
|
145127
145559
|
end: { line: 0, character: 0 }
|
|
145128
145560
|
},
|
|
145129
|
-
newText: `${
|
|
145561
|
+
newText: `${neoSourceTypeText(type)} ${name} = ${selected};
|
|
145130
145562
|
`
|
|
145131
145563
|
}
|
|
145132
145564
|
]
|
|
@@ -145135,9 +145567,6 @@ function localValueRefactorings(analysis, document, range2) {
|
|
|
145135
145567
|
}
|
|
145136
145568
|
];
|
|
145137
145569
|
}
|
|
145138
|
-
function typeText2(type) {
|
|
145139
|
-
return type.name + (type.typeArguments.length === 0 ? "" : `<${type.typeArguments.map(typeText2).join(", ")}>`) + (type.nullable ? "?" : "");
|
|
145140
|
-
}
|
|
145141
145570
|
function withoutValueIdentities(text) {
|
|
145142
145571
|
const tokens = lex(text).roots.filter((token) => token.kind !== "comment");
|
|
145143
145572
|
const removals = [];
|
|
@@ -145214,6 +145643,7 @@ var init_project_local_value_refactorings = __esm({
|
|
|
145214
145643
|
init_project_local_values();
|
|
145215
145644
|
init_project_source_language_features();
|
|
145216
145645
|
init_source_text();
|
|
145646
|
+
init_project_source_ast();
|
|
145217
145647
|
}
|
|
145218
145648
|
});
|
|
145219
145649
|
|
|
@@ -146142,6 +146572,7 @@ var init_service = __esm({
|
|
|
146142
146572
|
init_project_source_identifiers();
|
|
146143
146573
|
init_project_source_analysis();
|
|
146144
146574
|
init_project_source_construction_quick_fixes();
|
|
146575
|
+
init_project_source_lifecycle_editor();
|
|
146145
146576
|
init_project_source_reference_family();
|
|
146146
146577
|
init_project_source_language_features();
|
|
146147
146578
|
init_project_source_tokens();
|
|
@@ -146459,6 +146890,14 @@ var init_service = __esm({
|
|
|
146459
146890
|
actions.push(
|
|
146460
146891
|
...projectConstructionQuickFixes(project, state.document, diagnostic)
|
|
146461
146892
|
);
|
|
146893
|
+
actions.push(
|
|
146894
|
+
...projectLifecycleQuickFixes(
|
|
146895
|
+
project,
|
|
146896
|
+
state.document,
|
|
146897
|
+
diagnostic,
|
|
146898
|
+
(name) => findTypeDeclaration(project, name)
|
|
146899
|
+
)
|
|
146900
|
+
);
|
|
146462
146901
|
}
|
|
146463
146902
|
actions.push(...spellingQuickFixes(state.document, diagnostic));
|
|
146464
146903
|
const edit = quickFixFor(state.document, diagnostic);
|
|
@@ -156205,7 +156644,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
156205
156644
|
async function main() {
|
|
156206
156645
|
const args = parseArgs(process.argv.slice(2));
|
|
156207
156646
|
if (args.command === "--version") {
|
|
156208
|
-
console.log("0.
|
|
156647
|
+
console.log("0.66.0");
|
|
156209
156648
|
return;
|
|
156210
156649
|
}
|
|
156211
156650
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/dist/test-worker.mjs
CHANGED
|
@@ -2124,7 +2124,8 @@ var SystemProtectionKind = {
|
|
|
2124
2124
|
DialogueMemoryContainer: "dialogueMemoryContainer",
|
|
2125
2125
|
DialoguePriorityDefault: "dialoguePriorityDefault",
|
|
2126
2126
|
PolicyImmutable: "policyImmutable",
|
|
2127
|
-
PolicyDeleteBlocked: "policyDeleteBlocked"
|
|
2127
|
+
PolicyDeleteBlocked: "policyDeleteBlocked",
|
|
2128
|
+
ScriptRuntime: "scriptRuntime"
|
|
2128
2129
|
};
|
|
2129
2130
|
function isWithId(value) {
|
|
2130
2131
|
return typeof value?.id === "string";
|
|
@@ -2141,7 +2142,7 @@ function isEpochMillis(value) {
|
|
|
2141
2142
|
return Number.isFinite(value);
|
|
2142
2143
|
}
|
|
2143
2144
|
function isSystemProtectionKind(value) {
|
|
2144
|
-
return value === SystemProtectionKind.WorldAuthoring || value === SystemProtectionKind.DialogueMemorySchema || value === SystemProtectionKind.DialogueMemoryContainer || value === SystemProtectionKind.DialoguePriorityDefault || value === SystemProtectionKind.PolicyImmutable || value === SystemProtectionKind.PolicyDeleteBlocked;
|
|
2145
|
+
return value === SystemProtectionKind.WorldAuthoring || value === SystemProtectionKind.DialogueMemorySchema || value === SystemProtectionKind.DialogueMemoryContainer || value === SystemProtectionKind.DialoguePriorityDefault || value === SystemProtectionKind.PolicyImmutable || value === SystemProtectionKind.PolicyDeleteBlocked || value === SystemProtectionKind.ScriptRuntime;
|
|
2145
2146
|
}
|
|
2146
2147
|
function isSystemMetadata(value) {
|
|
2147
2148
|
const v = value;
|
|
@@ -40639,13 +40640,11 @@ function classArguments(member, context, seen, genericEnvironment) {
|
|
|
40639
40640
|
if (environmentEntry?.kind === "member") {
|
|
40640
40641
|
const argument3 = analyzerMemberById(context, environmentEntry.memberId);
|
|
40641
40642
|
return argument3 ? [
|
|
40642
|
-
|
|
40643
|
-
|
|
40644
|
-
|
|
40645
|
-
|
|
40646
|
-
|
|
40647
|
-
genericEnvironment
|
|
40648
|
-
)
|
|
40643
|
+
memberRuntimeType(
|
|
40644
|
+
argument3,
|
|
40645
|
+
context,
|
|
40646
|
+
new Set(seen),
|
|
40647
|
+
genericEnvironment
|
|
40649
40648
|
)
|
|
40650
40649
|
] : [];
|
|
40651
40650
|
}
|
|
@@ -40660,13 +40659,11 @@ function classArguments(member, context, seen, genericEnvironment) {
|
|
|
40660
40659
|
}
|
|
40661
40660
|
const argument2 = analyzerMemberById(context, binding.memberId);
|
|
40662
40661
|
return argument2 ? [
|
|
40663
|
-
|
|
40664
|
-
|
|
40665
|
-
|
|
40666
|
-
|
|
40667
|
-
|
|
40668
|
-
genericEnvironment
|
|
40669
|
-
)
|
|
40662
|
+
memberRuntimeType(
|
|
40663
|
+
argument2,
|
|
40664
|
+
context,
|
|
40665
|
+
new Set(seen),
|
|
40666
|
+
genericEnvironment
|
|
40670
40667
|
)
|
|
40671
40668
|
] : [];
|
|
40672
40669
|
});
|
|
@@ -40853,11 +40850,7 @@ function genericConstraintLanguageType(constraint, context, genericEnvironment,
|
|
|
40853
40850
|
];
|
|
40854
40851
|
}
|
|
40855
40852
|
const member = analyzerMemberById(context, binding.memberId);
|
|
40856
|
-
return member ? [
|
|
40857
|
-
requiredType(
|
|
40858
|
-
memberRuntimeType(member, context, /* @__PURE__ */ new Set(), genericEnvironment)
|
|
40859
|
-
)
|
|
40860
|
-
] : [];
|
|
40853
|
+
return member ? [memberRuntimeType(member, context, /* @__PURE__ */ new Set(), genericEnvironment)] : [];
|
|
40861
40854
|
});
|
|
40862
40855
|
return {
|
|
40863
40856
|
kind: "named",
|
|
@@ -44843,6 +44836,14 @@ var SYSTEM_PROTECTION_RULES = {
|
|
|
44843
44836
|
disallow: [SystemDisallowedOperation.DeleteRecord],
|
|
44844
44837
|
reasonKey: "systemProtection.reasons.policyDeleteBlocked",
|
|
44845
44838
|
serverReason: "System default policy may be edited but must keep one default row."
|
|
44839
|
+
},
|
|
44840
|
+
[SystemProtectionKind.ScriptRuntime]: {
|
|
44841
|
+
disallow: [
|
|
44842
|
+
SystemDisallowedOperation.EditRecord,
|
|
44843
|
+
SystemDisallowedOperation.DeleteRecord
|
|
44844
|
+
],
|
|
44845
|
+
reasonKey: "systemProtection.reasons.scriptRuntime",
|
|
44846
|
+
serverReason: "Lifecycle interface the Neo Compose script runtime calls."
|
|
44846
44847
|
}
|
|
44847
44848
|
};
|
|
44848
44849
|
|
|
@@ -46088,7 +46089,8 @@ function isSchemaSystemMetadata(value) {
|
|
|
46088
46089
|
"dialogueMemoryContainer",
|
|
46089
46090
|
"dialoguePriorityDefault",
|
|
46090
46091
|
"policyImmutable",
|
|
46091
|
-
"policyDeleteBlocked"
|
|
46092
|
+
"policyDeleteBlocked",
|
|
46093
|
+
"scriptRuntime"
|
|
46092
46094
|
]);
|
|
46093
46095
|
const worlds = /* @__PURE__ */ new Set([
|
|
46094
46096
|
"cellPattern",
|
package/package.json
CHANGED
|
@@ -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.
|
|
113
|
+
<!-- reviewed-through-cli: 0.66.0 -->
|
|
114
114
|
```
|
|
115
115
|
|
|
116
116
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -197,6 +197,16 @@ itself; both are durable writes deduplicated by target identity, so
|
|
|
197
197
|
re-running a subscription cannot double-subscribe. Invoke it as a statement —
|
|
198
198
|
an action is never a value, never a return type, and never assigned with `=`.
|
|
199
199
|
|
|
200
|
+
Implement a system lifecycle interface to run code when the runtime does.
|
|
201
|
+
`INeoOnLoad` and `INeoOnUnload` run when an instance becomes live and when it
|
|
202
|
+
stops being live. The `INeoUnity*` interfaces, such as `INeoUnityUpdate` and
|
|
203
|
+
`INeoUnityOnTriggerEnter2D`, run for a rendered `NeoObjectBase` in play mode.
|
|
204
|
+
Their member names, such as `OnLoad` and `Update`, are reserved: declare one
|
|
205
|
+
only as the public, immediate instance method that implements its interface,
|
|
206
|
+
and never mark it `@effect`. Subscribe Session actions in `OnLoad` and remove
|
|
207
|
+
them in `OnUnload`. React to data changes with `@effect`, and keep `Update`
|
|
208
|
+
for work that really happens every frame.
|
|
209
|
+
|
|
200
210
|
Keep generic project relations as typed top-level declarations in
|
|
201
211
|
`Relations.neo`. Let the compiler derive identities for owned descriptors and
|
|
202
212
|
concrete generic bindings.
|