@neocompose/cli 0.49.0 → 0.50.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,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.50.0] - 2026-09-11
|
|
4
|
+
|
|
5
|
+
- Expose tile placement assets with `@tile(VoidTile)` or `@tile(asset: VoidTile)`. Pull emits the tile class beside each placement; authored bindings resolve to the existing asset metadata.
|
|
6
|
+
- Add tile asset validation, completion, and class navigation to the shared language service.
|
|
7
|
+
|
|
3
8
|
## [0.49.0] - 2026-09-11
|
|
4
9
|
|
|
5
10
|
- Require every constructed object's non-nullable members to be supplied by a member default, constructor, or initializer. Missing values are now compile errors.
|
package/dist/neo.mjs
CHANGED
|
@@ -10166,6 +10166,14 @@ var init_strict_resolver = __esm({
|
|
|
10166
10166
|
);
|
|
10167
10167
|
}
|
|
10168
10168
|
case "annotated":
|
|
10169
|
+
if (expression.annotations.some(
|
|
10170
|
+
(annotation2) => annotation2.name === "tile"
|
|
10171
|
+
)) {
|
|
10172
|
+
throw new CompileError(
|
|
10173
|
+
"@tile is only supported on persisted literal placements, not executable NeoScript constructions.",
|
|
10174
|
+
expression.pos
|
|
10175
|
+
);
|
|
10176
|
+
}
|
|
10169
10177
|
return this.resolveExpression(expression.expression, scope, expected);
|
|
10170
10178
|
case "binary":
|
|
10171
10179
|
return this.resolveBinary(expression, scope);
|
|
@@ -17880,6 +17888,55 @@ var init_project_source_registry = __esm({
|
|
|
17880
17888
|
}
|
|
17881
17889
|
});
|
|
17882
17890
|
|
|
17891
|
+
// ../packages/neoscript-language/src/project-source-tile.ts
|
|
17892
|
+
function tileAssetAnnotation(expression) {
|
|
17893
|
+
if (expression.kind !== "annotated") return null;
|
|
17894
|
+
const annotations = expression.annotations.filter(
|
|
17895
|
+
(entry) => entry.name === "tile"
|
|
17896
|
+
);
|
|
17897
|
+
const annotation2 = annotations[0];
|
|
17898
|
+
if (annotation2 === void 0) return null;
|
|
17899
|
+
if (annotations.length > 1) {
|
|
17900
|
+
throw new CompileError(
|
|
17901
|
+
"A placement can have only one @tile annotation.",
|
|
17902
|
+
annotations[1].pos
|
|
17903
|
+
);
|
|
17904
|
+
}
|
|
17905
|
+
if (expression.expression.kind !== "new") {
|
|
17906
|
+
throw new CompileError(
|
|
17907
|
+
"@tile requires a NeoTileInstance construction.",
|
|
17908
|
+
annotation2.pos
|
|
17909
|
+
);
|
|
17910
|
+
}
|
|
17911
|
+
if (annotation2.args.length !== 1) {
|
|
17912
|
+
throw new CompileError(
|
|
17913
|
+
"@tile requires exactly one tile class: @tile(VoidTile) or @tile(asset: VoidTile).",
|
|
17914
|
+
annotation2.pos
|
|
17915
|
+
);
|
|
17916
|
+
}
|
|
17917
|
+
const name = annotation2.argumentNames?.[0];
|
|
17918
|
+
if (name != null && name !== "asset") {
|
|
17919
|
+
throw new CompileError(
|
|
17920
|
+
`@tile has no '${name}' option. Use 'asset'.`,
|
|
17921
|
+
annotation2.pos
|
|
17922
|
+
);
|
|
17923
|
+
}
|
|
17924
|
+
const asset = annotation2.args[0];
|
|
17925
|
+
if (asset.kind !== "ident") {
|
|
17926
|
+
throw new CompileError(
|
|
17927
|
+
"@tile asset must name a concrete tile class.",
|
|
17928
|
+
asset.pos
|
|
17929
|
+
);
|
|
17930
|
+
}
|
|
17931
|
+
return asset.name;
|
|
17932
|
+
}
|
|
17933
|
+
var init_project_source_tile = __esm({
|
|
17934
|
+
"../packages/neoscript-language/src/project-source-tile.ts"() {
|
|
17935
|
+
"use strict";
|
|
17936
|
+
init_strict_compile_error();
|
|
17937
|
+
}
|
|
17938
|
+
});
|
|
17939
|
+
|
|
17883
17940
|
// ../packages/neoscript-language/src/project-schema-contract.generated.ts
|
|
17884
17941
|
var PROJECT_FILE_UPLOAD_BATCH_SIZE, NEO_PROJECT_SOURCE_RECORD_CONTRACT;
|
|
17885
17942
|
var init_project_schema_contract_generated = __esm({
|
|
@@ -22911,7 +22968,48 @@ function validateExpression(expression, expected, scope, environment, uri, range
|
|
|
22911
22968
|
return;
|
|
22912
22969
|
}
|
|
22913
22970
|
if (expression.kind === "annotated") {
|
|
22971
|
+
const assetName = tileAssetAnnotation(expression);
|
|
22972
|
+
if (assetName !== null) {
|
|
22973
|
+
const constructed = expression.expression;
|
|
22974
|
+
const className = constructed.kind === "new" ? constructed.className ?? expected?.name : void 0;
|
|
22975
|
+
const asset = environment.types.get(assetName);
|
|
22976
|
+
if (!className || !classExtends(className, "NeoTileInstance", environment, /* @__PURE__ */ new Set())) {
|
|
22977
|
+
pushDiagnostic(
|
|
22978
|
+
diagnostics,
|
|
22979
|
+
uri,
|
|
22980
|
+
range2,
|
|
22981
|
+
"invalid-tile-placement",
|
|
22982
|
+
"@tile requires a NeoTileInstance construction."
|
|
22983
|
+
);
|
|
22984
|
+
}
|
|
22985
|
+
if (!asset || !classExtends(assetName, "NeoTile", environment, /* @__PURE__ */ new Set())) {
|
|
22986
|
+
pushDiagnostic(
|
|
22987
|
+
diagnostics,
|
|
22988
|
+
uri,
|
|
22989
|
+
range2,
|
|
22990
|
+
"invalid-tile-asset",
|
|
22991
|
+
`@tile asset '${assetName}' must name a tile class.`
|
|
22992
|
+
);
|
|
22993
|
+
} else if (asset.modifiers.includes("abstract")) {
|
|
22994
|
+
pushDiagnostic(
|
|
22995
|
+
diagnostics,
|
|
22996
|
+
uri,
|
|
22997
|
+
range2,
|
|
22998
|
+
"invalid-tile-asset",
|
|
22999
|
+
`@tile asset '${assetName}' must be a concrete tile class.`
|
|
23000
|
+
);
|
|
23001
|
+
} else if (asset.genericParameters.length > 0) {
|
|
23002
|
+
pushDiagnostic(
|
|
23003
|
+
diagnostics,
|
|
23004
|
+
uri,
|
|
23005
|
+
range2,
|
|
23006
|
+
"invalid-tile-asset",
|
|
23007
|
+
`@tile asset '${assetName}' must be a non-generic tile class.`
|
|
23008
|
+
);
|
|
23009
|
+
}
|
|
23010
|
+
}
|
|
22914
23011
|
for (const annotation2 of expression.annotations) {
|
|
23012
|
+
if (annotation2.name === "tile") continue;
|
|
22915
23013
|
validateInlineAnnotation(
|
|
22916
23014
|
annotation2,
|
|
22917
23015
|
environment,
|
|
@@ -23444,7 +23542,7 @@ function validateInlineAnnotation(annotation2, environment, uri, range2, diagnos
|
|
|
23444
23542
|
uri,
|
|
23445
23543
|
range2,
|
|
23446
23544
|
"invalid-inline-annotation",
|
|
23447
|
-
`Only @id
|
|
23545
|
+
`Only @id and @tile are valid on an inline persisted value; got @${annotation2.name}.`
|
|
23448
23546
|
);
|
|
23449
23547
|
return;
|
|
23450
23548
|
}
|
|
@@ -24011,6 +24109,7 @@ var init_project_source_semantics = __esm({
|
|
|
24011
24109
|
"../packages/neoscript-language/src/project-source-semantics.ts"() {
|
|
24012
24110
|
"use strict";
|
|
24013
24111
|
init_project_local_values();
|
|
24112
|
+
init_project_source_tile();
|
|
24014
24113
|
init_language_spec();
|
|
24015
24114
|
init_project_schema_contract_generated();
|
|
24016
24115
|
init_strict_compile_error();
|
|
@@ -27739,6 +27838,28 @@ function projectCompletions(analysis, document, position) {
|
|
|
27739
27838
|
items: [...script.items, variantScopeInBody]
|
|
27740
27839
|
};
|
|
27741
27840
|
}
|
|
27841
|
+
const tileCall = activeTileAnnotation(document, position);
|
|
27842
|
+
if (tileCall) {
|
|
27843
|
+
const items = analysis.symbols.filter(
|
|
27844
|
+
(symbol) => symbol.kind === "class" && projectTypeNameAssignable(analysis, symbol.name, "NeoTile")
|
|
27845
|
+
).filter((symbol) => {
|
|
27846
|
+
const declaration = analysis.documents.get(symbol.location.uri)?.declarations.find(
|
|
27847
|
+
(entry) => entry.kind === "class" && entry.name === symbol.name
|
|
27848
|
+
);
|
|
27849
|
+
return declaration?.kind === "class" && !declaration.modifiers.includes("abstract") && declaration.genericParameters.length === 0;
|
|
27850
|
+
}).map((symbol) => ({
|
|
27851
|
+
label: symbol.name,
|
|
27852
|
+
kind: "class",
|
|
27853
|
+
insertText: symbol.name
|
|
27854
|
+
}));
|
|
27855
|
+
if (!tileCall.named)
|
|
27856
|
+
items.unshift({
|
|
27857
|
+
label: "asset",
|
|
27858
|
+
kind: "property",
|
|
27859
|
+
insertText: "asset: "
|
|
27860
|
+
});
|
|
27861
|
+
return { isIncomplete: false, items };
|
|
27862
|
+
}
|
|
27742
27863
|
const annotations = projectAnnotationCompletions(
|
|
27743
27864
|
analysis,
|
|
27744
27865
|
document,
|
|
@@ -27864,12 +27985,32 @@ function projectCompletions(analysis, document, position) {
|
|
|
27864
27985
|
}
|
|
27865
27986
|
return projectFallbackCompletions(analysis, document, position);
|
|
27866
27987
|
}
|
|
27988
|
+
function isTileAssetToken(tokens, index) {
|
|
27989
|
+
const open = tokens[index - 1]?.text === ":" && tokens[index - 2]?.text === "asset" ? index - 3 : index - 1;
|
|
27990
|
+
return tokens[index + 1]?.text !== ":" && tokens[open]?.text === "(" && tokens[open - 1]?.text === "tile" && tokens[open - 2]?.text === "@";
|
|
27991
|
+
}
|
|
27992
|
+
function activeTileAnnotation(document, position) {
|
|
27993
|
+
const tokens = projectTokens(document);
|
|
27994
|
+
const open = activeCallOpenIndex(tokens, position);
|
|
27995
|
+
if (tokens[open - 1]?.text !== "tile" || tokens[open - 2]?.text !== "@")
|
|
27996
|
+
return null;
|
|
27997
|
+
const before = tokens.slice(open + 1).filter((token) => positionCompare2(token.range.start, position) < 0);
|
|
27998
|
+
if (before.some((token) => token.text === ",")) return null;
|
|
27999
|
+
const named = before.some((token) => token.text === ":");
|
|
28000
|
+
return { named };
|
|
28001
|
+
}
|
|
27867
28002
|
function projectAnnotationCompletions(analysis, document, position) {
|
|
27868
28003
|
const source = new SourceText(document.text);
|
|
27869
28004
|
const offset = source.offsetAt(position);
|
|
27870
28005
|
const word = projectWordRange(document.text, offset);
|
|
27871
28006
|
if (document.text[word.start - 1] !== "@") return null;
|
|
27872
|
-
if (initializerRootAt(analysis, document, position))
|
|
28007
|
+
if (initializerRootAt(analysis, document, position)) {
|
|
28008
|
+
return ["id", "tile"].map((name) => ({
|
|
28009
|
+
label: `@${name}`,
|
|
28010
|
+
kind: "snippet",
|
|
28011
|
+
insertText: name
|
|
28012
|
+
}));
|
|
28013
|
+
}
|
|
27873
28014
|
const names = projectAnnotationNamesAt(analysis, document, position);
|
|
27874
28015
|
return names.map((name) => ({
|
|
27875
28016
|
label: `@${name}`,
|
|
@@ -29307,7 +29448,7 @@ function indexedProjectSymbolAt(analysis, document, position, index) {
|
|
|
29307
29448
|
);
|
|
29308
29449
|
const source = analysis.documents.get(document.uri);
|
|
29309
29450
|
const typePosition = source && sourceTypeAt(source, token.range.start);
|
|
29310
|
-
if (typePosition || sourceTokens[tokenIndex - 1]?.text === "new") {
|
|
29451
|
+
if (typePosition || sourceTokens[tokenIndex - 1]?.text === "new" || isTileAssetToken(sourceTokens, tokenIndex)) {
|
|
29311
29452
|
const types = candidates.filter(
|
|
29312
29453
|
(symbol) => symbol.kind === "class" || symbol.kind === "interface" || symbol.kind === "enum" || symbol.kind === "genericParameter"
|
|
29313
29454
|
);
|
|
@@ -29547,6 +29688,8 @@ function annotationSignatureParameters(name) {
|
|
|
29547
29688
|
switch (name) {
|
|
29548
29689
|
case "id":
|
|
29549
29690
|
return ["string id"];
|
|
29691
|
+
case "tile":
|
|
29692
|
+
return ["NeoTile class asset"];
|
|
29550
29693
|
case "settings":
|
|
29551
29694
|
return ["named settings"];
|
|
29552
29695
|
case "storage":
|
|
@@ -34012,6 +34155,7 @@ var init_src = __esm({
|
|
|
34012
34155
|
init_project_source_construction_quick_fixes();
|
|
34013
34156
|
init_project_source_manifest();
|
|
34014
34157
|
init_project_source_variants();
|
|
34158
|
+
init_project_source_tile();
|
|
34015
34159
|
init_project_source_parameter_defaults();
|
|
34016
34160
|
init_project_source_settlement();
|
|
34017
34161
|
init_project_source_parser();
|
|
@@ -52159,6 +52303,18 @@ function constructionMembers(classId, context) {
|
|
|
52159
52303
|
}
|
|
52160
52304
|
return result;
|
|
52161
52305
|
}
|
|
52306
|
+
function createMemberDefaultConstructionChecker(document) {
|
|
52307
|
+
const context = contextFor(document);
|
|
52308
|
+
return (member, genericEnv = /* @__PURE__ */ new Map()) => {
|
|
52309
|
+
const previousEnv = context.env;
|
|
52310
|
+
context.env = genericEnv;
|
|
52311
|
+
try {
|
|
52312
|
+
return defaultSettlesConstruction(member, context, /* @__PURE__ */ new Set());
|
|
52313
|
+
} finally {
|
|
52314
|
+
context.env = previousEnv;
|
|
52315
|
+
}
|
|
52316
|
+
};
|
|
52317
|
+
}
|
|
52162
52318
|
function storedValueSettlesConstruction(member, sourceValue, document, genericEnv) {
|
|
52163
52319
|
return valueSettlesConstruction(
|
|
52164
52320
|
member,
|
|
@@ -53450,7 +53606,8 @@ function createDefaultValueResolutionCache() {
|
|
|
53450
53606
|
materializationPlanByClassAndEnvironment: /* @__PURE__ */ new Map(),
|
|
53451
53607
|
resolvedMemberById: /* @__PURE__ */ new Map(),
|
|
53452
53608
|
storedSchemaByClassId: /* @__PURE__ */ new Map(),
|
|
53453
|
-
validatedInitializerContainers: /* @__PURE__ */ new WeakSet()
|
|
53609
|
+
validatedInitializerContainers: /* @__PURE__ */ new WeakSet(),
|
|
53610
|
+
memberDefaultConstructionChecker: null
|
|
53454
53611
|
};
|
|
53455
53612
|
}
|
|
53456
53613
|
function withIndexedDefaultValueDocument(document, options = {}) {
|
|
@@ -53504,6 +53661,13 @@ function withIndexedDefaultValueDocument(document, options = {}) {
|
|
|
53504
53661
|
cache.validatedInitializerContainers.add(value);
|
|
53505
53662
|
return true;
|
|
53506
53663
|
},
|
|
53664
|
+
memberDefaultSettlesConstruction: (member, environment) => {
|
|
53665
|
+
cache.memberDefaultConstructionChecker ??= createMemberDefaultConstructionChecker({
|
|
53666
|
+
...document,
|
|
53667
|
+
constructors: document.constructors ?? []
|
|
53668
|
+
});
|
|
53669
|
+
return cache.memberDefaultConstructionChecker(member, environment);
|
|
53670
|
+
},
|
|
53507
53671
|
createValueRow: options.createValueRow ?? document.createValueRow
|
|
53508
53672
|
};
|
|
53509
53673
|
indexed.storedInstanceMaterializationPlan = (classId, environment) => {
|
|
@@ -53549,6 +53713,10 @@ function directScalarDefaultBody(document, member) {
|
|
|
53549
53713
|
return { value: body.value, classId: body.classId };
|
|
53550
53714
|
}
|
|
53551
53715
|
function buildDefaultClassMaterializationPlan(document, classId, instanceEnv) {
|
|
53716
|
+
const settlesConstruction = document.memberDefaultSettlesConstruction ?? createMemberDefaultConstructionChecker({
|
|
53717
|
+
...document,
|
|
53718
|
+
constructors: document.constructors ?? []
|
|
53719
|
+
});
|
|
53552
53720
|
const merged = document.storedInstanceSchema?.(classId) ?? mergeStoredInstanceSchema(classId, document.classes, document.members);
|
|
53553
53721
|
return merged.flatMap((entry) => {
|
|
53554
53722
|
if (entry.memberId === null) return [];
|
|
@@ -53564,6 +53732,7 @@ function buildDefaultClassMaterializationPlan(document, classId, instanceEnv) {
|
|
|
53564
53732
|
{
|
|
53565
53733
|
schemaKey: entry.schemaKey,
|
|
53566
53734
|
member,
|
|
53735
|
+
defaultSettlesConstruction: settlesConstruction(member, instanceEnv),
|
|
53567
53736
|
directScalarBody: directScalarDefaultBody(document, member)
|
|
53568
53737
|
}
|
|
53569
53738
|
];
|
|
@@ -53772,6 +53941,7 @@ function buildDefaultMemberValue(args) {
|
|
|
53772
53941
|
for (const {
|
|
53773
53942
|
schemaKey,
|
|
53774
53943
|
member: resolvedChildMember,
|
|
53944
|
+
defaultSettlesConstruction: defaultSettlesConstruction2,
|
|
53775
53945
|
directScalarBody
|
|
53776
53946
|
} of member.payload === 1 /* Partial */ ? [] : materializationPlan) {
|
|
53777
53947
|
if (storageKeyReferencesParentClass(
|
|
@@ -53787,6 +53957,7 @@ function buildDefaultMemberValue(args) {
|
|
|
53787
53957
|
args.constructorRoot,
|
|
53788
53958
|
schemaKey,
|
|
53789
53959
|
resolvedChildMember,
|
|
53960
|
+
defaultSettlesConstruction2,
|
|
53790
53961
|
documentHasInitValueContent(
|
|
53791
53962
|
args.document,
|
|
53792
53963
|
resolvedChildMember.defaultValue
|
|
@@ -53794,7 +53965,7 @@ function buildDefaultMemberValue(args) {
|
|
|
53794
53965
|
)) {
|
|
53795
53966
|
continue;
|
|
53796
53967
|
}
|
|
53797
|
-
if (isRequiredMember2(resolvedChildMember) &&
|
|
53968
|
+
if (isRequiredMember2(resolvedChildMember) && !defaultSettlesConstruction2 && !(isMemberClassBase(resolvedChildMember) && resolvedChildMember.payload === 1 /* Partial */)) {
|
|
53798
53969
|
if (args.constructorRoot?.runsMemberInitializers === true) continue;
|
|
53799
53970
|
if (args.constructorRoot?.omitMissingRequired === true) continue;
|
|
53800
53971
|
throw new Error(
|
|
@@ -53804,6 +53975,7 @@ function buildDefaultMemberValue(args) {
|
|
|
53804
53975
|
if (!shouldMaterializeChildDefaultForRoot(
|
|
53805
53976
|
args.constructorRoot,
|
|
53806
53977
|
resolvedChildMember,
|
|
53978
|
+
defaultSettlesConstruction2,
|
|
53807
53979
|
documentHasInitValueContent(
|
|
53808
53980
|
args.document,
|
|
53809
53981
|
resolvedChildMember.defaultValue
|
|
@@ -54309,18 +54481,18 @@ function shouldMaterializeConstructorChildDefault(member, isInitializer = isInit
|
|
|
54309
54481
|
if (!isRequiredMember2(member)) return false;
|
|
54310
54482
|
return shouldMaterializeChildDefault(member);
|
|
54311
54483
|
}
|
|
54312
|
-
function skipProvidedConstructorSchemaKey(constructorRoot, schemaKey, member, isInitializer = isInitValueContent(member.defaultValue)) {
|
|
54484
|
+
function skipProvidedConstructorSchemaKey(constructorRoot, schemaKey, member, defaultSettlesConstruction2, isInitializer = isInitValueContent(member.defaultValue)) {
|
|
54313
54485
|
if (constructorRoot === void 0) return false;
|
|
54314
54486
|
if (!constructorRoot.providedSchemaKeys.has(schemaKey)) return false;
|
|
54315
54487
|
if (constructorRoot.runsMemberInitializers !== true) {
|
|
54316
54488
|
return !isInitializer;
|
|
54317
54489
|
}
|
|
54318
|
-
return
|
|
54490
|
+
return !isInitializer && !defaultSettlesConstruction2;
|
|
54319
54491
|
}
|
|
54320
|
-
function shouldMaterializeChildDefaultForRoot(constructorRoot, member, isInitializer = isInitValueContent(member.defaultValue)) {
|
|
54492
|
+
function shouldMaterializeChildDefaultForRoot(constructorRoot, member, defaultSettlesConstruction2, isInitializer = isInitValueContent(member.defaultValue)) {
|
|
54321
54493
|
if (constructorRoot === void 0)
|
|
54322
54494
|
return shouldMaterializeChildDefault(member);
|
|
54323
|
-
if (constructorRoot.omitMissingRequired === true &&
|
|
54495
|
+
if (constructorRoot.omitMissingRequired === true && !defaultSettlesConstruction2) {
|
|
54324
54496
|
return false;
|
|
54325
54497
|
}
|
|
54326
54498
|
if (constructorRoot.runsMemberInitializers === true) {
|
|
@@ -113956,7 +114128,18 @@ function animationConstructorProjectionTargetValueIds(context, classId, value) {
|
|
|
113956
114128
|
}
|
|
113957
114129
|
return targetIds;
|
|
113958
114130
|
}
|
|
113959
|
-
function
|
|
114131
|
+
function isTileInstanceClass(classId, classes) {
|
|
114132
|
+
const visited = /* @__PURE__ */ new Set();
|
|
114133
|
+
while (typeof classId === "string" && !visited.has(classId)) {
|
|
114134
|
+
visited.add(classId);
|
|
114135
|
+
const schemaClass2 = classes.get(classId);
|
|
114136
|
+
if (isObjectRecord2(schemaClass2?.system) && schemaClass2.system.worldKind === "tileInstance")
|
|
114137
|
+
return true;
|
|
114138
|
+
classId = schemaClass2?.extendsClassId;
|
|
114139
|
+
}
|
|
114140
|
+
return false;
|
|
114141
|
+
}
|
|
114142
|
+
function rowBackedDefaultBody(member, isPulledValueRow, classes) {
|
|
113960
114143
|
if (member.modifier === 3) return null;
|
|
113961
114144
|
const defaultValue = member.defaultValue;
|
|
113962
114145
|
if (!isObjectRecord2(defaultValue)) return null;
|
|
@@ -113965,7 +114148,10 @@ function rowBackedDefaultBody(member, isPulledValueRow) {
|
|
|
113965
114148
|
(child) => typeof child === "string" && isPulledValueRow(child)
|
|
113966
114149
|
);
|
|
113967
114150
|
if (member.kind === MEMBER_KIND_CLASS2 && isObjectRecord2(body)) {
|
|
113968
|
-
const children =
|
|
114151
|
+
const children = isTileInstanceClass(
|
|
114152
|
+
defaultValue.classId ?? member.classId,
|
|
114153
|
+
classes
|
|
114154
|
+
) ? Object.entries(body).filter(([key]) => key !== "assetClassId" && key !== "variantId").map(([, value]) => value) : Object.values(body);
|
|
113969
114155
|
return referencesRows(children) ? { kind: "class", body } : null;
|
|
113970
114156
|
}
|
|
113971
114157
|
if (member.kind === MEMBER_KIND_LIST2 && member.listKind !== "unordered" && Array.isArray(body)) {
|
|
@@ -113981,15 +114167,18 @@ function rowBackedDefaultBody(member, isPulledValueRow) {
|
|
|
113981
114167
|
}
|
|
113982
114168
|
function rowBackedDefaultMemberIdsV4(state) {
|
|
113983
114169
|
const values = /* @__PURE__ */ new Set();
|
|
114170
|
+
const classes = /* @__PURE__ */ new Map();
|
|
113984
114171
|
for (const record4 of Object.values(state)) {
|
|
113985
114172
|
if (record4.recordKind === "value") values.add(record4.recordId);
|
|
114173
|
+
if (record4.recordKind === "class" && isObjectRecord2(record4.data))
|
|
114174
|
+
classes.set(record4.recordId, record4.data);
|
|
113986
114175
|
}
|
|
113987
114176
|
const result = /* @__PURE__ */ new Set();
|
|
113988
114177
|
for (const record4 of Object.values(state)) {
|
|
113989
114178
|
if (record4.recordKind !== "member" || !isObjectRecord2(record4.data)) {
|
|
113990
114179
|
continue;
|
|
113991
114180
|
}
|
|
113992
|
-
if (rowBackedDefaultBody(record4.data, (id2) => values.has(id2)) !== null) {
|
|
114181
|
+
if (rowBackedDefaultBody(record4.data, (id2) => values.has(id2), classes) !== null) {
|
|
113993
114182
|
result.add(record4.recordId);
|
|
113994
114183
|
}
|
|
113995
114184
|
}
|
|
@@ -114023,7 +114212,11 @@ function emitMemberDefaultSourcesV4(records2, manifest) {
|
|
|
114023
114212
|
context.localizedTextIds.clear();
|
|
114024
114213
|
continue;
|
|
114025
114214
|
}
|
|
114026
|
-
const backed = rowBackedDefaultBody(
|
|
114215
|
+
const backed = rowBackedDefaultBody(
|
|
114216
|
+
member,
|
|
114217
|
+
(id2) => context.values.has(id2),
|
|
114218
|
+
context.manifestClasses
|
|
114219
|
+
);
|
|
114027
114220
|
if (backed === null) continue;
|
|
114028
114221
|
const visited = /* @__PURE__ */ new Set();
|
|
114029
114222
|
const environment = declaringClassGenericEnvironment(context, member);
|
|
@@ -114750,7 +114943,11 @@ function lowerMemberDefaultSourcesV4(state, analysis, manifest, options = {}) {
|
|
|
114750
114943
|
});
|
|
114751
114944
|
continue;
|
|
114752
114945
|
}
|
|
114753
|
-
const backed = baseData3 === null || requiresEvaluation ? null : rowBackedDefaultBody(
|
|
114946
|
+
const backed = baseData3 === null || requiresEvaluation ? null : rowBackedDefaultBody(
|
|
114947
|
+
baseData3,
|
|
114948
|
+
(id2) => pulledValueIds.has(id2),
|
|
114949
|
+
context.classes
|
|
114950
|
+
);
|
|
114754
114951
|
if (backed !== null && baseData3 !== null) {
|
|
114755
114952
|
const existingReconstructedKeys = new Set(context.reconstructed.keys());
|
|
114756
114953
|
const existingPendingValueIds = new Set(context.pendingValues.keys());
|
|
@@ -115349,9 +115546,11 @@ function classGenericEnvironment(context, classId) {
|
|
|
115349
115546
|
function lowerRowBackedDefault(context, member, backed, baseData3, binding) {
|
|
115350
115547
|
const baseDefault = isObjectRecord2(baseData3.defaultValue) ? baseData3.defaultValue : {};
|
|
115351
115548
|
const storedClassId = stringOrNull2(baseDefault.classId);
|
|
115352
|
-
const
|
|
115353
|
-
|
|
115354
|
-
|
|
115549
|
+
const sourceExpression = parseCachedInitializer(
|
|
115550
|
+
context.parsedInitializers,
|
|
115551
|
+
binding.initializer
|
|
115552
|
+
);
|
|
115553
|
+
const expression = annotatedValue(sourceExpression).expression;
|
|
115355
115554
|
const bindingEnvironment = bindingGenericEnvironment(context, binding);
|
|
115356
115555
|
if (member.kind === "class" && backed.kind === "class") {
|
|
115357
115556
|
if (expression.kind === "litNull") {
|
|
@@ -115390,6 +115589,21 @@ function lowerRowBackedDefault(context, member, backed, baseData3, binding) {
|
|
|
115390
115589
|
);
|
|
115391
115590
|
const baseBody = backed.body;
|
|
115392
115591
|
const body = {};
|
|
115592
|
+
if (isTileInstanceClass(classId, context.classes) && isObjectRecord2(baseBody)) {
|
|
115593
|
+
for (const key of ["assetClassId", "assetValueId", "variantId"]) {
|
|
115594
|
+
if (baseBody[key] !== void 0) body[key] = baseBody[key];
|
|
115595
|
+
}
|
|
115596
|
+
if (typeof body.assetValueId === "string") {
|
|
115597
|
+
retainStoredValueSubgraph(
|
|
115598
|
+
context,
|
|
115599
|
+
body.assetValueId,
|
|
115600
|
+
binding.source,
|
|
115601
|
+
/* @__PURE__ */ new Set(),
|
|
115602
|
+
null,
|
|
115603
|
+
environment
|
|
115604
|
+
);
|
|
115605
|
+
}
|
|
115606
|
+
}
|
|
115393
115607
|
lowerConstructorProjections(
|
|
115394
115608
|
context,
|
|
115395
115609
|
schemaClass2,
|
|
@@ -115449,7 +115663,10 @@ function lowerRowBackedDefault(context, member, backed, baseData3, binding) {
|
|
|
115449
115663
|
);
|
|
115450
115664
|
}
|
|
115451
115665
|
return {
|
|
115452
|
-
value:
|
|
115666
|
+
value: applyTileAnnotation(context, sourceExpression, {
|
|
115667
|
+
classId,
|
|
115668
|
+
value: body
|
|
115669
|
+
}).value,
|
|
115453
115670
|
classId: classId === currentClassId ? storedClassId : classId
|
|
115454
115671
|
};
|
|
115455
115672
|
}
|
|
@@ -115815,7 +116032,6 @@ function preserveReboundValue(context, currentValueId, nextValueId, binding) {
|
|
|
115815
116032
|
);
|
|
115816
116033
|
}
|
|
115817
116034
|
function lowerStaticSeed(context, member, sourceExpression, source, valueId) {
|
|
115818
|
-
const expression = annotatedValue(sourceExpression).expression;
|
|
115819
116035
|
const rows = /* @__PURE__ */ new Map();
|
|
115820
116036
|
const localizedTexts = /* @__PURE__ */ new Map();
|
|
115821
116037
|
const existingBindingMemberIds = new Set(
|
|
@@ -115826,7 +116042,7 @@ function lowerStaticSeed(context, member, sourceExpression, source, valueId) {
|
|
|
115826
116042
|
const root = lowerSeedRow(
|
|
115827
116043
|
context,
|
|
115828
116044
|
member,
|
|
115829
|
-
|
|
116045
|
+
sourceExpression,
|
|
115830
116046
|
source,
|
|
115831
116047
|
valueId,
|
|
115832
116048
|
source.label,
|
|
@@ -115880,7 +116096,8 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
|
|
|
115880
116096
|
localizedTexts,
|
|
115881
116097
|
containerId,
|
|
115882
116098
|
inheritedEnvironment,
|
|
115883
|
-
authoredSlice
|
|
116099
|
+
authoredSlice,
|
|
116100
|
+
sourceExpression
|
|
115884
116101
|
);
|
|
115885
116102
|
}
|
|
115886
116103
|
if (!isStoredCallableLiteral(resolvedMember.kind, expression) && memberInitializerRequiresEvaluation(
|
|
@@ -115889,6 +116106,11 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
|
|
|
115889
116106
|
expression,
|
|
115890
116107
|
source
|
|
115891
116108
|
)) {
|
|
116109
|
+
if (tileAssetAnnotation(sourceExpression) !== null) {
|
|
116110
|
+
throw new Error(
|
|
116111
|
+
"@tile requires a literal placement construction. Construct NeoTileInstance directly and assign its members in the initializer."
|
|
116112
|
+
);
|
|
116113
|
+
}
|
|
115892
116114
|
const unattachedId = annotated.id === null ? unattachedAuthoredRowId(authoredSlice) : null;
|
|
115893
116115
|
if (unattachedId !== null) {
|
|
115894
116116
|
throw new Error(
|
|
@@ -116204,6 +116426,10 @@ function lowerSeedRow(context, member, sourceExpression, source, valueId, path,
|
|
|
116204
116426
|
value = lowered.value;
|
|
116205
116427
|
classId = typeof lowered.classId === "string" ? lowered.classId : null;
|
|
116206
116428
|
}
|
|
116429
|
+
value = applyTileAnnotation(context, sourceExpression, {
|
|
116430
|
+
classId,
|
|
116431
|
+
value
|
|
116432
|
+
}).value;
|
|
116207
116433
|
const row = {
|
|
116208
116434
|
nodeType: "literal",
|
|
116209
116435
|
id: valueId,
|
|
@@ -116288,7 +116514,7 @@ function structurallyConstructedClassId(context, member, expression) {
|
|
|
116288
116514
|
if (expression.args.length === 0) return null;
|
|
116289
116515
|
return effective.id;
|
|
116290
116516
|
}
|
|
116291
|
-
function lowerStructuralConstructionRow(context, member, expression, source, valueId, path, rows, localizedTexts, containerId, inheritedEnvironment, authoredSlice) {
|
|
116517
|
+
function lowerStructuralConstructionRow(context, member, expression, source, valueId, path, rows, localizedTexts, containerId, inheritedEnvironment, authoredSlice, annotatedExpression = expression) {
|
|
116292
116518
|
const effectiveClass = constructedClass(
|
|
116293
116519
|
context,
|
|
116294
116520
|
member,
|
|
@@ -116416,7 +116642,10 @@ function lowerStructuralConstructionRow(context, member, expression, source, val
|
|
|
116416
116642
|
nodeType: "literal",
|
|
116417
116643
|
id: valueId,
|
|
116418
116644
|
memberId: member.id,
|
|
116419
|
-
value,
|
|
116645
|
+
value: applyTileAnnotation(context, annotatedExpression, {
|
|
116646
|
+
classId: effectiveClass.id,
|
|
116647
|
+
value
|
|
116648
|
+
}).value,
|
|
116420
116649
|
classId: effectiveClass.id,
|
|
116421
116650
|
constructorArgs,
|
|
116422
116651
|
// Provenance is stamped explicitly on every construction this lowerer
|
|
@@ -116617,7 +116846,13 @@ function lowerValueRow(context, member, sourceExpression, expectedValueId, sourc
|
|
|
116617
116846
|
authoredSlice,
|
|
116618
116847
|
projectedConstructionEditable ? "reproject" : "preserve"
|
|
116619
116848
|
);
|
|
116620
|
-
addReconstructed(
|
|
116849
|
+
addReconstructed(
|
|
116850
|
+
context,
|
|
116851
|
+
"value",
|
|
116852
|
+
expectedValueId,
|
|
116853
|
+
applyTileAnnotation(context, sourceExpression, value2),
|
|
116854
|
+
source.source
|
|
116855
|
+
);
|
|
116621
116856
|
return expectedValueId;
|
|
116622
116857
|
}
|
|
116623
116858
|
const literalFields = valueFileFields(base);
|
|
@@ -116641,7 +116876,13 @@ function lowerValueRow(context, member, sourceExpression, expectedValueId, sourc
|
|
|
116641
116876
|
environment,
|
|
116642
116877
|
authoredSlice
|
|
116643
116878
|
);
|
|
116644
|
-
addReconstructed(
|
|
116879
|
+
addReconstructed(
|
|
116880
|
+
context,
|
|
116881
|
+
"value",
|
|
116882
|
+
expectedValueId,
|
|
116883
|
+
applyTileAnnotation(context, sourceExpression, value),
|
|
116884
|
+
source.source
|
|
116885
|
+
);
|
|
116645
116886
|
return expectedValueId;
|
|
116646
116887
|
}
|
|
116647
116888
|
function lowerValueBody(context, member, expression, base, source, environment, authoredSlice) {
|
|
@@ -118894,6 +119135,38 @@ function memberPath(expression) {
|
|
|
118894
119135
|
const receiver = memberPath(expression.receiver);
|
|
118895
119136
|
return receiver === null ? null : `${receiver}.${expression.name}`;
|
|
118896
119137
|
}
|
|
119138
|
+
function applyTileAnnotation(context, expression, value) {
|
|
119139
|
+
const assetName = tileAssetAnnotation(expression);
|
|
119140
|
+
if (assetName === null) return value;
|
|
119141
|
+
const instanceBase = requiredClassByName(context, "NeoTileInstance");
|
|
119142
|
+
if (typeof value.classId !== "string" || !classAssignableToClass2(context, value.classId, instanceBase.id)) {
|
|
119143
|
+
throw new Error("@tile requires a NeoTileInstance construction.");
|
|
119144
|
+
}
|
|
119145
|
+
const asset = requiredClassByName(context, assetName);
|
|
119146
|
+
const tileBase = requiredClassByName(context, "NeoTile");
|
|
119147
|
+
if (!classAssignableToClass2(context, asset.id, tileBase.id)) {
|
|
119148
|
+
throw new Error(`@tile asset '${assetName}' must name a tile class.`);
|
|
119149
|
+
}
|
|
119150
|
+
if (asset.declarationModifier === "abstract") {
|
|
119151
|
+
throw new Error(
|
|
119152
|
+
`@tile asset '${assetName}' must be a concrete tile class.`
|
|
119153
|
+
);
|
|
119154
|
+
}
|
|
119155
|
+
if (asset.genericParameters.length > 0) {
|
|
119156
|
+
throw new Error(
|
|
119157
|
+
`@tile asset '${assetName}' must be a non-generic tile class.`
|
|
119158
|
+
);
|
|
119159
|
+
}
|
|
119160
|
+
if (!isObjectRecord2(value.value))
|
|
119161
|
+
throw new Error("@tile requires a stored placement body.");
|
|
119162
|
+
const body = value.value;
|
|
119163
|
+
if (body.assetClassId !== asset.id && (body.assetValueId !== void 0 || body.variantId !== void 0)) {
|
|
119164
|
+
throw new Error(
|
|
119165
|
+
"Cannot change a tile asset while the placement has overrides or a variant. Recreate the placement to select a different tile."
|
|
119166
|
+
);
|
|
119167
|
+
}
|
|
119168
|
+
return { ...value, value: { ...body, assetClassId: asset.id } };
|
|
119169
|
+
}
|
|
118897
119170
|
function annotatedValue(expression) {
|
|
118898
119171
|
if (expression.kind !== "annotated") return { expression, id: null };
|
|
118899
119172
|
const id2 = annotationId2(expression.annotations);
|
|
@@ -119135,6 +119408,27 @@ function emitValueBody(context, member, value, visited, targetTyped, environment
|
|
|
119135
119408
|
);
|
|
119136
119409
|
}
|
|
119137
119410
|
function classValue(context, member, value, visited, targetTyped, outerEnvironment) {
|
|
119411
|
+
const source = classValueBody(
|
|
119412
|
+
context,
|
|
119413
|
+
member,
|
|
119414
|
+
value,
|
|
119415
|
+
visited,
|
|
119416
|
+
targetTyped,
|
|
119417
|
+
outerEnvironment
|
|
119418
|
+
);
|
|
119419
|
+
const assetId = isObjectRecord2(value.value) ? value.value.assetClassId : void 0;
|
|
119420
|
+
if (typeof assetId !== "string") return source;
|
|
119421
|
+
const classId = stringOrNull2(value.classId) ?? stringField3(member, "classId");
|
|
119422
|
+
if (!isTileInstanceClass(classId, context.manifestClasses)) return source;
|
|
119423
|
+
const asset = context.manifestClasses.get(assetId);
|
|
119424
|
+
if (asset === void 0)
|
|
119425
|
+
throw new Error(
|
|
119426
|
+
`Tile placement ${String(value.id)} references unknown asset class ${assetId}.`
|
|
119427
|
+
);
|
|
119428
|
+
return `@tile(${asset.name})
|
|
119429
|
+
${source}`;
|
|
119430
|
+
}
|
|
119431
|
+
function classValueBody(context, member, value, visited, targetTyped, outerEnvironment) {
|
|
119138
119432
|
if (value.value === null) return "null";
|
|
119139
119433
|
const partial = member.payload === 1 /* Partial */;
|
|
119140
119434
|
const classId = stringOrNull2(value.classId) ?? stringField3(member, "classId");
|
|
@@ -131846,7 +132140,7 @@ var init_registry2 = __esm({
|
|
|
131846
132140
|
"schema-contract/registry.mjs"() {
|
|
131847
132141
|
"use strict";
|
|
131848
132142
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
131849
|
-
cliVersion: "0.
|
|
132143
|
+
cliVersion: "0.50.0",
|
|
131850
132144
|
projectFileUploadBatchSize: 32,
|
|
131851
132145
|
documentRecords: {
|
|
131852
132146
|
member: {
|
|
@@ -138896,7 +139190,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
138896
139190
|
async function main() {
|
|
138897
139191
|
const args = parseArgs(process.argv.slice(2));
|
|
138898
139192
|
if (args.command === "--version") {
|
|
138899
|
-
console.log("0.
|
|
139193
|
+
console.log("0.50.0");
|
|
138900
139194
|
return;
|
|
138901
139195
|
}
|
|
138902
139196
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/package.json
CHANGED
|
@@ -24,6 +24,29 @@ For world layer links, derive a concrete project class from
|
|
|
24
24
|
`targetLayer` relation. Do not add value-level target metadata or ask painting
|
|
25
25
|
operations to create/repair relation targets.
|
|
26
26
|
|
|
27
|
+
## Tile placements
|
|
28
|
+
|
|
29
|
+
Use `@tile(VoidTile)` on a `NeoTileInstance` construction to select its tile
|
|
30
|
+
class. The named spelling `@tile(asset: VoidTile)` is equivalent; the asset is
|
|
31
|
+
required and only the argument label is optional.
|
|
32
|
+
|
|
33
|
+
```neo
|
|
34
|
+
@tile(VoidTile)
|
|
35
|
+
new NeoTileInstance() {
|
|
36
|
+
Cell = new(9, -4)
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Pull emits the positional spelling. The annotation writes the placement's
|
|
41
|
+
`assetClassId` metadata and does not construct a tile value or add a generic
|
|
42
|
+
argument. The asset must be a concrete, non-generic descendant of `NeoTile`.
|
|
43
|
+
Use the annotation on persisted literal constructions; executable NeoScript
|
|
44
|
+
and evaluated placement constructors reject it.
|
|
45
|
+
The grid's imports and the tile's compatible-layer relations still constrain
|
|
46
|
+
where the placement can be used. Existing placement overrides remain attached
|
|
47
|
+
when the selected asset is unchanged; recreate a placement to change its asset
|
|
48
|
+
when it has overrides or a variant.
|
|
49
|
+
|
|
27
50
|
## Object variants
|
|
28
51
|
|
|
29
52
|
A variant is a named configuration of one `NeoObject`-derived class: how to
|
|
@@ -88,7 +88,7 @@ wrappers.
|
|
|
88
88
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
89
89
|
|
|
90
90
|
```html
|
|
91
|
-
<!-- reviewed-through-cli: 0.
|
|
91
|
+
<!-- reviewed-through-cli: 0.50.0 -->
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
The quoted version above is checked too, so this instruction cannot go stale
|