@neocompose/cli 0.33.1 → 0.34.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 CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.34.0] - 2026-08-19
4
+
5
+ ### Added
6
+
7
+ - P71 `List.Repeat`: call `List.Repeat(value, count)` from any NeoScript body
8
+ to build a list of `count` copies of `value`. The entry type is inferred
9
+ from the value and joined with the assignment context, so
10
+ `List<float> w = List.Repeat(0, 4)` widens; `count` must be an `int`, a
11
+ negative count is a runtime error, and materialization is charged to the
12
+ shared collection-entries budget.
13
+ - Unity export schema version 25, so an SDK that predates `listRepeat` refuses
14
+ the export with the standard upgrade message instead of failing
15
+ mid-deserialize.
16
+
17
+ ## [0.33.2] - 2026-08-19
18
+
19
+ ### Fixed
20
+
21
+ - Preserve authored non-null generic fields while projecting the local schema
22
+ manifest used by `neo script check --all`, so a `T` field read remains `T`
23
+ instead of becoming `T?` from the storage placeholder's structural flags.
24
+ - Compile prospective functions, properties, migrations, and ad-hoc scripts
25
+ against the complete project context, including declared constructors,
26
+ project files, and variants. `neo test` now resolves required Class-header
27
+ constructors instead of incorrectly falling back to their stored fields.
28
+
3
29
  ## [0.33.1] - 2026-08-19
4
30
 
5
31
  ### Fixed
package/dist/neo.mjs CHANGED
@@ -1336,7 +1336,7 @@ function vectorTypes() {
1336
1336
  members: structuredLeafFieldProperties(name)
1337
1337
  }));
1338
1338
  }
1339
- var NEO_PROJECT_IGNORED_DIRECTORY_NAMES, NEOSCRIPT_KEYWORDS, NEOSCRIPT_INFERRED_LOCAL_KEYWORD, NEOSCRIPT_CONSTRUCTOR_KEYWORD, NEOSCRIPT_PRIMITIVE_TYPES, NEOSCRIPT_BUILTIN_ANNOTATION_TYPES, NEOSCRIPT_BUILTIN_NAMESPACES, NEOSCRIPT_BUILTIN_TYPES, NEO_VARIANT_TYPE_NAME, NEO_VARIANT_FOLDER_TYPE_NAME, NEO_LOOKUP_VARIANT_TYPE_NAME, NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME, NEO_VARIANT_SCOPE_NAME, NEO_VARIANT_RESERVED_NAME, NEO_VARIANT_FOLDER_PATH_SEPARATOR, NEOSCRIPT_OPERATORS, NEOSCRIPT_STATEMENT_SNIPPETS, STRING_TYPE, INT_TYPE, FLOAT_TYPE, BOOL_TYPE, IMAGE_REF_TYPE, SPRITE_INFO_TYPE, FLOAT_OPTIONAL_TYPE, NEOSCRIPT_STRUCTURED_LEAF_FIELDS, NEOSCRIPT_IMAGE_REGISTRY_TYPE, NEOSCRIPT_AUDIO_CLIP_REGISTRY_TYPE, NEOSCRIPT_PENDING_SYMBOL_ID_PREFIX, REGISTRY_ENTRY_TYPES, NEOSCRIPT_GLOBALS, NEOSCRIPT_SPRITE_INFO_EMPTY_MEMBER_ID, NEOSCRIPT_SPRITE_INFO_EMPTY_VALUE, NEOSCRIPT_MATH_TYPE_ID, MATH_INFERENCE_RULE, MATH_INTEGRAL_RULE, NEOSCRIPT_BUILTIN_TYPE_SYMBOLS;
1339
+ var NEO_PROJECT_IGNORED_DIRECTORY_NAMES, NEOSCRIPT_KEYWORDS, NEOSCRIPT_INFERRED_LOCAL_KEYWORD, NEOSCRIPT_CONSTRUCTOR_KEYWORD, NEOSCRIPT_PRIMITIVE_TYPES, NEOSCRIPT_BUILTIN_ANNOTATION_TYPES, NEOSCRIPT_BUILTIN_NAMESPACES, NEOSCRIPT_BUILTIN_TYPES, NEO_VARIANT_TYPE_NAME, NEO_VARIANT_FOLDER_TYPE_NAME, NEO_LOOKUP_VARIANT_TYPE_NAME, NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME, NEO_VARIANT_SCOPE_NAME, NEO_VARIANT_RESERVED_NAME, NEO_VARIANT_FOLDER_PATH_SEPARATOR, NEOSCRIPT_OPERATORS, NEOSCRIPT_STATEMENT_SNIPPETS, STRING_TYPE, INT_TYPE, FLOAT_TYPE, BOOL_TYPE, IMAGE_REF_TYPE, SPRITE_INFO_TYPE, FLOAT_OPTIONAL_TYPE, NEOSCRIPT_STRUCTURED_LEAF_FIELDS, NEOSCRIPT_IMAGE_REGISTRY_TYPE, NEOSCRIPT_AUDIO_CLIP_REGISTRY_TYPE, NEOSCRIPT_PENDING_SYMBOL_ID_PREFIX, REGISTRY_ENTRY_TYPES, NEOSCRIPT_GLOBALS, NEOSCRIPT_SPRITE_INFO_EMPTY_MEMBER_ID, NEOSCRIPT_SPRITE_INFO_EMPTY_VALUE, NEOSCRIPT_MATH_TYPE_ID, MATH_INFERENCE_RULE, MATH_INTEGRAL_RULE, NEOSCRIPT_LIST_TYPE_NAME, NEOSCRIPT_LIST_TYPE_ID, NEOSCRIPT_LIST_REPEAT_NAME, LIST_ENTRY_TYPE, NEOSCRIPT_BUILTIN_TYPE_SYMBOLS;
1340
1340
  var init_language_spec = __esm({
1341
1341
  "../packages/neoscript-language/src/language-spec.ts"() {
1342
1342
  "use strict";
@@ -1680,6 +1680,14 @@ var init_language_spec = __esm({
1680
1680
  NEOSCRIPT_MATH_TYPE_ID = "builtin:Math";
1681
1681
  MATH_INFERENCE_RULE = "Accepts int, float, or decimal; the result mirrors the widest argument type.";
1682
1682
  MATH_INTEGRAL_RULE = "Accepts int, float, or decimal; int and float return int, decimal returns decimal.";
1683
+ NEOSCRIPT_LIST_TYPE_NAME = "List";
1684
+ NEOSCRIPT_LIST_TYPE_ID = "builtin:List";
1685
+ NEOSCRIPT_LIST_REPEAT_NAME = "Repeat";
1686
+ LIST_ENTRY_TYPE = {
1687
+ kind: "typeParameter",
1688
+ id: `${NEOSCRIPT_LIST_TYPE_ID}:entry`,
1689
+ name: "T"
1690
+ };
1683
1691
  NEOSCRIPT_BUILTIN_TYPE_SYMBOLS = [
1684
1692
  {
1685
1693
  id: "builtin:SpriteInfo",
@@ -1833,6 +1841,27 @@ var init_language_spec = __esm({
1833
1841
  static: true
1834
1842
  }
1835
1843
  ]
1844
+ },
1845
+ {
1846
+ id: NEOSCRIPT_LIST_TYPE_ID,
1847
+ name: NEOSCRIPT_LIST_TYPE_NAME,
1848
+ kind: "builtin",
1849
+ documentation: "The ordered collection type. Write List<T> to annotate, and bare List to reach its static factories.",
1850
+ members: [
1851
+ {
1852
+ id: `${NEOSCRIPT_LIST_TYPE_ID}:function:${NEOSCRIPT_LIST_REPEAT_NAME}`,
1853
+ name: NEOSCRIPT_LIST_REPEAT_NAME,
1854
+ kind: "function",
1855
+ type: { kind: "list", elementType: LIST_ENTRY_TYPE },
1856
+ returnType: { kind: "list", elementType: LIST_ENTRY_TYPE },
1857
+ parameters: [
1858
+ parameter("value", LIST_ENTRY_TYPE),
1859
+ parameter("count", INT_TYPE)
1860
+ ],
1861
+ documentation: "Returns a list of count copies of value. The entry type is inferred from value and the assignment context \u2014 never spell it. value is evaluated exactly once, then count exactly once, so a reference-typed value is the same reference in every entry; count must be a non-negative int, and 0 produces an empty list.",
1862
+ static: true
1863
+ }
1864
+ ]
1836
1865
  }
1837
1866
  ];
1838
1867
  }
@@ -6975,6 +7004,9 @@ var init_strict_parser = __esm({
6975
7004
  if (t.kind === "keyword" && t.text === "Dictionary") {
6976
7005
  return true;
6977
7006
  }
7007
+ if (t.kind === "keyword" && (t.text === "List" || t.text === "Set") && this.peek(1).kind === "op" && this.peek(1).text === "<") {
7008
+ return true;
7009
+ }
6978
7010
  if (t.kind !== "ident") return false;
6979
7011
  let j = this.i + 1;
6980
7012
  const tk = (k) => this.tokens[k];
@@ -7233,6 +7265,15 @@ var init_strict_parser = __esm({
7233
7265
  let expr = this.parsePrimary();
7234
7266
  while (true) {
7235
7267
  const t = this.peek();
7268
+ if (t.kind === "op" && t.text === "<" && expr.kind === "ident" && expr.name === NEOSCRIPT_LIST_TYPE_NAME) {
7269
+ const member = this.genericStaticMemberName();
7270
+ if (member !== null) {
7271
+ throw new CompileError(
7272
+ `Do not spell type arguments on '${NEOSCRIPT_LIST_TYPE_NAME}.${member}'; the entry type is inferred from the value.`,
7273
+ t.pos
7274
+ );
7275
+ }
7276
+ }
7236
7277
  if (t.kind === "op" && t.text === "<" && this.looksLikeGenericCall()) {
7237
7278
  this.next();
7238
7279
  const typeArguments = [this.parseType()];
@@ -7322,6 +7363,28 @@ var init_strict_parser = __esm({
7322
7363
  return expr;
7323
7364
  }
7324
7365
  }
7366
+ /**
7367
+ * The member name in a `<T, …>.Member` spelling at the cursor, or `null`
7368
+ * when the `<` is an ordinary comparison. Type arguments never precede a
7369
+ * member access in NeoScript, so this shape is always an author mistake and
7370
+ * the name is what a diagnostic needs to describe it.
7371
+ */
7372
+ genericStaticMemberName() {
7373
+ const open = this.tokens[this.i];
7374
+ if (open?.kind !== "op" || open.text !== "<") return null;
7375
+ let index = this.scanType(this.i + 1);
7376
+ if (index === null) return null;
7377
+ while (this.tokens[index]?.kind === "punct" && this.tokens[index]?.text === ",") {
7378
+ index = this.scanType(index + 1);
7379
+ if (index === null) return null;
7380
+ }
7381
+ const close = this.tokens[index];
7382
+ const dot = this.tokens[index + 1];
7383
+ const member = this.tokens[index + 2];
7384
+ if (close?.kind !== "op" || close.text !== ">") return null;
7385
+ if (dot?.kind !== "punct" || dot.text !== ".") return null;
7386
+ return member?.kind === "ident" ? member.text : null;
7387
+ }
7325
7388
  looksLikeGenericCall() {
7326
7389
  const open = this.tokens[this.i];
7327
7390
  if (open?.kind !== "op" || open.text !== "<") return false;
@@ -9431,7 +9494,7 @@ function switchValueKey(value) {
9431
9494
  const enumId = value.typeInfo.type === 8 /* Enum */ ? value.typeInfo.enumId : null;
9432
9495
  return JSON.stringify([value.typeInfo.type, enumId, value.value]);
9433
9496
  }
9434
- var CONSTRUCTING_FUNCTION_KINDS, VARIANT_INITIALIZE_NAME, VARIANT_APPLY_NAME, MATH_NAMESPACE_NAME, MATH_FUNCTIONS, MATH_CONSTANTS, WRITE_TARGET_DESCRIPTIONS, FALLTHROUGH_LABELS, Scope, StrictNeoScriptResolver, SPRITE_DERIVED_MEMBERS;
9497
+ var CONSTRUCTING_FUNCTION_KINDS, VARIANT_INITIALIZE_NAME, VARIANT_APPLY_NAME, MATH_NAMESPACE_NAME, MATH_FUNCTIONS, MATH_CONSTANTS, LIST_STATIC_FUNCTIONS, WRITE_TARGET_DESCRIPTIONS, FALLTHROUGH_LABELS, Scope, StrictNeoScriptResolver, SPRITE_DERIVED_MEMBERS;
9435
9498
  var init_strict_resolver = __esm({
9436
9499
  "../packages/neoscript-language/src/strict-resolver.ts"() {
9437
9500
  "use strict";
@@ -9472,6 +9535,9 @@ var init_strict_resolver = __esm({
9472
9535
  ["PI", 3.141592653589793],
9473
9536
  ["E", 2.718281828459045]
9474
9537
  ]);
9538
+ LIST_STATIC_FUNCTIONS = /* @__PURE__ */ new Map([
9539
+ [NEOSCRIPT_LIST_REPEAT_NAME, { arity: 2 }]
9540
+ ]);
9475
9541
  WRITE_TARGET_DESCRIPTIONS = {
9476
9542
  this: "`this`",
9477
9543
  local: "a local",
@@ -11123,7 +11189,8 @@ var init_strict_resolver = __esm({
11123
11189
  expression.callee,
11124
11190
  expression.args,
11125
11191
  scope,
11126
- expression.pos
11192
+ expression.pos,
11193
+ expected
11127
11194
  );
11128
11195
  case "new": {
11129
11196
  const vector = this.targetTypedVectorKind(expression, expected);
@@ -11770,6 +11837,12 @@ var init_strict_resolver = __esm({
11770
11837
  pos
11771
11838
  );
11772
11839
  }
11840
+ if (name === NEOSCRIPT_LIST_TYPE_NAME) {
11841
+ throw new CompileError(
11842
+ `'${NEOSCRIPT_LIST_TYPE_NAME}' is a type and cannot be used as a value.`,
11843
+ pos
11844
+ );
11845
+ }
11773
11846
  const type = this.project.typeByName.get(name);
11774
11847
  if (type?.kind === "enum") {
11775
11848
  return {
@@ -12222,6 +12295,15 @@ var init_strict_resolver = __esm({
12222
12295
  }
12223
12296
  return this.resolveMathMemberRead(name, pos);
12224
12297
  }
12298
+ if (receiverAst.name === NEOSCRIPT_LIST_TYPE_NAME) {
12299
+ if (optional) {
12300
+ throw new CompileError(
12301
+ `Optional chaining is not valid on type '${NEOSCRIPT_LIST_TYPE_NAME}'.`,
12302
+ pos
12303
+ );
12304
+ }
12305
+ return this.resolveListStaticMemberRead(name, pos);
12306
+ }
12225
12307
  const staticType = this.project.typeByName.get(receiverAst.name);
12226
12308
  if (staticType && staticType.kind !== "enum") {
12227
12309
  if (optional) {
@@ -12851,7 +12933,97 @@ var init_strict_resolver = __esm({
12851
12933
  )
12852
12934
  };
12853
12935
  }
12854
- resolveCall(callee, argumentsList2, scope, pos) {
12936
+ /**
12937
+ * P71 §1.2. A member read on the `List` qualifier. Nothing on `List` is
12938
+ * readable as a value: the statics are functions, and there are no
12939
+ * constants.
12940
+ */
12941
+ resolveListStaticMemberRead(name, pos) {
12942
+ if (LIST_STATIC_FUNCTIONS.has(name)) {
12943
+ throw new CompileError(
12944
+ `'${NEOSCRIPT_LIST_TYPE_NAME}.${name}' must be called with \`()\`; it cannot be read as a value.`,
12945
+ pos
12946
+ );
12947
+ }
12948
+ throw new CompileError(
12949
+ `'${NEOSCRIPT_LIST_TYPE_NAME}' has no static member '${name}'.`,
12950
+ pos
12951
+ );
12952
+ }
12953
+ /** P71 §1.1. A static-factory call on the bare `List` qualifier. */
12954
+ resolveListStaticCall(name, args, scope, expected, pos) {
12955
+ const fn = LIST_STATIC_FUNCTIONS.get(name);
12956
+ if (!fn) {
12957
+ throw new CompileError(
12958
+ `'${NEOSCRIPT_LIST_TYPE_NAME}' has no static member '${name}'.`,
12959
+ pos
12960
+ );
12961
+ }
12962
+ requireArgCount(`${NEOSCRIPT_LIST_TYPE_NAME}.${name}`, args, fn.arity, pos);
12963
+ return this.resolveListRepeat(args, scope, expected);
12964
+ }
12965
+ /**
12966
+ * P71 §2/§3. `List.Repeat(value, count)`: the entry type is the value's
12967
+ * type joined with the contextual entry type — the list-literal join,
12968
+ * numeric widening included — and the count is an `int` with no implicit
12969
+ * narrowing. Lowers to a `listRepeat` intrinsic carrying the value pointer,
12970
+ * the count pointer, and the joined entry type the evaluators must not
12971
+ * re-derive.
12972
+ */
12973
+ resolveListRepeat(args, scope, expected) {
12974
+ const label = `${NEOSCRIPT_LIST_TYPE_NAME}.${NEOSCRIPT_LIST_REPEAT_NAME}`;
12975
+ const expectedEntry = expected?.kind === "list" ? expected.elementType : void 0;
12976
+ const valueAst = requiredAt(args, 0);
12977
+ const countAst = requiredAt(args, 1);
12978
+ const value = this.resolveExpression(valueAst, scope, expectedEntry);
12979
+ const count = this.resolveExpression(countAst, scope, {
12980
+ kind: "primitive",
12981
+ name: "int"
12982
+ });
12983
+ if (isNullable(count.type)) {
12984
+ throw new CompileError(
12985
+ `${label} count must be a non-optional int; got ${this.describe(count.type)}.`,
12986
+ countAst.pos
12987
+ );
12988
+ }
12989
+ if (!isPrimitive(count.type, "int")) {
12990
+ throw new CompileError(
12991
+ `${label} count must be an int; got ${this.describe(count.type)}.`,
12992
+ countAst.pos
12993
+ );
12994
+ }
12995
+ const entryType = commonNeoScriptAssignableType(
12996
+ expectedEntry ?? value.type,
12997
+ value.type,
12998
+ this.project
12999
+ );
13000
+ if (entryType === null) {
13001
+ throw new CompileError(
13002
+ `${label} value ${this.describe(value.type)} is not a ${this.describe(expectedEntry ?? value.type)} entry.`,
13003
+ valueAst.pos
13004
+ );
13005
+ }
13006
+ const type = {
13007
+ kind: "list",
13008
+ elementType: entryType
13009
+ };
13010
+ const wire = toWireType(type, this.project);
13011
+ if (wire.type !== 6 /* List */) {
13012
+ throw new Error(
13013
+ "NeoScript strict compiler produced a non-list wire type for List.Repeat."
13014
+ );
13015
+ }
13016
+ return intrinsic(
13017
+ "listRepeat" /* ListRepeat */,
13018
+ {
13019
+ valuePointer: value.pointer,
13020
+ countPointer: count.pointer,
13021
+ entryTypeInfo: wire.entryTypeInfo
13022
+ },
13023
+ type
13024
+ );
13025
+ }
13026
+ resolveCall(callee, argumentsList2, scope, pos, expected) {
12855
13027
  const variantCall = this.resolveVariantCall(
12856
13028
  callee,
12857
13029
  argumentsList2,
@@ -12953,6 +13125,21 @@ var init_strict_resolver = __esm({
12953
13125
  }
12954
13126
  return this.resolveMathCall(callee.name, argumentsList2, scope, pos);
12955
13127
  }
13128
+ if (callee.receiver.name === NEOSCRIPT_LIST_TYPE_NAME) {
13129
+ if (callee.optional) {
13130
+ throw new CompileError(
13131
+ `Optional chaining is not valid on type '${NEOSCRIPT_LIST_TYPE_NAME}'.`,
13132
+ pos
13133
+ );
13134
+ }
13135
+ return this.resolveListStaticCall(
13136
+ callee.name,
13137
+ argumentsList2,
13138
+ scope,
13139
+ expected,
13140
+ pos
13141
+ );
13142
+ }
12956
13143
  const staticType = this.project.typeByName.get(callee.receiver.name);
12957
13144
  if (staticType && staticType.kind !== "enum") {
12958
13145
  if (callee.optional) {
@@ -32824,7 +33011,7 @@ function memberType(member, environment, visiting, field) {
32824
33011
  return typeParameter(
32825
33012
  string2(member.genericParamId, `${field}.genericParamId`),
32826
33013
  environment,
32827
- nullable
33014
+ false
32828
33015
  );
32829
33016
  }
32830
33017
  return { ...unknownType(), nullable };
@@ -42486,6 +42673,19 @@ function isNSFunctionMathOp(value) {
42486
42673
  const decimal2 = info.decimal;
42487
42674
  return decimal2 === void 0 || decimal2 === true;
42488
42675
  }
42676
+ function isNSFunctionListRepeat(value) {
42677
+ const v = value;
42678
+ if (v?.type !== "listRepeat" /* listRepeat */) return false;
42679
+ const info = v.info;
42680
+ if (typeof info !== "object" || info === null) return false;
42681
+ if (!isNSPointer(info.valuePointer)) {
42682
+ return false;
42683
+ }
42684
+ if (!isNSPointer(info.countPointer)) {
42685
+ return false;
42686
+ }
42687
+ return isNSTypeInfo(info.entryTypeInfo);
42688
+ }
42489
42689
  function isNSFunctionCount(value) {
42490
42690
  const v = value;
42491
42691
  if (v?.type !== "count" /* count */) return false;
@@ -42533,7 +42733,7 @@ function isNSFunction(value) {
42533
42733
  return isNSFunctionClassConstructor(value) || isNSFunctionClassClone(value) || isNSFunctionListIndex(value) || isNSFunctionSelect(value) || isNSFunctionFirst(value) || isNSFunctionFirstOrDefault(value) || isNSFunctionWhere(value) || isNSFunctionContains(value) || // stringOp was missing from this chain since its introduction — a
42534
42734
  // compiled getter using ToLower()/StartsWith() would fail pointer
42535
42735
  // validation anywhere isNSFunction gates. Fixed alongside decimalOp.
42536
- isNSFunctionStringOp(value) || isNSFunctionDecimalOp(value) || isNSFunctionMathOp(value) || isNSFunctionCount(value) || isNSFunctionVisitCount(value) || isNSFunctionHasVisited(value) || isNSFunctionVectorConstructor(value) || isNSFunctionImageSlice(value) || isNSFunctionVariantInitialize(value) || isNSFunctionVariantApply(value) || isNSFunctionDeclaredConstructor(value);
42736
+ isNSFunctionStringOp(value) || isNSFunctionDecimalOp(value) || isNSFunctionMathOp(value) || isNSFunctionListRepeat(value) || isNSFunctionCount(value) || isNSFunctionVisitCount(value) || isNSFunctionHasVisited(value) || isNSFunctionVectorConstructor(value) || isNSFunctionImageSlice(value) || isNSFunctionVariantInitialize(value) || isNSFunctionVariantApply(value) || isNSFunctionDeclaredConstructor(value);
42537
42737
  }
42538
42738
  function isNSInstructionVariable(value) {
42539
42739
  const v = value;
@@ -69347,6 +69547,25 @@ function evalDecimalMathOp(info, fn, scope, ctx) {
69347
69547
  rethrowDecimalError(error);
69348
69548
  }
69349
69549
  }
69550
+ function evalListRepeat(info, scope, ctx) {
69551
+ const value = evalPointer(info.valuePointer, scope, ctx);
69552
+ const count = numberArg(
69553
+ evalPointer(info.countPointer, scope, ctx),
69554
+ "List.Repeat count"
69555
+ );
69556
+ if (count < 0) {
69557
+ throw new NSGetterRuntimeError(
69558
+ `List.Repeat count must be non-negative; got ${count}.`
69559
+ );
69560
+ }
69561
+ consumeBudget(
69562
+ ctx,
69563
+ "producedCollectionEntries",
69564
+ count,
69565
+ "produced collection entry"
69566
+ );
69567
+ return new Array(count).fill(value);
69568
+ }
69350
69569
  function stringifyForInterp(v) {
69351
69570
  if (v === null || v === void 0) return "";
69352
69571
  if (typeof v === "string") return v;
@@ -69868,6 +70087,8 @@ function evalFunction(fn, scope, ctx) {
69868
70087
  }
69869
70088
  case "mathOp" /* mathOp */:
69870
70089
  return evalMathOp(fn.info, scope, ctx);
70090
+ case "listRepeat" /* listRepeat */:
70091
+ return evalListRepeat(fn.info, scope, ctx);
69871
70092
  case "stringOp" /* stringOp */: {
69872
70093
  const receiver = evalPointer(fn.info.receiverPointer, scope, ctx);
69873
70094
  if (typeof receiver !== "string") {
@@ -107138,6 +107359,7 @@ function createCliNeoScriptContext(options) {
107138
107359
  const members = [...options.documents.members];
107139
107360
  const vm = {
107140
107361
  project: options.documents.project,
107362
+ projectFiles: [...options.documents.projectFiles ?? []],
107141
107363
  members,
107142
107364
  classes: [...options.documents.classes],
107143
107365
  enums: [...options.documents.enums],
@@ -107157,7 +107379,9 @@ function createCliNeoScriptContext(options) {
107157
107379
  ...options.functionReturnTypeInfo ? { functionReturnTypeInfo: options.functionReturnTypeInfo } : {},
107158
107380
  ...options.functionArguments ? { functionArguments: options.functionArguments } : {},
107159
107381
  ...options.functionDeferred !== void 0 ? { functionDeferred: options.functionDeferred } : {},
107160
- ...options.functionName ? { functionName: options.functionName } : {}
107382
+ ...options.functionName ? { functionName: options.functionName } : {},
107383
+ ...options.documents.variants?.length ? { variants: [...options.documents.variants] } : {},
107384
+ ...options.documents.variantFolders?.length ? { variantFolders: [...options.documents.variantFolders] } : {}
107161
107385
  });
107162
107386
  if (!options.manifest) return compilerContext;
107163
107387
  const projection = projectSchemaManifest(options.manifest, {
@@ -107796,11 +108020,14 @@ function readDocumentArrays(raw) {
107796
108020
  }
107797
108021
  return {
107798
108022
  project: raw.project,
108023
+ projectFiles: arrayOf2("projectFiles"),
107799
108024
  members: arrayOf2("members"),
107800
108025
  classes: arrayOf2("classes"),
107801
108026
  constructors: arrayOf2("constructors"),
107802
108027
  enums: arrayOf2("enums"),
107803
108028
  interfaces: arrayOf2("interfaces"),
108029
+ variants: arrayOf2("variants"),
108030
+ variantFolders: arrayOf2("variantFolders"),
107804
108031
  values: arrayOf2("values"),
107805
108032
  dialogues: arrayOf2("dialogues"),
107806
108033
  dialogueRecords: arrayOf2("dialogueRecords"),
@@ -107808,7 +108035,6 @@ function readDocumentArrays(raw) {
107808
108035
  dialogueGroups: arrayOf2("dialogueGroups"),
107809
108036
  priorityGroups: arrayOf2("priorityGroups"),
107810
108037
  migrations: arrayOf2("migrations"),
107811
- projectFiles: arrayOf2("projectFiles"),
107812
108038
  localizationConfig: raw.localizationConfig,
107813
108039
  localizedTexts: arrayOf2("localizedTexts")
107814
108040
  };
@@ -108411,12 +108637,19 @@ async function runScript(workspace, command, options, dependencies = {}) {
108411
108637
  unit,
108412
108638
  code: source
108413
108639
  });
108414
- const compileContext = {
108640
+ const compilerProject = {
108415
108641
  project: document.project,
108642
+ projectFiles: document.projectFiles,
108416
108643
  members: document.members,
108417
108644
  classes: document.classes,
108645
+ constructors: document.constructors,
108418
108646
  enums: document.enums,
108419
108647
  interfaces: document.interfaces,
108648
+ variants: document.variants,
108649
+ variantFolders: document.variantFolders
108650
+ };
108651
+ const compileContext = {
108652
+ ...compilerProject,
108420
108653
  thisClass,
108421
108654
  returnTypeInfo: parseReturns(options.returns, document),
108422
108655
  dialogueContext: null
@@ -108465,11 +108698,7 @@ async function runScript(workspace, command, options, dependencies = {}) {
108465
108698
  }
108466
108699
  compiled = compileNeoScriptBodyOrThrow(
108467
108700
  () => compileNSFunction(source, {
108468
- project: document.project,
108469
- members: document.members,
108470
- classes: document.classes,
108471
- enums: document.enums,
108472
- interfaces: document.interfaces,
108701
+ ...compilerProject,
108473
108702
  thisClass,
108474
108703
  returnTypeInfo: nsFunctionDefinition.returnTypeInfo,
108475
108704
  argumentTypes: nsFunctionDefinition.argumentTypes,
@@ -108485,11 +108714,7 @@ async function runScript(workspace, command, options, dependencies = {}) {
108485
108714
  }
108486
108715
  compiled = compileNeoScriptBodyOrThrow(
108487
108716
  () => compileNSSetter(source, {
108488
- project: document.project,
108489
- members: document.members,
108490
- classes: document.classes,
108491
- enums: document.enums,
108492
- interfaces: document.interfaces,
108717
+ ...compilerProject,
108493
108718
  thisClass,
108494
108719
  valueTypeInfo: resolveScriptPropertyReturnTypeInfo(
108495
108720
  setterMember,
@@ -112398,10 +112623,27 @@ async function buildPostPushCompileSchema(workspace, status) {
112398
112623
  }
112399
112624
  return {
112400
112625
  project,
112626
+ projectFiles: [...bucket("project-file").values()],
112401
112627
  members: [...bucket("member").values()],
112402
112628
  classes: [...bucket("class").values()],
112629
+ constructors: [...bucket("constructor").values()],
112403
112630
  enums: [...bucket("enum").values()],
112404
- interfaces: [...bucket("interface").values()]
112631
+ interfaces: [...bucket("interface").values()],
112632
+ variants: [...bucket("variant").values()],
112633
+ variantFolders: [...bucket("variant-folder").values()]
112634
+ };
112635
+ }
112636
+ function postPushCompilerProject(schema) {
112637
+ return {
112638
+ project: schema.project,
112639
+ projectFiles: schema.projectFiles,
112640
+ members: schema.members,
112641
+ classes: schema.classes,
112642
+ constructors: schema.constructors,
112643
+ enums: schema.enums,
112644
+ interfaces: schema.interfaces,
112645
+ variants: schema.variants,
112646
+ variantFolders: schema.variantFolders
112405
112647
  };
112406
112648
  }
112407
112649
  function containingClass(schema, memberId) {
@@ -112433,11 +112675,7 @@ function compileNSPropertyChange(schema, memberData, locator) {
112433
112675
  const code = memberData.code;
112434
112676
  next.getter = compileNeoScriptBodyOrThrow(
112435
112677
  () => compileNSGetter2(code, {
112436
- project: schema.project,
112437
- members: schema.members,
112438
- classes: schema.classes,
112439
- enums: schema.enums,
112440
- interfaces: schema.interfaces,
112678
+ ...postPushCompilerProject(schema),
112441
112679
  thisClass,
112442
112680
  returnTypeInfo,
112443
112681
  dialogueContext: null,
@@ -112454,11 +112692,7 @@ function compileNSPropertyChange(schema, memberData, locator) {
112454
112692
  const setterCode = memberData.setterCode;
112455
112693
  next.setter = compileNeoScriptBodyOrThrow(
112456
112694
  () => compileNSSetter2(setterCode, {
112457
- project: schema.project,
112458
- members: schema.members,
112459
- classes: schema.classes,
112460
- enums: schema.enums,
112461
- interfaces: schema.interfaces,
112695
+ ...postPushCompilerProject(schema),
112462
112696
  thisClass,
112463
112697
  valueTypeInfo: returnTypeInfo,
112464
112698
  implicitMemberAccess: true,
@@ -112483,11 +112717,7 @@ function compileNSFunctionChange(schema, memberData, locator) {
112483
112717
  const thisClass = containingClass(schema, memberData.id);
112484
112718
  next.action = compileNeoScriptBodyOrThrow(
112485
112719
  () => compileNSFunction2(code, {
112486
- project: schema.project,
112487
- members: schema.members,
112488
- classes: schema.classes,
112489
- enums: schema.enums,
112490
- interfaces: schema.interfaces,
112720
+ ...postPushCompilerProject(schema),
112491
112721
  thisClass,
112492
112722
  returnTypeInfo: contract.returnTypeInfo,
112493
112723
  argumentTypes: contract.argumentTypes,
@@ -112827,11 +113057,7 @@ function compileMigrationAction(schema, migrationData, locator) {
112827
113057
  const code = String(migrationData.code);
112828
113058
  return compileNeoScriptBodyOrThrow(
112829
113059
  () => compileNSVoidBody2(code, {
112830
- project: schema.project,
112831
- members: schema.members,
112832
- classes: schema.classes,
112833
- enums: schema.enums,
112834
- interfaces: schema.interfaces,
113060
+ ...postPushCompilerProject(schema),
112835
113061
  thisClass,
112836
113062
  dialogueContext: null,
112837
113063
  migrationContext: true
@@ -112939,7 +113165,7 @@ var init_registry2 = __esm({
112939
113165
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
112940
113166
  formatVersion: 3,
112941
113167
  contractVersion: "3.13",
112942
- cliVersion: "0.33.1",
113168
+ cliVersion: "0.34.0",
112943
113169
  projectFileUploadBatchSize: 32,
112944
113170
  documentRecords: {
112945
113171
  member: {
@@ -116812,10 +117038,14 @@ async function runPendingMigrations(workspace, client, raw, migrations, onlyRef,
116812
117038
  const compiled = pinned !== void 0 && pinned !== null ? pinned : compileNeoScriptBodyOrThrow(
116813
117039
  () => compileNSVoidBody(migrationCode, {
116814
117040
  project: document.project,
117041
+ projectFiles: document.projectFiles,
116815
117042
  members: document.members,
116816
117043
  classes: document.classes,
117044
+ constructors: document.constructors,
116817
117045
  enums: document.enums,
116818
117046
  interfaces: document.interfaces,
117047
+ variants: document.variants,
117048
+ variantFolders: document.variantFolders,
116819
117049
  thisClass,
116820
117050
  dialogueContext: null,
116821
117051
  migrationContext: true
@@ -119534,7 +119764,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
119534
119764
  async function main() {
119535
119765
  const args = parseArgs(process.argv.slice(2));
119536
119766
  if (args.command === "--version") {
119537
- console.log("0.33.1");
119767
+ console.log("0.34.0");
119538
119768
  return;
119539
119769
  }
119540
119770
  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.33.1",
3
+ "version": "0.34.0",
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.33.1 -->
12
+ <!-- reviewed-through-cli: 0.34.0 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -138,8 +138,8 @@ completely before editing:
138
138
  variant folders, partial animation overrides, segments, tracks, and NeoFlow
139
139
  dialogues.
140
140
  - [NeoScript](references/neoscript.md): inline bodies, snippets, nullability,
141
- numeric builtins, loops, switch, try/catch, ownership, evaluation, and
142
- migrations.
141
+ numeric and list builtins, loops, switch, try/catch, ownership, evaluation,
142
+ and migrations.
143
143
  - [Commands and synchronization](references/commands-and-sync.md): pull/push,
144
144
  conflicts, low-level repair, branches, releases, and history.
145
145
  - [CLI development](references/cli-development.md): implementation source of
@@ -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.33.1 -->
86
+ <!-- reviewed-through-cli: 0.34.0 -->
87
87
  ```
88
88
 
89
89
  The quoted version above is checked too, so this instruction cannot go stale
@@ -8,6 +8,7 @@ runtime ownership, evaluation, and migrations.
8
8
  - Inline bodies and snippets
9
9
  - Nullability and ownership
10
10
  - Numeric builtins
11
+ - List builtins
11
12
  - Conditional and logical operators
12
13
  - Loops and transfer
13
14
  - Switch
@@ -127,6 +128,31 @@ enum, parameter, or local may shadow it. Qualified members use their owner's
127
128
  namespace and may be named `Math`; access one as `this.Math` or
128
129
  `SomeValue.Math` without colliding with the builtin qualifier.
129
130
 
131
+ ## List builtins
132
+
133
+ Use `List.Repeat(value, count)` to build a list of `count` copies of a value
134
+ instead of hand-counting a literal or looping around `Add`:
135
+
136
+ ```neo
137
+ List<int> scores = List.Repeat(0, 10);
138
+ ```
139
+
140
+ The entry type is inferred from the value and joined with the assignment
141
+ context, exactly like a list literal, so assigning `List.Repeat(0, 4)` to a
142
+ `List<float>` widens the entries to `float`. Never spell type arguments on the
143
+ qualifier: `List<int>.Repeat(0, 3)` is an error, and bare `List` is a
144
+ qualifier, not a value.
145
+
146
+ `count` must be an `int` — a `float` count is a compile error, and a negative
147
+ count fails at runtime with `List.Repeat count must be non-negative; got
148
+ {count}.`. A count of `0` produces an empty `List<T>` whose entry type is
149
+ still known. The value is evaluated exactly once, then the count exactly once,
150
+ so side effects happen once regardless of `count`, and every entry is that one
151
+ value: for a reference-typed entry the same reference repeats `count` times.
152
+ Materializing the list charges `count` to the shared collection-entries
153
+ execution budget, so a runaway count fails with the existing budget error
154
+ before allocating.
155
+
130
156
  ## Conditional and logical operators
131
157
 
132
158
  Use `condition ? whenTrue : whenFalse` for a value chosen by a condition: