@neocompose/cli 0.32.0 → 0.32.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.32.2] - 2026-08-18
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Preserve abstract NeoScript functions as `NSFunction` declarations when
|
|
8
|
+
lowering prospective project candidates, so concrete overrides inherit their
|
|
9
|
+
signature during `neo test` and push validation.
|
|
10
|
+
|
|
11
|
+
## [0.32.1] - 2026-08-18
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Lower typed NeoScript setters through the same shared accessor parser used
|
|
16
|
+
by source-body compilation, so `neo test`, animation validation, and
|
|
17
|
+
initializer replay retain property writability in prospective candidates.
|
|
18
|
+
|
|
3
19
|
## [0.32.0] - 2026-08-18
|
|
4
20
|
|
|
5
21
|
### Added
|
package/dist/neo.mjs
CHANGED
|
@@ -24057,6 +24057,74 @@ var init_project_source_semantics = __esm({
|
|
|
24057
24057
|
}
|
|
24058
24058
|
});
|
|
24059
24059
|
|
|
24060
|
+
// ../packages/neoscript-language/src/project-source-accessors.ts
|
|
24061
|
+
function findProjectSourceAccessorBody(source, keyword, containingRange) {
|
|
24062
|
+
if (source.length === 0) return null;
|
|
24063
|
+
const full = new SourceText(source);
|
|
24064
|
+
const range2 = containingRange ?? full.fullRange();
|
|
24065
|
+
const bodyStart = full.offsetAt(range2.start);
|
|
24066
|
+
const bodyEnd = full.offsetAt(range2.end);
|
|
24067
|
+
const body = source.slice(bodyStart, bodyEnd);
|
|
24068
|
+
const local = new SourceText(body);
|
|
24069
|
+
const tokens = lex2(body);
|
|
24070
|
+
let depth = 0;
|
|
24071
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
24072
|
+
const token = tokens[index];
|
|
24073
|
+
if (token.text === "{") {
|
|
24074
|
+
depth++;
|
|
24075
|
+
continue;
|
|
24076
|
+
}
|
|
24077
|
+
if (token.text === "}") {
|
|
24078
|
+
depth--;
|
|
24079
|
+
continue;
|
|
24080
|
+
}
|
|
24081
|
+
if (depth !== 1 || token.text !== keyword) continue;
|
|
24082
|
+
let openIndex = index + 1;
|
|
24083
|
+
if (tokens[openIndex]?.text === "(") {
|
|
24084
|
+
let parameterDepth = 1;
|
|
24085
|
+
for (let cursor = openIndex + 1; cursor < tokens.length; cursor++) {
|
|
24086
|
+
const candidate = tokens[cursor];
|
|
24087
|
+
if (candidate.text === "(") parameterDepth++;
|
|
24088
|
+
if (candidate.text === ")") parameterDepth--;
|
|
24089
|
+
if (parameterDepth !== 0) continue;
|
|
24090
|
+
openIndex = cursor + 1;
|
|
24091
|
+
break;
|
|
24092
|
+
}
|
|
24093
|
+
if (parameterDepth !== 0) return null;
|
|
24094
|
+
}
|
|
24095
|
+
const open = tokens[openIndex];
|
|
24096
|
+
if (open?.text !== "{") return null;
|
|
24097
|
+
let accessorDepth = 1;
|
|
24098
|
+
for (let cursor = openIndex + 1; cursor < tokens.length; cursor++) {
|
|
24099
|
+
const candidate = tokens[cursor];
|
|
24100
|
+
if (candidate.text === "{") accessorDepth++;
|
|
24101
|
+
if (candidate.text === "}") accessorDepth--;
|
|
24102
|
+
if (accessorDepth !== 0) continue;
|
|
24103
|
+
const start = bodyStart + sourceOffset2(local, open.pos) + 1;
|
|
24104
|
+
const end = bodyStart + sourceOffset2(local, candidate.pos);
|
|
24105
|
+
return {
|
|
24106
|
+
range: full.range(start, end),
|
|
24107
|
+
source: source.slice(start, end)
|
|
24108
|
+
};
|
|
24109
|
+
}
|
|
24110
|
+
return null;
|
|
24111
|
+
}
|
|
24112
|
+
return null;
|
|
24113
|
+
}
|
|
24114
|
+
function sourceOffset2(source, position) {
|
|
24115
|
+
return source.offsetAt({
|
|
24116
|
+
line: Math.max(0, position.line - 1),
|
|
24117
|
+
character: Math.max(0, position.column - 1)
|
|
24118
|
+
});
|
|
24119
|
+
}
|
|
24120
|
+
var init_project_source_accessors = __esm({
|
|
24121
|
+
"../packages/neoscript-language/src/project-source-accessors.ts"() {
|
|
24122
|
+
"use strict";
|
|
24123
|
+
init_source_text();
|
|
24124
|
+
init_strict_lexer();
|
|
24125
|
+
}
|
|
24126
|
+
});
|
|
24127
|
+
|
|
24060
24128
|
// ../packages/neoscript-language/src/project-source-script-compiler.ts
|
|
24061
24129
|
function isPrimitiveName(name) {
|
|
24062
24130
|
return PRIMITIVE_NAMES.has(name);
|
|
@@ -24198,11 +24266,11 @@ function compileProjectSourceBodies(documents) {
|
|
|
24198
24266
|
}
|
|
24199
24267
|
if (member.kind !== "property") continue;
|
|
24200
24268
|
for (const unit of ["getter", "setter"]) {
|
|
24201
|
-
const range2 =
|
|
24269
|
+
const range2 = findProjectSourceAccessorBody(
|
|
24202
24270
|
document.sourceText,
|
|
24203
|
-
|
|
24204
|
-
|
|
24205
|
-
);
|
|
24271
|
+
unit === "getter" ? "get" : "set",
|
|
24272
|
+
member.body.range
|
|
24273
|
+
)?.range;
|
|
24206
24274
|
if (!range2) continue;
|
|
24207
24275
|
compileBody({
|
|
24208
24276
|
uri,
|
|
@@ -24560,7 +24628,7 @@ function sourceMemberSymbol(member, owner, typeIds, source) {
|
|
|
24560
24628
|
};
|
|
24561
24629
|
}
|
|
24562
24630
|
if (member.kind === "property") {
|
|
24563
|
-
const hasSetter =
|
|
24631
|
+
const hasSetter = findProjectSourceAccessorBody(source, "set", member.body.range) !== null || /\bset\s*;/.test(member.body.text);
|
|
24564
24632
|
return {
|
|
24565
24633
|
...common,
|
|
24566
24634
|
kind: "property",
|
|
@@ -24901,61 +24969,6 @@ function memberWritability(annotations) {
|
|
|
24901
24969
|
if (/\.Session\b/.test(allowed ?? "")) return "session";
|
|
24902
24970
|
return "runtime";
|
|
24903
24971
|
}
|
|
24904
|
-
function accessorBodyRange(source, bodyRange, keyword) {
|
|
24905
|
-
if (source.length === 0) return null;
|
|
24906
|
-
const full = new SourceText(source);
|
|
24907
|
-
const bodyStart = full.offsetAt(bodyRange.start);
|
|
24908
|
-
const bodyEnd = full.offsetAt(bodyRange.end);
|
|
24909
|
-
const body = source.slice(bodyStart, bodyEnd);
|
|
24910
|
-
const local = new SourceText(body);
|
|
24911
|
-
const tokens = lex2(body);
|
|
24912
|
-
let depth = 0;
|
|
24913
|
-
for (let index = 0; index < tokens.length; index++) {
|
|
24914
|
-
const token = tokens[index];
|
|
24915
|
-
if (token.text === "{") {
|
|
24916
|
-
depth++;
|
|
24917
|
-
continue;
|
|
24918
|
-
}
|
|
24919
|
-
if (token.text === "}") {
|
|
24920
|
-
depth--;
|
|
24921
|
-
continue;
|
|
24922
|
-
}
|
|
24923
|
-
if (depth !== 1 || token.text !== keyword) continue;
|
|
24924
|
-
let openIndex = index + 1;
|
|
24925
|
-
if (tokens[openIndex]?.text === "(") {
|
|
24926
|
-
let parameterDepth = 1;
|
|
24927
|
-
for (let cursor = openIndex + 1; cursor < tokens.length; cursor++) {
|
|
24928
|
-
const candidate = tokens[cursor];
|
|
24929
|
-
if (candidate.text === "(") parameterDepth++;
|
|
24930
|
-
if (candidate.text === ")") parameterDepth--;
|
|
24931
|
-
if (parameterDepth !== 0) continue;
|
|
24932
|
-
openIndex = cursor + 1;
|
|
24933
|
-
break;
|
|
24934
|
-
}
|
|
24935
|
-
if (parameterDepth !== 0) return null;
|
|
24936
|
-
}
|
|
24937
|
-
const open = tokens[openIndex];
|
|
24938
|
-
if (open?.text !== "{") return null;
|
|
24939
|
-
let accessorDepth = 1;
|
|
24940
|
-
for (let cursor = openIndex + 1; cursor < tokens.length; cursor++) {
|
|
24941
|
-
const candidate = tokens[cursor];
|
|
24942
|
-
if (candidate.text === "{") accessorDepth++;
|
|
24943
|
-
if (candidate.text === "}") accessorDepth--;
|
|
24944
|
-
if (accessorDepth !== 0) continue;
|
|
24945
|
-
const start = bodyStart + sourceOffset2(local, open.pos) + 1;
|
|
24946
|
-
const end = bodyStart + sourceOffset2(local, candidate.pos);
|
|
24947
|
-
return full.range(start, end);
|
|
24948
|
-
}
|
|
24949
|
-
return null;
|
|
24950
|
-
}
|
|
24951
|
-
return null;
|
|
24952
|
-
}
|
|
24953
|
-
function sourceOffset2(source, position) {
|
|
24954
|
-
return source.offsetAt({
|
|
24955
|
-
line: Math.max(0, position.line - 1),
|
|
24956
|
-
character: Math.max(0, position.column - 1)
|
|
24957
|
-
});
|
|
24958
|
-
}
|
|
24959
24972
|
function innerBodyRange(source, range2) {
|
|
24960
24973
|
const text = new SourceText(source);
|
|
24961
24974
|
const start = text.offsetAt(range2.start);
|
|
@@ -25024,11 +25037,11 @@ var init_project_source_script_compiler = __esm({
|
|
|
25024
25037
|
init_declared_constructors();
|
|
25025
25038
|
init_language_spec();
|
|
25026
25039
|
init_project_source_ast();
|
|
25040
|
+
init_project_source_accessors();
|
|
25027
25041
|
init_project();
|
|
25028
25042
|
init_project_root();
|
|
25029
25043
|
init_project_source_registry();
|
|
25030
25044
|
init_source_text();
|
|
25031
|
-
init_strict_lexer();
|
|
25032
25045
|
PRIMITIVE_NAME_LIST = [
|
|
25033
25046
|
...NEOSCRIPT_PRIMITIVE_TYPES,
|
|
25034
25047
|
"void",
|
|
@@ -33707,6 +33720,7 @@ var init_src = __esm({
|
|
|
33707
33720
|
init_project_source_ast();
|
|
33708
33721
|
init_project_source_ignore();
|
|
33709
33722
|
init_project_source_analysis();
|
|
33723
|
+
init_project_source_accessors();
|
|
33710
33724
|
init_project_source_construction_diagnostics();
|
|
33711
33725
|
init_project_source_construction_quick_fixes();
|
|
33712
33726
|
init_project_source_manifest();
|
|
@@ -57024,6 +57038,16 @@ function lowerMemberKind(context, ownerClass, declaration, id2, owner) {
|
|
|
57024
57038
|
script: null
|
|
57025
57039
|
};
|
|
57026
57040
|
}
|
|
57041
|
+
if (declaration.modifiers.includes("abstract")) {
|
|
57042
|
+
return {
|
|
57043
|
+
...common,
|
|
57044
|
+
kind: "scriptFunction",
|
|
57045
|
+
returnType,
|
|
57046
|
+
arguments: argumentsValue,
|
|
57047
|
+
deferred: declaration.modifiers.includes("async"),
|
|
57048
|
+
script: null
|
|
57049
|
+
};
|
|
57050
|
+
}
|
|
57027
57051
|
return {
|
|
57028
57052
|
...common,
|
|
57029
57053
|
kind: "function",
|
|
@@ -58993,40 +59017,15 @@ function memberModifier3(modifiers, baseModifier) {
|
|
|
58993
59017
|
return "plain";
|
|
58994
59018
|
}
|
|
58995
59019
|
function propertyAccessors(body) {
|
|
59020
|
+
const accessorBody = (keyword) => {
|
|
59021
|
+
const accessor = findProjectSourceAccessorBody(body, keyword);
|
|
59022
|
+
return accessor === null ? null : normalizeBodySource(accessor.source);
|
|
59023
|
+
};
|
|
58996
59024
|
return {
|
|
58997
|
-
get: accessorBody(
|
|
58998
|
-
set: accessorBody(
|
|
59025
|
+
get: accessorBody("get"),
|
|
59026
|
+
set: accessorBody("set")
|
|
58999
59027
|
};
|
|
59000
59028
|
}
|
|
59001
|
-
function accessorBody(source, keyword) {
|
|
59002
|
-
const match = new RegExp(`\\b${keyword}\\b\\s*\\{`).exec(source);
|
|
59003
|
-
if (!match) return null;
|
|
59004
|
-
const open = source.indexOf("{", match.index);
|
|
59005
|
-
let depth = 0;
|
|
59006
|
-
let quote6 = null;
|
|
59007
|
-
let escaped = false;
|
|
59008
|
-
for (let index = open; index < source.length; index += 1) {
|
|
59009
|
-
const character = source[index];
|
|
59010
|
-
if (quote6) {
|
|
59011
|
-
if (escaped) escaped = false;
|
|
59012
|
-
else if (character === "\\") escaped = true;
|
|
59013
|
-
else if (character === quote6) quote6 = null;
|
|
59014
|
-
continue;
|
|
59015
|
-
}
|
|
59016
|
-
if (character === '"' || character === "'") {
|
|
59017
|
-
quote6 = character;
|
|
59018
|
-
continue;
|
|
59019
|
-
}
|
|
59020
|
-
if (character === "{") depth += 1;
|
|
59021
|
-
else if (character === "}") {
|
|
59022
|
-
depth -= 1;
|
|
59023
|
-
if (depth === 0) {
|
|
59024
|
-
return normalizeBodySource(source.slice(open + 1, index));
|
|
59025
|
-
}
|
|
59026
|
-
}
|
|
59027
|
-
}
|
|
59028
|
-
throw new Error(`Unclosed ${keyword} accessor.`);
|
|
59029
|
-
}
|
|
59030
59029
|
function innerBody2(body) {
|
|
59031
59030
|
const start = body.indexOf("{");
|
|
59032
59031
|
const end = body.lastIndexOf("}");
|
|
@@ -112252,7 +112251,7 @@ var init_registry2 = __esm({
|
|
|
112252
112251
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
112253
112252
|
formatVersion: 3,
|
|
112254
112253
|
contractVersion: "3.13",
|
|
112255
|
-
cliVersion: "0.32.
|
|
112254
|
+
cliVersion: "0.32.2",
|
|
112256
112255
|
projectFileUploadBatchSize: 32,
|
|
112257
112256
|
documentRecords: {
|
|
112258
112257
|
member: {
|
|
@@ -118847,7 +118846,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
118847
118846
|
async function main() {
|
|
118848
118847
|
const args = parseArgs(process.argv.slice(2));
|
|
118849
118848
|
if (args.command === "--version") {
|
|
118850
|
-
console.log("0.32.
|
|
118849
|
+
console.log("0.32.2");
|
|
118851
118850
|
return;
|
|
118852
118851
|
}
|
|
118853
118852
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/package.json
CHANGED
|
@@ -83,7 +83,7 @@ wrappers.
|
|
|
83
83
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
84
84
|
|
|
85
85
|
```html
|
|
86
|
-
<!-- reviewed-through-cli: 0.32.
|
|
86
|
+
<!-- reviewed-through-cli: 0.32.2 -->
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -20,6 +20,14 @@ Keep computed getters, setters, functions, dialogue logic, group logic, and
|
|
|
20
20
|
constructors inline in their owning `.neo` or `.neoflow` declaration. Do not
|
|
21
21
|
create `Scripts/<Class>/<Member>.neo` sidecars.
|
|
22
22
|
|
|
23
|
+
Declare a setter's value type explicitly with the canonical form
|
|
24
|
+
`set(int value) { ... }`. Project analysis, candidate materialization, and
|
|
25
|
+
focused script commands all use the same accessor extraction.
|
|
26
|
+
|
|
27
|
+
Declare a bodyless NeoScript contract with `abstract`, for example
|
|
28
|
+
`public abstract bool Equals(Item other);`. Reserve `native` for host-provided
|
|
29
|
+
functions; concrete NeoScript overrides inherit the abstract signature.
|
|
30
|
+
|
|
23
31
|
Use the shared language service through focused commands:
|
|
24
32
|
|
|
25
33
|
```sh
|