@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 = accessorBodyRange(
24269
+ const range2 = findProjectSourceAccessorBody(
24202
24270
  document.sourceText,
24203
- member.body.range,
24204
- unit === "getter" ? "get" : "set"
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 = accessorBodyRange(source, member.body.range, "set") !== null || /\bset\s*;/.test(member.body.text);
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(body, "get"),
58998
- set: accessorBody(body, "set")
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.0",
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.0");
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.32.0",
3
+ "version": "0.32.2",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,7 +9,7 @@ description: >-
9
9
  `@neocompose/cli` or `node cli/bin/neo.mjs` in the neo-compose repository.
10
10
  ---
11
11
 
12
- <!-- reviewed-through-cli: 0.32.0 -->
12
+ <!-- reviewed-through-cli: 0.32.2 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -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.0 -->
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