@neocompose/cli 0.31.7 → 0.31.9
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,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.31.9] - 2026-08-17
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Surface `SpriteInfo.Empty` in project-source and NeoScript completion and
|
|
8
|
+
hover with documentation for its canonical empty-sprite behavior.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Accept the exact `SpriteInfo.Empty` sentinel as the non-null result of a
|
|
13
|
+
required Sprite function while continuing to reject malformed empty sprites
|
|
14
|
+
and empty Audio values.
|
|
15
|
+
|
|
16
|
+
## [0.31.8] - 2026-08-17
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Propagate `?.` through following required member and index accesses in the
|
|
21
|
+
same expression chain, so a nullable parent safely short-circuits a deep
|
|
22
|
+
read while independently nullable descendants still require explicit null
|
|
23
|
+
handling.
|
|
24
|
+
|
|
3
25
|
## [0.31.7] - 2026-08-15
|
|
4
26
|
|
|
5
27
|
### Fixed
|
package/dist/neo.mjs
CHANGED
|
@@ -1663,13 +1663,14 @@ var init_language_spec = __esm({
|
|
|
1663
1663
|
id: "builtin:SpriteInfo",
|
|
1664
1664
|
name: "SpriteInfo",
|
|
1665
1665
|
kind: "builtin",
|
|
1666
|
+
documentation: "A sprite asset reference and slice index. Use SpriteInfo.Empty when a required sprite should render no image.",
|
|
1666
1667
|
members: [
|
|
1667
1668
|
{
|
|
1668
1669
|
...property(
|
|
1669
1670
|
"SpriteInfo",
|
|
1670
1671
|
"Empty",
|
|
1671
1672
|
SPRITE_INFO_TYPE,
|
|
1672
|
-
"
|
|
1673
|
+
"The canonical non-null empty sprite. Use it when a required SpriteInfo should render no image; it has no backing file and uses slice index 0."
|
|
1673
1674
|
),
|
|
1674
1675
|
static: true
|
|
1675
1676
|
},
|
|
@@ -2319,7 +2320,11 @@ function complete(snapshot, position) {
|
|
|
2319
2320
|
word
|
|
2320
2321
|
);
|
|
2321
2322
|
} else {
|
|
2322
|
-
const
|
|
2323
|
+
const directStaticType = receiverTokens.length === 1 && receiverTokens[0]?.kind === "type" ? snapshot.project.typeByName.get(receiverTokens[0].text) : void 0;
|
|
2324
|
+
const resolved = directStaticType ? {
|
|
2325
|
+
type: { kind: "named", typeId: directStaticType.id },
|
|
2326
|
+
staticType: directStaticType
|
|
2327
|
+
} : resolveChain(snapshot, receiverTokens, offset);
|
|
2323
2328
|
candidates = completionItemsForResolution(snapshot, resolved, word);
|
|
2324
2329
|
}
|
|
2325
2330
|
} else if (tail?.kind === "identifier" && tail.text === NEOSCRIPT_CONSTRUCTOR_KEYWORD) {
|
|
@@ -2343,27 +2348,14 @@ function complete(snapshot, position) {
|
|
|
2343
2348
|
function hover(snapshot, position) {
|
|
2344
2349
|
const offset = snapshot.source.offsetAt(position);
|
|
2345
2350
|
const reference2 = referenceAt(snapshot.parsed.references, offset);
|
|
2346
|
-
if (!reference2) return
|
|
2351
|
+
if (!reference2) return builtinStaticMemberHoverAt(snapshot, offset);
|
|
2347
2352
|
const resolution = resolveReference(snapshot, reference2);
|
|
2348
|
-
if (!resolution?.symbol && !resolution?.staticType)
|
|
2353
|
+
if (!resolution?.symbol && !resolution?.staticType) {
|
|
2354
|
+
return builtinStaticMemberHoverAt(snapshot, offset);
|
|
2355
|
+
}
|
|
2349
2356
|
const symbol = resolution.symbol;
|
|
2350
2357
|
if (symbol) {
|
|
2351
|
-
|
|
2352
|
-
const origin = symbol.inheritedFrom ? `
|
|
2353
|
-
|
|
2354
|
-
Inherited from \`${symbol.inheritedFrom.typeName}\`.` : "";
|
|
2355
|
-
const identity2 = symbol.id.startsWith("local:") || symbol.id.startsWith("parameter:") ? "" : `
|
|
2356
|
-
|
|
2357
|
-
Schema id: \`${symbol.id}\``;
|
|
2358
|
-
const docs2 = symbol.documentation ? `
|
|
2359
|
-
|
|
2360
|
-
${symbol.documentation}` : "";
|
|
2361
|
-
return {
|
|
2362
|
-
range: reference2.range,
|
|
2363
|
-
markdown: `**${symbol.name}** _${displaySymbolKind(symbol)}_
|
|
2364
|
-
|
|
2365
|
-
\`${signature}\`${docs2}${origin}${identity2}`
|
|
2366
|
-
};
|
|
2358
|
+
return symbolHover(symbol, reference2.range, snapshot.project);
|
|
2367
2359
|
}
|
|
2368
2360
|
const type = resolution.staticType;
|
|
2369
2361
|
if (!type) return null;
|
|
@@ -2380,6 +2372,39 @@ ${type.documentation}` : "";
|
|
|
2380
2372
|
Schema id: \`${type.id}\`${docs}`
|
|
2381
2373
|
};
|
|
2382
2374
|
}
|
|
2375
|
+
function symbolHover(symbol, range2, project) {
|
|
2376
|
+
const signature = formatSymbolSignature(symbol, project);
|
|
2377
|
+
const origin = symbol.inheritedFrom ? `
|
|
2378
|
+
|
|
2379
|
+
Inherited from \`${symbol.inheritedFrom.typeName}\`.` : "";
|
|
2380
|
+
const identity2 = symbol.id.startsWith("local:") || symbol.id.startsWith("parameter:") ? "" : `
|
|
2381
|
+
|
|
2382
|
+
Schema id: \`${symbol.id}\``;
|
|
2383
|
+
const docs = symbol.documentation ? `
|
|
2384
|
+
|
|
2385
|
+
${symbol.documentation}` : "";
|
|
2386
|
+
return {
|
|
2387
|
+
range: range2,
|
|
2388
|
+
markdown: `**${symbol.name}** _${displaySymbolKind(symbol)}_
|
|
2389
|
+
|
|
2390
|
+
\`${signature}\`${docs}${origin}${identity2}`
|
|
2391
|
+
};
|
|
2392
|
+
}
|
|
2393
|
+
function builtinStaticMemberHoverAt(snapshot, offset) {
|
|
2394
|
+
const tokens = snapshot.lexed.tokens;
|
|
2395
|
+
const memberIndex = tokens.findIndex(
|
|
2396
|
+
(token) => token.kind === "identifier" && token.start <= offset && offset <= token.end
|
|
2397
|
+
);
|
|
2398
|
+
if (memberIndex < 2 || tokens[memberIndex - 1]?.text !== ".") return null;
|
|
2399
|
+
const owner = tokens[memberIndex - 2];
|
|
2400
|
+
const memberToken = tokens[memberIndex];
|
|
2401
|
+
if (owner?.kind !== "type" || !memberToken) return null;
|
|
2402
|
+
const type = snapshot.project.typeByName.get(owner.text);
|
|
2403
|
+
const member = type?.members.find(
|
|
2404
|
+
(candidate) => candidate.static === true && candidate.name === memberToken.text
|
|
2405
|
+
);
|
|
2406
|
+
return member ? symbolHover(member, memberToken.range, snapshot.project) : null;
|
|
2407
|
+
}
|
|
2383
2408
|
function definition(snapshot, position) {
|
|
2384
2409
|
const offset = snapshot.source.offsetAt(position);
|
|
2385
2410
|
const reference2 = referenceAt(snapshot.parsed.references, offset);
|
|
@@ -11838,13 +11863,15 @@ var init_strict_resolver = __esm({
|
|
|
11838
11863
|
};
|
|
11839
11864
|
}
|
|
11840
11865
|
}
|
|
11841
|
-
const
|
|
11842
|
-
if (optional && !isNullable(
|
|
11866
|
+
const resolvedReceiver = this.resolveExpression(receiverAst, scope);
|
|
11867
|
+
if (optional && !isNullable(resolvedReceiver.type)) {
|
|
11843
11868
|
throw new CompileError(
|
|
11844
|
-
`\`?.\` requires an optional receiver; got ${this.describe(
|
|
11869
|
+
`\`?.\` requires an optional receiver; got ${this.describe(resolvedReceiver.type)}`,
|
|
11845
11870
|
pos
|
|
11846
11871
|
);
|
|
11847
11872
|
}
|
|
11873
|
+
const receiver = resolvedReceiver.optionalChainType ? { ...resolvedReceiver, type: resolvedReceiver.optionalChainType } : resolvedReceiver;
|
|
11874
|
+
const nullPropagating = optional || resolvedReceiver.optionalChainType !== void 0;
|
|
11848
11875
|
if (!optional && isNullable(receiver.type)) {
|
|
11849
11876
|
throw new CompileError(
|
|
11850
11877
|
`Member '${name}' is read on ${this.describe(receiver.type)}, which may be null. Handle null before reading through it \u2014 use \`!\` if it is always set, or \`?.\`, \`??\`, or a null check that narrows it.`,
|
|
@@ -11852,7 +11879,7 @@ var init_strict_resolver = __esm({
|
|
|
11852
11879
|
);
|
|
11853
11880
|
}
|
|
11854
11881
|
if (receiver.staticType?.kind === "enum") {
|
|
11855
|
-
if (
|
|
11882
|
+
if (nullPropagating) {
|
|
11856
11883
|
throw new CompileError(
|
|
11857
11884
|
`\`?.\` is not valid on enum type '${receiver.staticType.name}'; enum option access is always defined`,
|
|
11858
11885
|
pos
|
|
@@ -11924,9 +11951,10 @@ var init_strict_resolver = __esm({
|
|
|
11924
11951
|
pointer: receiver.pointer,
|
|
11925
11952
|
key: numberPointer(0)
|
|
11926
11953
|
},
|
|
11927
|
-
...
|
|
11954
|
+
...nullPropagating ? { optional: true } : {}
|
|
11928
11955
|
},
|
|
11929
|
-
type:
|
|
11956
|
+
type: nullPropagating ? { ...primitiveMember.type, nullable: true } : primitiveMember.type,
|
|
11957
|
+
...nullPropagating ? { optionalChainType: primitiveMember.type } : {},
|
|
11930
11958
|
...receiver.writability ? { writability: receiver.writability } : {}
|
|
11931
11959
|
};
|
|
11932
11960
|
}
|
|
@@ -11934,7 +11962,7 @@ var init_strict_resolver = __esm({
|
|
|
11934
11962
|
receiver,
|
|
11935
11963
|
primitiveMember.key ?? name,
|
|
11936
11964
|
primitiveMember.type,
|
|
11937
|
-
|
|
11965
|
+
nullPropagating
|
|
11938
11966
|
);
|
|
11939
11967
|
if (!primitiveMember.derived) return resolved;
|
|
11940
11968
|
return {
|
|
@@ -11968,7 +11996,7 @@ var init_strict_resolver = __esm({
|
|
|
11968
11996
|
receiver,
|
|
11969
11997
|
name,
|
|
11970
11998
|
{ kind: "primitive", name: "string" },
|
|
11971
|
-
|
|
11999
|
+
nullPropagating
|
|
11972
12000
|
);
|
|
11973
12001
|
}
|
|
11974
12002
|
const member = type.members.find((candidate) => candidate.name === name);
|
|
@@ -12002,9 +12030,10 @@ var init_strict_resolver = __esm({
|
|
|
12002
12030
|
type: "callGetter" /* CallGetter */,
|
|
12003
12031
|
memberId: member.id,
|
|
12004
12032
|
receiver: { kind: "instance", pointer: receiver.pointer },
|
|
12005
|
-
...
|
|
12033
|
+
...nullPropagating ? { optional: true } : {}
|
|
12006
12034
|
},
|
|
12007
|
-
type:
|
|
12035
|
+
type: nullPropagating ? { ...memberType2, nullable: true } : memberType2,
|
|
12036
|
+
...nullPropagating ? { optionalChainType: memberType2 } : {},
|
|
12008
12037
|
symbol: member,
|
|
12009
12038
|
...member.writable ? {
|
|
12010
12039
|
writability: member.writability ? toWritability(member.writability) : "setter" /* Setter */
|
|
@@ -12028,7 +12057,7 @@ var init_strict_resolver = __esm({
|
|
|
12028
12057
|
receiver,
|
|
12029
12058
|
member.schemaKey ?? member.name,
|
|
12030
12059
|
memberType2,
|
|
12031
|
-
|
|
12060
|
+
nullPropagating,
|
|
12032
12061
|
member.id
|
|
12033
12062
|
),
|
|
12034
12063
|
symbol: member,
|
|
@@ -12136,14 +12165,23 @@ var init_strict_resolver = __esm({
|
|
|
12136
12165
|
...optional ? { optional: true } : {}
|
|
12137
12166
|
},
|
|
12138
12167
|
type: optional ? { ...type, nullable: true } : type,
|
|
12168
|
+
...optional ? { optionalChainType: type } : {},
|
|
12139
12169
|
...receiver.writability ? { writability: receiver.writability } : {}
|
|
12140
12170
|
};
|
|
12141
12171
|
}
|
|
12142
12172
|
resolveIndex(receiverAst, indexAst, scope, pos, optional) {
|
|
12143
|
-
const
|
|
12144
|
-
if (optional && !isNullable(
|
|
12173
|
+
const resolvedReceiver = this.resolveExpression(receiverAst, scope);
|
|
12174
|
+
if (optional && !isNullable(resolvedReceiver.type)) {
|
|
12175
|
+
throw new CompileError(
|
|
12176
|
+
`\`?.[]\` requires an optional receiver; got ${this.describe(resolvedReceiver.type)}`,
|
|
12177
|
+
pos
|
|
12178
|
+
);
|
|
12179
|
+
}
|
|
12180
|
+
const receiver = resolvedReceiver.optionalChainType ? { ...resolvedReceiver, type: resolvedReceiver.optionalChainType } : resolvedReceiver;
|
|
12181
|
+
const nullPropagating = optional || resolvedReceiver.optionalChainType !== void 0;
|
|
12182
|
+
if (!optional && isNullable(receiver.type)) {
|
|
12145
12183
|
throw new CompileError(
|
|
12146
|
-
|
|
12184
|
+
`Index access is read on ${this.describe(receiver.type)}, which may be null. Handle null before indexing it \u2014 use \`!\` if it is always set, or \`?.[]\`, \`??\`, or a null check that narrows it.`,
|
|
12147
12185
|
pos
|
|
12148
12186
|
);
|
|
12149
12187
|
}
|
|
@@ -12185,9 +12223,10 @@ var init_strict_resolver = __esm({
|
|
|
12185
12223
|
pointer: {
|
|
12186
12224
|
type: "keyOf" /* KeyOf */,
|
|
12187
12225
|
keyOf: { pointer: receiver.pointer, key: requested.pointer },
|
|
12188
|
-
...
|
|
12226
|
+
...nullPropagating ? { optional: true } : {}
|
|
12189
12227
|
},
|
|
12190
|
-
type:
|
|
12228
|
+
type: nullPropagating ? { ...receiver.type.elementType, nullable: true } : receiver.type.elementType,
|
|
12229
|
+
...nullPropagating ? { optionalChainType: receiver.type.elementType } : {},
|
|
12191
12230
|
...receiver.writability ? { writability: receiver.writability } : {}
|
|
12192
12231
|
};
|
|
12193
12232
|
}
|
|
@@ -12218,9 +12257,10 @@ var init_strict_resolver = __esm({
|
|
|
12218
12257
|
pointer: {
|
|
12219
12258
|
type: "keyOf" /* KeyOf */,
|
|
12220
12259
|
keyOf: { pointer: receiver.pointer, key: index.pointer },
|
|
12221
|
-
...
|
|
12260
|
+
...nullPropagating ? { optional: true } : {}
|
|
12222
12261
|
},
|
|
12223
|
-
type:
|
|
12262
|
+
type: nullPropagating ? { ...valueType, nullable: true } : valueType,
|
|
12263
|
+
...nullPropagating ? { optionalChainType: valueType } : {},
|
|
12224
12264
|
...receiver.writability ? { writability: receiver.writability } : {}
|
|
12225
12265
|
};
|
|
12226
12266
|
}
|
|
@@ -27285,6 +27325,16 @@ function projectCompletions(analysis, document, position) {
|
|
|
27285
27325
|
position
|
|
27286
27326
|
);
|
|
27287
27327
|
if (annotations) return { isIncomplete: false, items: annotations };
|
|
27328
|
+
const builtinMembers = projectBuiltinStaticMemberCompletions(
|
|
27329
|
+
document,
|
|
27330
|
+
position
|
|
27331
|
+
);
|
|
27332
|
+
if (builtinMembers) {
|
|
27333
|
+
return {
|
|
27334
|
+
isIncomplete: false,
|
|
27335
|
+
items: builtinMembers.map(projectBuiltinCompletionItem)
|
|
27336
|
+
};
|
|
27337
|
+
}
|
|
27288
27338
|
const members = projectMemberCompletions(analysis, document, position);
|
|
27289
27339
|
const variantScope = variantScopeInBody;
|
|
27290
27340
|
if (members || variantScope) {
|
|
@@ -27785,20 +27835,8 @@ function sourceTypeAt(document, position) {
|
|
|
27785
27835
|
return null;
|
|
27786
27836
|
}
|
|
27787
27837
|
function projectMemberCompletions(analysis, document, position) {
|
|
27788
|
-
const
|
|
27789
|
-
|
|
27790
|
-
// yet for completion purposes. Including a semicolon that starts at the
|
|
27791
|
-
// cursor makes `Device.|;` lose the dot it is completing.
|
|
27792
|
-
positionCompare2(token.range.start, position) < 0
|
|
27793
|
-
);
|
|
27794
|
-
let cursor = tokens.length - 1;
|
|
27795
|
-
const current = tokens[cursor];
|
|
27796
|
-
if (current?.kind === "identifier" && current.range.start.line === position.line) {
|
|
27797
|
-
cursor--;
|
|
27798
|
-
}
|
|
27799
|
-
if (tokens[cursor]?.text !== ".") return null;
|
|
27800
|
-
const owner = tokens[cursor - 1];
|
|
27801
|
-
if (!owner || owner.kind !== "identifier") return null;
|
|
27838
|
+
const owner = projectMemberCompletionOwnerToken(document, position);
|
|
27839
|
+
if (!owner) return null;
|
|
27802
27840
|
const resolvedOwner = projectSymbolAt(analysis, document, owner.range.start);
|
|
27803
27841
|
if (!resolvedOwner) return null;
|
|
27804
27842
|
const ownerNames = projectReceiverOwnerNames(analysis, resolvedOwner.symbol);
|
|
@@ -27816,6 +27854,71 @@ function projectMemberCompletions(analysis, document, position) {
|
|
|
27816
27854
|
}
|
|
27817
27855
|
return members.length > 0 ? members : null;
|
|
27818
27856
|
}
|
|
27857
|
+
function projectMemberCompletionOwnerToken(document, position) {
|
|
27858
|
+
const tokens = projectTokens(document).filter(
|
|
27859
|
+
(token) => token.kind !== "eof" && token.kind !== "comment" && // Auto-inserted/future punctuation at the cursor has not been authored
|
|
27860
|
+
// yet for completion purposes. Including a semicolon that starts at the
|
|
27861
|
+
// cursor makes `Device.|;` lose the dot it is completing.
|
|
27862
|
+
positionCompare2(token.range.start, position) < 0
|
|
27863
|
+
);
|
|
27864
|
+
let cursor = tokens.length - 1;
|
|
27865
|
+
const current = tokens[cursor];
|
|
27866
|
+
if (current?.kind === "identifier" && current.range.start.line === position.line) {
|
|
27867
|
+
cursor--;
|
|
27868
|
+
}
|
|
27869
|
+
if (tokens[cursor]?.text !== ".") return null;
|
|
27870
|
+
const owner = tokens[cursor - 1];
|
|
27871
|
+
if (!owner || owner.kind !== "identifier" && owner.kind !== "type") {
|
|
27872
|
+
return null;
|
|
27873
|
+
}
|
|
27874
|
+
return owner;
|
|
27875
|
+
}
|
|
27876
|
+
function projectBuiltinStaticMemberCompletions(document, position) {
|
|
27877
|
+
const owner = projectMemberCompletionOwnerToken(document, position);
|
|
27878
|
+
if (!owner) return null;
|
|
27879
|
+
const type = NEOSCRIPT_BUILTIN_TYPE_SYMBOLS.find(
|
|
27880
|
+
(candidate) => candidate.name === owner.text
|
|
27881
|
+
);
|
|
27882
|
+
if (!type) return null;
|
|
27883
|
+
const members = type.members.filter((member) => member.static === true);
|
|
27884
|
+
return members.length > 0 ? members : null;
|
|
27885
|
+
}
|
|
27886
|
+
function projectBuiltinCompletionItem(symbol) {
|
|
27887
|
+
return {
|
|
27888
|
+
label: symbol.name,
|
|
27889
|
+
kind: projectBuiltinCompletionKind(symbol),
|
|
27890
|
+
detail: projectBuiltinSymbolSignature(symbol),
|
|
27891
|
+
...symbol.documentation ? { documentation: symbol.documentation } : {},
|
|
27892
|
+
insertText: symbol.name,
|
|
27893
|
+
symbolId: symbol.id
|
|
27894
|
+
};
|
|
27895
|
+
}
|
|
27896
|
+
function projectBuiltinCompletionKind(symbol) {
|
|
27897
|
+
switch (symbol.kind) {
|
|
27898
|
+
case "property":
|
|
27899
|
+
case "field":
|
|
27900
|
+
return "property";
|
|
27901
|
+
case "method":
|
|
27902
|
+
return "method";
|
|
27903
|
+
case "function":
|
|
27904
|
+
return "function";
|
|
27905
|
+
case "enumMember":
|
|
27906
|
+
return "enumMember";
|
|
27907
|
+
default:
|
|
27908
|
+
return "value";
|
|
27909
|
+
}
|
|
27910
|
+
}
|
|
27911
|
+
function projectBuiltinSymbolSignature(symbol) {
|
|
27912
|
+
if (symbol.parameters !== void 0) {
|
|
27913
|
+
const parameters = symbol.parameters.map((parameter4) => `${formatType(parameter4.type)} ${parameter4.name}`).join(", ");
|
|
27914
|
+
return `${formatType(symbol.returnType ?? symbol.type)} ${symbol.name}(${parameters})`;
|
|
27915
|
+
}
|
|
27916
|
+
if (symbol.kind === "property" || symbol.kind === "field") {
|
|
27917
|
+
const setter = symbol.writable ? " set;" : "";
|
|
27918
|
+
return `${formatType(symbol.type)} ${symbol.name} { get;${setter} }`;
|
|
27919
|
+
}
|
|
27920
|
+
return `${formatType(symbol.type)} ${symbol.name}`;
|
|
27921
|
+
}
|
|
27819
27922
|
function projectConstructorArgumentCompletions(analysis, document, position) {
|
|
27820
27923
|
const tokens = tokensBeforePosition(document.text, position);
|
|
27821
27924
|
const openIndex = activeCallOpenIndex(tokens, position);
|
|
@@ -28187,6 +28290,31 @@ function projectHover(analysis, document, position) {
|
|
|
28187
28290
|
}
|
|
28188
28291
|
const body = projectBodySnapshotAt(analysis, document, position);
|
|
28189
28292
|
if (body) return hover(body, position);
|
|
28293
|
+
const builtin = projectBuiltinSymbolAt(document, position);
|
|
28294
|
+
if (builtin) {
|
|
28295
|
+
if (builtin.symbol) {
|
|
28296
|
+
const documentation3 = builtin.symbol.documentation ? `
|
|
28297
|
+
|
|
28298
|
+
${builtin.symbol.documentation}` : "";
|
|
28299
|
+
return {
|
|
28300
|
+
range: builtin.token.range,
|
|
28301
|
+
markdown: `**${builtin.symbol.name}** _${builtin.symbol.kind}_
|
|
28302
|
+
|
|
28303
|
+
\`${projectBuiltinSymbolSignature(builtin.symbol)}\`${documentation3}
|
|
28304
|
+
|
|
28305
|
+
Schema id: \`${builtin.symbol.id}\``
|
|
28306
|
+
};
|
|
28307
|
+
}
|
|
28308
|
+
const documentation2 = builtin.type.documentation ? `
|
|
28309
|
+
|
|
28310
|
+
${builtin.type.documentation}` : "";
|
|
28311
|
+
return {
|
|
28312
|
+
range: builtin.token.range,
|
|
28313
|
+
markdown: `**${builtin.type.name}** _${builtin.type.kind}_${documentation2}
|
|
28314
|
+
|
|
28315
|
+
Schema id: \`${builtin.type.id}\``
|
|
28316
|
+
};
|
|
28317
|
+
}
|
|
28190
28318
|
const resolved = projectSymbolAt(analysis, document, position);
|
|
28191
28319
|
if (!resolved) return null;
|
|
28192
28320
|
const owner = resolved.symbol.ownerName ? ` on \`${resolved.symbol.ownerName}\`` : "";
|
|
@@ -28203,6 +28331,30 @@ ID: \`${resolved.symbol.id}\`` : "\n\nPending ID";
|
|
|
28203
28331
|
markdown: `**${resolved.symbol.kind}** \`${resolved.symbol.name}\`${detail}${owner}${documentation}${contract}${id2}`
|
|
28204
28332
|
};
|
|
28205
28333
|
}
|
|
28334
|
+
function projectBuiltinSymbolAt(document, position) {
|
|
28335
|
+
const token = projectTokenAt(document, position);
|
|
28336
|
+
if (!token || token.kind !== "identifier" && token.kind !== "type") {
|
|
28337
|
+
return null;
|
|
28338
|
+
}
|
|
28339
|
+
const tokens = projectTokens(document);
|
|
28340
|
+
const tokenIndex = tokens.findIndex(
|
|
28341
|
+
(candidate) => candidate.start === token.start && candidate.end === token.end
|
|
28342
|
+
);
|
|
28343
|
+
const owner = tokens[tokenIndex - 1]?.text === "." ? tokens[tokenIndex - 2] : void 0;
|
|
28344
|
+
if (owner?.kind === "identifier" || owner?.kind === "type") {
|
|
28345
|
+
const type2 = NEOSCRIPT_BUILTIN_TYPE_SYMBOLS.find(
|
|
28346
|
+
(candidate) => candidate.name === owner.text
|
|
28347
|
+
);
|
|
28348
|
+
const symbol = type2?.members.find(
|
|
28349
|
+
(candidate) => candidate.static === true && candidate.name === token.text
|
|
28350
|
+
);
|
|
28351
|
+
if (type2 && symbol) return { token, type: type2, symbol };
|
|
28352
|
+
}
|
|
28353
|
+
const type = NEOSCRIPT_BUILTIN_TYPE_SYMBOLS.find(
|
|
28354
|
+
(candidate) => candidate.name === token.text
|
|
28355
|
+
);
|
|
28356
|
+
return type ? { token, type } : null;
|
|
28357
|
+
}
|
|
28206
28358
|
function projectConstructionContractMarkdown(analysis, className) {
|
|
28207
28359
|
const index = projectConstructionIndex(analysis);
|
|
28208
28360
|
const contract = classConstructionContract(index, className);
|
|
@@ -29358,6 +29510,7 @@ var init_project_source_language_features = __esm({
|
|
|
29358
29510
|
init_language_spec();
|
|
29359
29511
|
init_project_source_semantics();
|
|
29360
29512
|
init_project_source_variants();
|
|
29513
|
+
init_project();
|
|
29361
29514
|
init_project_source_semantics();
|
|
29362
29515
|
init_project_source_settlement();
|
|
29363
29516
|
init_project_source_tokens();
|
|
@@ -67143,6 +67296,7 @@ function isRuntimeFileValue(value) {
|
|
|
67143
67296
|
return typeof fileId === "string" && fileId.length > 0;
|
|
67144
67297
|
}
|
|
67145
67298
|
function isRuntimeSpriteValue(value) {
|
|
67299
|
+
if (isEmptySpriteValue(value)) return true;
|
|
67146
67300
|
if (!isRuntimeFileValue(value)) return false;
|
|
67147
67301
|
const sliceIndex = value.sliceIndex;
|
|
67148
67302
|
return typeof sliceIndex === "number" && Number.isInteger(sliceIndex) && sliceIndex >= 0;
|
|
@@ -111261,7 +111415,7 @@ var init_registry2 = __esm({
|
|
|
111261
111415
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
111262
111416
|
formatVersion: 3,
|
|
111263
111417
|
contractVersion: "3.13",
|
|
111264
|
-
cliVersion: "0.31.
|
|
111418
|
+
cliVersion: "0.31.9",
|
|
111265
111419
|
projectFileUploadBatchSize: 32,
|
|
111266
111420
|
documentRecords: {
|
|
111267
111421
|
member: {
|
|
@@ -117856,7 +118010,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
117856
118010
|
async function main() {
|
|
117857
118011
|
const args = parseArgs(process.argv.slice(2));
|
|
117858
118012
|
if (args.command === "--version") {
|
|
117859
|
-
console.log("0.31.
|
|
118013
|
+
console.log("0.31.9");
|
|
117860
118014
|
return;
|
|
117861
118015
|
}
|
|
117862
118016
|
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.31.
|
|
86
|
+
<!-- reviewed-through-cli: 0.31.9 -->
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -49,8 +49,17 @@ if (player.Target != null) {
|
|
|
49
49
|
return player.Target?.Name ?? "Unknown";
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
Null propagation remains active across following required accesses in the same
|
|
53
|
+
chain, so `config.Hat?.Head.Idle.Down.Frames` safely returns null when `Hat` is
|
|
54
|
+
null. A descendant that is itself nullable still needs its own `?.`, `??`, `!`,
|
|
55
|
+
or narrowing guard before the next access.
|
|
56
|
+
|
|
52
57
|
Treat lookup-return values with the same nullable narrowing rules.
|
|
53
58
|
|
|
59
|
+
Use `SpriteInfo.Empty` when a required sprite should intentionally render no
|
|
60
|
+
image. It is the canonical non-null empty sprite: it has no backing file and
|
|
61
|
+
uses slice index zero.
|
|
62
|
+
|
|
54
63
|
Let runtime ownership—not body kind—decide whether a write target is Immutable,
|
|
55
64
|
Save, Session, Setter, or otherwise writable. A constructor writes only its
|
|
56
65
|
`this` instance. A writable structured-leaf field still inherits the receiver's
|