@neocompose/cli 0.65.1 → 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 +7 -0
- package/dist/neo.mjs +471 -33
- package/dist/test-worker.mjs +13 -3
- 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,12 @@
|
|
|
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
|
+
|
|
3
10
|
## [0.65.1] - 2026-10-03
|
|
4
11
|
|
|
5
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".
|
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
|
`;
|
|
@@ -109581,6 +109741,14 @@ var init_system_protection = __esm({
|
|
|
109581
109741
|
disallow: [SystemDisallowedOperation.DeleteRecord],
|
|
109582
109742
|
reasonKey: "systemProtection.reasons.policyDeleteBlocked",
|
|
109583
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."
|
|
109584
109752
|
}
|
|
109585
109753
|
};
|
|
109586
109754
|
}
|
|
@@ -142417,6 +142585,260 @@ var init_analyzer = __esm({
|
|
|
142417
142585
|
}
|
|
142418
142586
|
});
|
|
142419
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
|
+
|
|
142420
142842
|
// ../packages/neoscript-language/src/quick-fixes.ts
|
|
142421
142843
|
function quickFixFor(document, diagnostic) {
|
|
142422
142844
|
if (diagnostic.code === "missing-semicolon") {
|
|
@@ -142895,6 +143317,16 @@ function projectFallbackCompletions(analysis, document, position) {
|
|
|
142895
143317
|
document,
|
|
142896
143318
|
position
|
|
142897
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
|
+
}
|
|
142898
143330
|
const keywords = expression ? afterNew ? [] : ["new"] : typePosition ? [] : [
|
|
142899
143331
|
"class",
|
|
142900
143332
|
"interface",
|
|
@@ -143338,7 +143770,7 @@ function declaredConstructorNamedArguments(analysis, typeName, used) {
|
|
|
143338
143770
|
function parameterArgumentField(parameter4) {
|
|
143339
143771
|
return {
|
|
143340
143772
|
name: parameter4.name,
|
|
143341
|
-
type:
|
|
143773
|
+
type: neoSourceTypeText(parameter4.type),
|
|
143342
143774
|
...parameter4.defaultValue === void 0 ? {} : { defaultText: parameter4.defaultValue.text }
|
|
143343
143775
|
};
|
|
143344
143776
|
}
|
|
@@ -143358,7 +143790,7 @@ function projectInitializerMemberCompletions(analysis, document, position) {
|
|
|
143358
143790
|
const items = unsettled.map((member) => ({
|
|
143359
143791
|
label: member.name,
|
|
143360
143792
|
kind: "property",
|
|
143361
|
-
detail: `${
|
|
143793
|
+
detail: `${neoSourceTypeText(member.member.type)} \u2014 required`,
|
|
143362
143794
|
insertText: `${member.name} = `,
|
|
143363
143795
|
// Required members sort ahead of defaulted ones: they are the only entries
|
|
143364
143796
|
// whose absence is a diagnostic.
|
|
@@ -143369,7 +143801,7 @@ function projectInitializerMemberCompletions(analysis, document, position) {
|
|
|
143369
143801
|
items.push({
|
|
143370
143802
|
label: member.name,
|
|
143371
143803
|
kind: "property",
|
|
143372
|
-
detail:
|
|
143804
|
+
detail: neoSourceTypeText(member.type),
|
|
143373
143805
|
insertText: `${member.name} = `,
|
|
143374
143806
|
sortText: `1${member.name}`
|
|
143375
143807
|
});
|
|
@@ -143407,10 +143839,6 @@ function functionParameterLabel(parameter4) {
|
|
|
143407
143839
|
const suffix = parameter4.defaultValue === void 0 ? "" : ` = ${parameter4.defaultValue.text}`;
|
|
143408
143840
|
return `${parameter4.type.name} ${parameter4.name}${suffix}`;
|
|
143409
143841
|
}
|
|
143410
|
-
function sourceTypeText(type) {
|
|
143411
|
-
const args = type.typeArguments.length > 0 ? `<${type.typeArguments.map(sourceTypeText).join(", ")}>` : "";
|
|
143412
|
-
return `${type.name}${args}${type.nullable ? "?" : ""}`;
|
|
143413
|
-
}
|
|
143414
143842
|
function projectConstructionIndex(analysis) {
|
|
143415
143843
|
const cached = CONSTRUCTION_INDEX_CACHE.get(analysis);
|
|
143416
143844
|
if (cached) return cached;
|
|
@@ -143688,9 +144116,10 @@ ${resolved.symbol.documentation}` : "";
|
|
|
143688
144116
|
ID: \`${resolved.symbol.id}\`` : "\n\nPending ID";
|
|
143689
144117
|
const detail = resolved.symbol.detail ? `: \`${resolved.symbol.detail}\`` : "";
|
|
143690
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) : "";
|
|
143691
144120
|
return {
|
|
143692
144121
|
range: resolved.token.range,
|
|
143693
|
-
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}`
|
|
143694
144123
|
};
|
|
143695
144124
|
}
|
|
143696
144125
|
function projectBuiltinSymbolAt(document, position) {
|
|
@@ -143731,7 +144160,7 @@ Construct with \`new(${parameters})\` \u2014 this class declares a required cons
|
|
|
143731
144160
|
const lines = [];
|
|
143732
144161
|
if (required2.length > 0) {
|
|
143733
144162
|
const members = required2.map(
|
|
143734
|
-
(member) => `\`${
|
|
144163
|
+
(member) => `\`${neoSourceTypeText(member.member.type)} ${member.name}\``
|
|
143735
144164
|
).join(", ");
|
|
143736
144165
|
lines.push(`Every construction path must settle ${members}.`);
|
|
143737
144166
|
}
|
|
@@ -144895,7 +145324,7 @@ function declarationConstructorParameters(declaration) {
|
|
|
144895
145324
|
}
|
|
144896
145325
|
function sourceParameterProjection(parameter4) {
|
|
144897
145326
|
return {
|
|
144898
|
-
type:
|
|
145327
|
+
type: neoSourceTypeText(parameter4.type),
|
|
144899
145328
|
name: parameter4.name,
|
|
144900
145329
|
...parameter4.defaultValue === void 0 ? {} : { defaultText: parameter4.defaultValue.text }
|
|
144901
145330
|
};
|
|
@@ -145006,6 +145435,8 @@ var init_project_source_language_features = __esm({
|
|
|
145006
145435
|
init_language_spec();
|
|
145007
145436
|
init_project_source_semantics();
|
|
145008
145437
|
init_project_source_variants();
|
|
145438
|
+
init_project_source_lifecycle_editor();
|
|
145439
|
+
init_project_source_ast();
|
|
145009
145440
|
init_project();
|
|
145010
145441
|
init_project_source_semantics();
|
|
145011
145442
|
init_project_source_settlement();
|
|
@@ -145127,7 +145558,7 @@ function localValueRefactorings(analysis, document, range2) {
|
|
|
145127
145558
|
start: { line: 0, character: 0 },
|
|
145128
145559
|
end: { line: 0, character: 0 }
|
|
145129
145560
|
},
|
|
145130
|
-
newText: `${
|
|
145561
|
+
newText: `${neoSourceTypeText(type)} ${name} = ${selected};
|
|
145131
145562
|
`
|
|
145132
145563
|
}
|
|
145133
145564
|
]
|
|
@@ -145136,9 +145567,6 @@ function localValueRefactorings(analysis, document, range2) {
|
|
|
145136
145567
|
}
|
|
145137
145568
|
];
|
|
145138
145569
|
}
|
|
145139
|
-
function typeText2(type) {
|
|
145140
|
-
return type.name + (type.typeArguments.length === 0 ? "" : `<${type.typeArguments.map(typeText2).join(", ")}>`) + (type.nullable ? "?" : "");
|
|
145141
|
-
}
|
|
145142
145570
|
function withoutValueIdentities(text) {
|
|
145143
145571
|
const tokens = lex(text).roots.filter((token) => token.kind !== "comment");
|
|
145144
145572
|
const removals = [];
|
|
@@ -145215,6 +145643,7 @@ var init_project_local_value_refactorings = __esm({
|
|
|
145215
145643
|
init_project_local_values();
|
|
145216
145644
|
init_project_source_language_features();
|
|
145217
145645
|
init_source_text();
|
|
145646
|
+
init_project_source_ast();
|
|
145218
145647
|
}
|
|
145219
145648
|
});
|
|
145220
145649
|
|
|
@@ -146143,6 +146572,7 @@ var init_service = __esm({
|
|
|
146143
146572
|
init_project_source_identifiers();
|
|
146144
146573
|
init_project_source_analysis();
|
|
146145
146574
|
init_project_source_construction_quick_fixes();
|
|
146575
|
+
init_project_source_lifecycle_editor();
|
|
146146
146576
|
init_project_source_reference_family();
|
|
146147
146577
|
init_project_source_language_features();
|
|
146148
146578
|
init_project_source_tokens();
|
|
@@ -146460,6 +146890,14 @@ var init_service = __esm({
|
|
|
146460
146890
|
actions.push(
|
|
146461
146891
|
...projectConstructionQuickFixes(project, state.document, diagnostic)
|
|
146462
146892
|
);
|
|
146893
|
+
actions.push(
|
|
146894
|
+
...projectLifecycleQuickFixes(
|
|
146895
|
+
project,
|
|
146896
|
+
state.document,
|
|
146897
|
+
diagnostic,
|
|
146898
|
+
(name) => findTypeDeclaration(project, name)
|
|
146899
|
+
)
|
|
146900
|
+
);
|
|
146463
146901
|
}
|
|
146464
146902
|
actions.push(...spellingQuickFixes(state.document, diagnostic));
|
|
146465
146903
|
const edit = quickFixFor(state.document, diagnostic);
|
|
@@ -156206,7 +156644,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
156206
156644
|
async function main() {
|
|
156207
156645
|
const args = parseArgs(process.argv.slice(2));
|
|
156208
156646
|
if (args.command === "--version") {
|
|
156209
|
-
console.log("0.
|
|
156647
|
+
console.log("0.66.0");
|
|
156210
156648
|
return;
|
|
156211
156649
|
}
|
|
156212
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;
|
|
@@ -44835,6 +44836,14 @@ var SYSTEM_PROTECTION_RULES = {
|
|
|
44835
44836
|
disallow: [SystemDisallowedOperation.DeleteRecord],
|
|
44836
44837
|
reasonKey: "systemProtection.reasons.policyDeleteBlocked",
|
|
44837
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."
|
|
44838
44847
|
}
|
|
44839
44848
|
};
|
|
44840
44849
|
|
|
@@ -46080,7 +46089,8 @@ function isSchemaSystemMetadata(value) {
|
|
|
46080
46089
|
"dialogueMemoryContainer",
|
|
46081
46090
|
"dialoguePriorityDefault",
|
|
46082
46091
|
"policyImmutable",
|
|
46083
|
-
"policyDeleteBlocked"
|
|
46092
|
+
"policyDeleteBlocked",
|
|
46093
|
+
"scriptRuntime"
|
|
46084
46094
|
]);
|
|
46085
46095
|
const worlds = /* @__PURE__ */ new Set([
|
|
46086
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.
|