@neocompose/cli 0.34.0 → 0.34.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.34.2] - 2026-08-19
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Treat unknown top-level document fields with a JSON `null` value as absent
|
|
8
|
+
while continuing to reject unknown non-null authored data, so harmless fields
|
|
9
|
+
emitted by an older CLI do not block project commands.
|
|
10
|
+
|
|
11
|
+
## [0.34.1] - 2026-08-19
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Accept the advertised positional `NeoLookupVariantFolder<TObject, TValue>`
|
|
16
|
+
constructor form and lower it identically to named `path`, `collection`, and
|
|
17
|
+
`collectionValue` arguments.
|
|
18
|
+
- Preserve lookup-variant member `TValue` through the CLI/server document
|
|
19
|
+
boundary under the canonical `valueTypeInfo` field, including an open generic
|
|
20
|
+
parameter authored by an enclosing class.
|
|
21
|
+
- Give `neo test` the candidate project's variants and variant folders, so
|
|
22
|
+
variants declared in the same pending push resolve alongside root values and
|
|
23
|
+
declared list indexes.
|
|
24
|
+
|
|
3
25
|
## [0.34.0] - 2026-08-19
|
|
4
26
|
|
|
5
27
|
### Added
|
package/dist/neo.mjs
CHANGED
|
@@ -18762,7 +18762,7 @@ var init_project_schema_contract_generated = __esm({
|
|
|
18762
18762
|
"../packages/neoscript-language/src/project-schema-contract.generated.ts"() {
|
|
18763
18763
|
"use strict";
|
|
18764
18764
|
PROJECT_SCHEMA_MANIFEST_FORMAT_VERSION = 3;
|
|
18765
|
-
PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.
|
|
18765
|
+
PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.14";
|
|
18766
18766
|
PROJECT_FILE_UPLOAD_BATCH_SIZE = 32;
|
|
18767
18767
|
NEO_PROJECT_SOURCE_RECORD_CONTRACT = {
|
|
18768
18768
|
"recordFields": {
|
|
@@ -18804,7 +18804,7 @@ var init_project_schema_contract_generated = __esm({
|
|
|
18804
18804
|
"collectionValueId",
|
|
18805
18805
|
"declaredTypeInfo",
|
|
18806
18806
|
"targetTypeInfo",
|
|
18807
|
-
"
|
|
18807
|
+
"valueTypeInfo",
|
|
18808
18808
|
"dialogueGroupId",
|
|
18809
18809
|
"code",
|
|
18810
18810
|
"setterCode",
|
|
@@ -20934,10 +20934,20 @@ var init_project_source_construction_diagnostics = __esm({
|
|
|
20934
20934
|
});
|
|
20935
20935
|
|
|
20936
20936
|
// ../packages/neoscript-language/src/project-source-variants.ts
|
|
20937
|
+
function neoLookupVariantFolderArgument(expression, name) {
|
|
20938
|
+
const index = expression.args.findIndex((_, argumentIndex) => {
|
|
20939
|
+
const authoredName = expression.argumentNames?.[argumentIndex];
|
|
20940
|
+
return (authoredName ?? NEO_LOOKUP_VARIANT_FOLDER_CONSTRUCTOR_ARGUMENTS[argumentIndex]?.name ?? null) === name;
|
|
20941
|
+
});
|
|
20942
|
+
return index < 0 ? void 0 : expression.args[index];
|
|
20943
|
+
}
|
|
20937
20944
|
function neoVariantConstructionSiteCall(className, argumentNames, initializerNames) {
|
|
20938
20945
|
if (className === NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME) {
|
|
20946
|
+
const logicalNames = argumentNames.map(
|
|
20947
|
+
(name, index) => name ?? NEO_LOOKUP_VARIANT_FOLDER_CONSTRUCTOR_ARGUMENTS[index]?.name ?? null
|
|
20948
|
+
);
|
|
20939
20949
|
return {
|
|
20940
|
-
argumentNames:
|
|
20950
|
+
argumentNames: logicalNames.filter(
|
|
20941
20951
|
(name) => name !== "collection" && name !== "collectionValue"
|
|
20942
20952
|
),
|
|
20943
20953
|
initializerNames
|
|
@@ -21001,21 +21011,14 @@ function neoVariantFolderAnnotationSymbol(annotations) {
|
|
|
21001
21011
|
function folderPath(declaration) {
|
|
21002
21012
|
const expression = parseInitializer(declaration);
|
|
21003
21013
|
if (expression === null || expression.kind !== "new") return null;
|
|
21004
|
-
const
|
|
21005
|
-
(name) => name === "path"
|
|
21006
|
-
);
|
|
21007
|
-
const argument2 = expression.args[pathIndex !== void 0 && pathIndex >= 0 ? pathIndex : 0];
|
|
21014
|
+
const argument2 = neoLookupVariantFolderArgument(expression, "path");
|
|
21008
21015
|
if (argument2 === void 0 || argument2.kind !== "litString") return null;
|
|
21009
21016
|
return argument2.value;
|
|
21010
21017
|
}
|
|
21011
21018
|
function folderCollectionPath(declaration) {
|
|
21012
21019
|
const expression = parseInitializer(declaration);
|
|
21013
21020
|
if (expression === null || expression.kind !== "new") return null;
|
|
21014
|
-
const
|
|
21015
|
-
(name) => name === "collection"
|
|
21016
|
-
);
|
|
21017
|
-
if (index === void 0 || index < 0) return null;
|
|
21018
|
-
const argument2 = expression.args[index];
|
|
21021
|
+
const argument2 = neoLookupVariantFolderArgument(expression, "collection");
|
|
21019
21022
|
if (argument2 === void 0) return null;
|
|
21020
21023
|
const parts = [];
|
|
21021
21024
|
let cursor = argument2;
|
|
@@ -21746,7 +21749,7 @@ function variantDiagnostic(entry, range2, code, message) {
|
|
|
21746
21749
|
message
|
|
21747
21750
|
};
|
|
21748
21751
|
}
|
|
21749
|
-
var NEO_VARIANT_CONSTRUCTOR_ARGUMENTS, NEO_VARIANT_MEMBER_ARGUMENTS, dottedScope;
|
|
21752
|
+
var NEO_VARIANT_CONSTRUCTOR_ARGUMENTS, NEO_LOOKUP_VARIANT_FOLDER_CONSTRUCTOR_ARGUMENTS, NEO_VARIANT_MEMBER_ARGUMENTS, dottedScope;
|
|
21750
21753
|
var init_project_source_variants = __esm({
|
|
21751
21754
|
"../packages/neoscript-language/src/project-source-variants.ts"() {
|
|
21752
21755
|
"use strict";
|
|
@@ -21760,6 +21763,11 @@ var init_project_source_variants = __esm({
|
|
|
21760
21763
|
"overrides",
|
|
21761
21764
|
"childOverrides"
|
|
21762
21765
|
];
|
|
21766
|
+
NEO_LOOKUP_VARIANT_FOLDER_CONSTRUCTOR_ARGUMENTS = [
|
|
21767
|
+
{ name: "path", type: "string" },
|
|
21768
|
+
{ name: "collection", type: "List<TValue>" },
|
|
21769
|
+
{ name: "collectionValue", type: "Reference<List<TValue>>" }
|
|
21770
|
+
];
|
|
21763
21771
|
NEO_VARIANT_MEMBER_ARGUMENTS = /* @__PURE__ */ new Map([
|
|
21764
21772
|
["overrides", "Overrides"],
|
|
21765
21773
|
["childOverrides", "ChildOverrides"]
|
|
@@ -23847,7 +23855,8 @@ function validateExpression(expression, expected, scope, environment, uri, range
|
|
|
23847
23855
|
) ?? [];
|
|
23848
23856
|
const overload = declaration && declaration.constructors.length > 0 ? matchingDeclaredConstructor(declaration, expression.argumentNames) : null;
|
|
23849
23857
|
expression.args.forEach((argument2, index) => {
|
|
23850
|
-
const
|
|
23858
|
+
const authoredName = expression.argumentNames?.[index];
|
|
23859
|
+
const named = declaration.name === NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME ? authoredName ?? NEO_LOOKUP_VARIANT_FOLDER_CONSTRUCTOR_ARGUMENTS[index]?.name : authoredName;
|
|
23851
23860
|
if (declaration.name === NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME && named === "collection") {
|
|
23852
23861
|
return;
|
|
23853
23862
|
}
|
|
@@ -29003,11 +29012,7 @@ function projectConstructorArgumentCompletions(analysis, document, position) {
|
|
|
29003
29012
|
}
|
|
29004
29013
|
function lookupVariantFolderArgumentFields(typeName) {
|
|
29005
29014
|
if (typeName !== NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME) return null;
|
|
29006
|
-
return
|
|
29007
|
-
{ name: "path", type: "string" },
|
|
29008
|
-
{ name: "collection", type: "List<TValue>" },
|
|
29009
|
-
{ name: "collectionValue", type: "Reference<List<TValue>>" }
|
|
29010
|
-
];
|
|
29015
|
+
return NEO_LOOKUP_VARIANT_FOLDER_CONSTRUCTOR_ARGUMENTS;
|
|
29011
29016
|
}
|
|
29012
29017
|
function declaredConstructorNamedArguments(analysis, typeName, used) {
|
|
29013
29018
|
const contract = classConstructionContract(
|
|
@@ -34866,7 +34871,7 @@ var init_document_contracts = __esm({
|
|
|
34866
34871
|
"collectionValueId",
|
|
34867
34872
|
"declaredTypeInfo",
|
|
34868
34873
|
"targetTypeInfo",
|
|
34869
|
-
"
|
|
34874
|
+
"valueTypeInfo",
|
|
34870
34875
|
"dialogueGroupId",
|
|
34871
34876
|
"code",
|
|
34872
34877
|
"setterCode",
|
|
@@ -34905,6 +34910,7 @@ var init_document_contracts = __esm({
|
|
|
34905
34910
|
collectionValueId: "missingIsNullOnFullMember",
|
|
34906
34911
|
declaredTypeInfo: "nullIsAbsent",
|
|
34907
34912
|
targetTypeInfo: "nullIsAbsent",
|
|
34913
|
+
valueTypeInfo: "nullIsAbsent",
|
|
34908
34914
|
dialogueGroupId: "missingIsNullOnFullMember",
|
|
34909
34915
|
templateId: "missingIsNullOnFullMember",
|
|
34910
34916
|
setterCode: "nullIsAbsent",
|
|
@@ -35166,8 +35172,9 @@ function fieldDisposition(recordKind, field) {
|
|
|
35166
35172
|
return null;
|
|
35167
35173
|
}
|
|
35168
35174
|
function assertKnownDocumentFields(recordKind, value) {
|
|
35169
|
-
for (const field of Object.
|
|
35175
|
+
for (const [field, fieldValue] of Object.entries(value)) {
|
|
35170
35176
|
if (fieldDisposition(recordKind, field) !== null) continue;
|
|
35177
|
+
if (fieldValue === null) continue;
|
|
35171
35178
|
throw new SchemaDocumentContractError(recordKind, field);
|
|
35172
35179
|
}
|
|
35173
35180
|
}
|
|
@@ -35182,6 +35189,7 @@ function partitionDocumentFields(recordKind, value) {
|
|
|
35182
35189
|
if (fieldValue === void 0) continue;
|
|
35183
35190
|
const disposition = fieldDisposition(recordKind, field);
|
|
35184
35191
|
if (disposition === null) {
|
|
35192
|
+
if (fieldValue === null) continue;
|
|
35185
35193
|
throw new SchemaDocumentContractError(recordKind, field);
|
|
35186
35194
|
}
|
|
35187
35195
|
result[disposition][field] = fieldValue;
|
|
@@ -35192,6 +35200,11 @@ function normalizeDocumentFields(recordKind, value) {
|
|
|
35192
35200
|
assertKnownDocumentFields(recordKind, value);
|
|
35193
35201
|
const contract = SCHEMA_DOCUMENT_FIELD_CONTRACTS[recordKind];
|
|
35194
35202
|
const normalized = deepOmitUndefined(value);
|
|
35203
|
+
for (const [field, fieldValue] of Object.entries(normalized)) {
|
|
35204
|
+
if (fieldValue === null && fieldDisposition(recordKind, field) === null) {
|
|
35205
|
+
delete normalized[field];
|
|
35206
|
+
}
|
|
35207
|
+
}
|
|
35195
35208
|
for (const [field, rule] of Object.entries(contract.normalization)) {
|
|
35196
35209
|
const current = normalized[field];
|
|
35197
35210
|
if (rule === "nullIsAbsent") {
|
|
@@ -36335,10 +36348,10 @@ function memberFromDocument(record3, members, owners, classNames, context) {
|
|
|
36335
36348
|
record3,
|
|
36336
36349
|
"targetTypeInfo"
|
|
36337
36350
|
),
|
|
36338
|
-
valueType: field("
|
|
36339
|
-
field("
|
|
36351
|
+
valueType: field("valueTypeInfo", null) === null ? null : documentTypeToManifest(
|
|
36352
|
+
field("valueTypeInfo", void 0),
|
|
36340
36353
|
record3,
|
|
36341
|
-
"
|
|
36354
|
+
"valueTypeInfo"
|
|
36342
36355
|
)
|
|
36343
36356
|
};
|
|
36344
36357
|
}
|
|
@@ -36488,7 +36501,7 @@ function memberToDocumentFields(member, baseData3) {
|
|
|
36488
36501
|
}
|
|
36489
36502
|
if (member.kind === "variant") {
|
|
36490
36503
|
fields.targetTypeInfo = manifestTypeToDocument(member.targetType);
|
|
36491
|
-
fields.
|
|
36504
|
+
fields.valueTypeInfo = member.valueType === null ? null : manifestTypeToDocument(member.valueType);
|
|
36492
36505
|
}
|
|
36493
36506
|
if (member.kind === "generic") {
|
|
36494
36507
|
fields.genericParamId = member.genericParamId;
|
|
@@ -39692,10 +39705,10 @@ function assertMember2(value, path) {
|
|
|
39692
39705
|
member.valueType,
|
|
39693
39706
|
`${path}.valueType`
|
|
39694
39707
|
).kind;
|
|
39695
|
-
if (valueKind !== "class") {
|
|
39708
|
+
if (valueKind !== "class" && valueKind !== "generic") {
|
|
39696
39709
|
invalid(
|
|
39697
39710
|
`${path}.valueType.kind`,
|
|
39698
|
-
"a lookup variant member's TValue must be a collection entry class."
|
|
39711
|
+
"a lookup variant member's TValue must be a collection entry class or an open generic parameter."
|
|
39699
39712
|
);
|
|
39700
39713
|
}
|
|
39701
39714
|
}
|
|
@@ -44154,6 +44167,11 @@ function isMemberVariantBase(value) {
|
|
|
44154
44167
|
if (v.targetTypeInfo.type !== 7 /* Class */ && v.targetTypeInfo.type !== 21 /* Generic */) {
|
|
44155
44168
|
return false;
|
|
44156
44169
|
}
|
|
44170
|
+
if (v.valueTypeInfo !== void 0 && v.valueTypeInfo !== null && (!isNSTypeInfo(v.valueTypeInfo) || // P68's concrete folder binding resolves to a Class, while an unclosed
|
|
44171
|
+
// owner class can still spell the same TValue as its Generic parameter.
|
|
44172
|
+
v.valueTypeInfo.type !== 7 /* Class */ && v.valueTypeInfo.type !== 21 /* Generic */)) {
|
|
44173
|
+
return false;
|
|
44174
|
+
}
|
|
44157
44175
|
const defaultValue = v.defaultValue;
|
|
44158
44176
|
if (defaultValue === void 0 || defaultValue === null) return true;
|
|
44159
44177
|
if (!isMemberValueBase(defaultValue)) return false;
|
|
@@ -60262,13 +60280,11 @@ function folderBinding(context, global) {
|
|
|
60262
60280
|
`Lookup variant folder ${global.name} must be declared with new(...).`
|
|
60263
60281
|
);
|
|
60264
60282
|
}
|
|
60265
|
-
const
|
|
60266
|
-
|
|
60267
|
-
|
|
60268
|
-
|
|
60269
|
-
|
|
60270
|
-
const collection = named.get("collection");
|
|
60271
|
-
const collectionValue = named.get("collectionValue");
|
|
60283
|
+
const collection = neoLookupVariantFolderArgument(expression, "collection");
|
|
60284
|
+
const collectionValue = neoLookupVariantFolderArgument(
|
|
60285
|
+
expression,
|
|
60286
|
+
"collectionValue"
|
|
60287
|
+
);
|
|
60272
60288
|
const collectionPath = collection === void 0 ? null : dottedPath(collection);
|
|
60273
60289
|
if (collectionPath === null) {
|
|
60274
60290
|
throw new Error(
|
|
@@ -113164,8 +113180,8 @@ var init_registry2 = __esm({
|
|
|
113164
113180
|
"use strict";
|
|
113165
113181
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
113166
113182
|
formatVersion: 3,
|
|
113167
|
-
contractVersion: "3.
|
|
113168
|
-
cliVersion: "0.34.
|
|
113183
|
+
contractVersion: "3.14",
|
|
113184
|
+
cliVersion: "0.34.2",
|
|
113169
113185
|
projectFileUploadBatchSize: 32,
|
|
113170
113186
|
documentRecords: {
|
|
113171
113187
|
member: {
|
|
@@ -113207,7 +113223,7 @@ var init_registry2 = __esm({
|
|
|
113207
113223
|
"collectionValueId",
|
|
113208
113224
|
"declaredTypeInfo",
|
|
113209
113225
|
"targetTypeInfo",
|
|
113210
|
-
"
|
|
113226
|
+
"valueTypeInfo",
|
|
113211
113227
|
"dialogueGroupId",
|
|
113212
113228
|
"code",
|
|
113213
113229
|
"setterCode",
|
|
@@ -113246,6 +113262,7 @@ var init_registry2 = __esm({
|
|
|
113246
113262
|
collectionValueId: "missingIsNullOnFullMember",
|
|
113247
113263
|
declaredTypeInfo: "nullIsAbsent",
|
|
113248
113264
|
targetTypeInfo: "nullIsAbsent",
|
|
113265
|
+
valueTypeInfo: "nullIsAbsent",
|
|
113249
113266
|
dialogueGroupId: "missingIsNullOnFullMember",
|
|
113250
113267
|
templateId: "missingIsNullOnFullMember",
|
|
113251
113268
|
setterCode: "nullIsAbsent",
|
|
@@ -114652,6 +114669,8 @@ function sharedEvaluatorBase(rawDocument) {
|
|
|
114652
114669
|
enums: document.enums,
|
|
114653
114670
|
interfaces: document.interfaces,
|
|
114654
114671
|
constructors,
|
|
114672
|
+
variants: document.variants,
|
|
114673
|
+
variantFolders: document.variantFolders,
|
|
114655
114674
|
projectFiles: document.projectFiles,
|
|
114656
114675
|
localizationConfig: document.localizationConfig,
|
|
114657
114676
|
localizedTexts: document.localizedTexts,
|
|
@@ -119764,7 +119783,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
119764
119783
|
async function main() {
|
|
119765
119784
|
const args = parseArgs(process.argv.slice(2));
|
|
119766
119785
|
if (args.command === "--version") {
|
|
119767
|
-
console.log("0.34.
|
|
119786
|
+
console.log("0.34.2");
|
|
119768
119787
|
return;
|
|
119769
119788
|
}
|
|
119770
119789
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/package.json
CHANGED
|
@@ -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.34.
|
|
12
|
+
<!-- reviewed-through-cli: 0.34.2 -->
|
|
13
13
|
|
|
14
14
|
# Neo Compose CLI
|
|
15
15
|
|
|
@@ -47,8 +47,9 @@ Treat pull followed immediately by status or dry-run as a semantic no-op. If it
|
|
|
47
47
|
reports project changes, stop and report a round-trip bug instead of pushing.
|
|
48
48
|
|
|
49
49
|
The compiler reports file:line:column diagnostics and fails closed. Unknown
|
|
50
|
-
authorable server fields require a CLI contract update; never preserve
|
|
51
|
-
opaque JSON or guessed syntax.
|
|
50
|
+
non-null authorable server fields require a CLI contract update; never preserve
|
|
51
|
+
them as opaque JSON or guessed syntax. An unknown top-level document field whose
|
|
52
|
+
value is exactly JSON `null` is treated as absent.
|
|
52
53
|
|
|
53
54
|
## Honor hard authoring invariants
|
|
54
55
|
|
|
@@ -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.34.
|
|
86
|
+
<!-- reviewed-through-cli: 0.34.2 -->
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
The quoted version above is checked too, so this instruction cannot go stale
|