@neocompose/cli 0.62.1 → 0.63.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 +15 -0
- package/README.md +17 -3
- package/dist/neo.mjs +403 -55
- package/dist/test-worker.mjs +48529 -0
- package/package.json +1 -1
- package/skills/neocompose-cli/SKILL.md +1 -1
- package/skills/neocompose-cli/references/cli-development.md +1 -1
- package/skills/neocompose-cli/references/commands-and-sync.md +14 -0
- package/skills/neocompose-cli/references/declarations-and-construction.md +6 -0
package/dist/neo.mjs
CHANGED
|
@@ -19678,6 +19678,7 @@ var init_project_schema_contract_generated = __esm({
|
|
|
19678
19678
|
"argumentTypes",
|
|
19679
19679
|
"dispatch",
|
|
19680
19680
|
"bodyMode",
|
|
19681
|
+
"effect",
|
|
19681
19682
|
"uiAction",
|
|
19682
19683
|
"templateId",
|
|
19683
19684
|
"genericParamId"
|
|
@@ -19881,6 +19882,10 @@ var init_project_schema_contract_generated = __esm({
|
|
|
19881
19882
|
"Sprite",
|
|
19882
19883
|
"Audio"
|
|
19883
19884
|
],
|
|
19885
|
+
"NeoEffectKind": [
|
|
19886
|
+
"None",
|
|
19887
|
+
"Auto"
|
|
19888
|
+
],
|
|
19884
19889
|
"NeoProjectRecordKind": [
|
|
19885
19890
|
"Project",
|
|
19886
19891
|
"Member",
|
|
@@ -24245,6 +24250,9 @@ function fieldsForAnnotation(name, context, environment) {
|
|
|
24245
24250
|
if (context.kind === "type") return null;
|
|
24246
24251
|
if (name === "storage") return storageFields(context);
|
|
24247
24252
|
if (name === "distribution") return distributionFields(context);
|
|
24253
|
+
if (name === "effect") {
|
|
24254
|
+
return context.kind === "member" && context.memberKind === "function" ? [{ name: "kind", type: "NeoEffectKind" }] : null;
|
|
24255
|
+
}
|
|
24248
24256
|
if (name === "relations") return relationFields(context, environment);
|
|
24249
24257
|
if (name === "system") {
|
|
24250
24258
|
return context.kind === "class" || context.kind === "schema" || context.kind === "member" ? markerFields("NeoSystemAttribute") : null;
|
|
@@ -27804,11 +27812,23 @@ function validateMembers(environment, diagnostics) {
|
|
|
27804
27812
|
);
|
|
27805
27813
|
}
|
|
27806
27814
|
}
|
|
27815
|
+
for (const member of ref.declaration.members) {
|
|
27816
|
+
const effect = effectAnnotation(member);
|
|
27817
|
+
if (effect === void 0) continue;
|
|
27818
|
+
diagnose(
|
|
27819
|
+
diagnostics,
|
|
27820
|
+
ref.uri,
|
|
27821
|
+
effect.nameRange,
|
|
27822
|
+
"invalid-effect",
|
|
27823
|
+
`Interface member '${ref.declaration.name}.${member.name}' cannot be an @effect; only class member functions can.`
|
|
27824
|
+
);
|
|
27825
|
+
}
|
|
27807
27826
|
validateInterfaceMemberConflicts(ref, environment, diagnostics);
|
|
27808
27827
|
}
|
|
27809
27828
|
for (const ref of environment.classes.values()) {
|
|
27810
27829
|
validateClassMemberModifiers(ref, environment, diagnostics);
|
|
27811
27830
|
validateClassOverrides(ref, environment, diagnostics);
|
|
27831
|
+
validateEffects(ref, environment, diagnostics);
|
|
27812
27832
|
if (ref.declaration.modifiers.includes("abstract")) {
|
|
27813
27833
|
validateAbstractInterfaceMembers(ref, environment, diagnostics);
|
|
27814
27834
|
} else {
|
|
@@ -28234,6 +28254,70 @@ function validateClassOverrides(ref, environment, diagnostics) {
|
|
|
28234
28254
|
}
|
|
28235
28255
|
}
|
|
28236
28256
|
}
|
|
28257
|
+
function validateEffects(ref, environment, diagnostics) {
|
|
28258
|
+
let inherited;
|
|
28259
|
+
for (const member of ref.declaration.members) {
|
|
28260
|
+
if (member.kind !== "function") continue;
|
|
28261
|
+
const annotation2 = effectAnnotation(member);
|
|
28262
|
+
let kind = annotation2 === void 0 ? void 0 : effectKind(annotation2);
|
|
28263
|
+
if (annotation2 === void 0) {
|
|
28264
|
+
if (!member.modifiers.includes("override") || !member.modifiers.includes("native")) {
|
|
28265
|
+
continue;
|
|
28266
|
+
}
|
|
28267
|
+
inherited ??= inheritedClassMembers(ref, environment);
|
|
28268
|
+
kind = inheritedEffectKind(inherited, member.name);
|
|
28269
|
+
}
|
|
28270
|
+
if (kind !== "Auto") continue;
|
|
28271
|
+
const problem = effectIneligibility(member);
|
|
28272
|
+
if (problem === null) continue;
|
|
28273
|
+
diagnose(
|
|
28274
|
+
diagnostics,
|
|
28275
|
+
ref.uri,
|
|
28276
|
+
annotation2?.nameRange ?? member.nameRange,
|
|
28277
|
+
"invalid-effect",
|
|
28278
|
+
`'${ref.declaration.name}.${member.name}' cannot be an @effect: ${problem}.`
|
|
28279
|
+
);
|
|
28280
|
+
}
|
|
28281
|
+
}
|
|
28282
|
+
function effectAnnotation(member) {
|
|
28283
|
+
return member.annotations.find((entry) => entry.name === "effect");
|
|
28284
|
+
}
|
|
28285
|
+
function effectKind(annotation2) {
|
|
28286
|
+
if (annotation2.arguments.length === 0) return "Auto";
|
|
28287
|
+
const argument2 = annotation2.arguments.find((entry) => entry.name === "kind") ?? annotation2.arguments.find((entry) => entry.name === void 0);
|
|
28288
|
+
if (argument2 === void 0) return void 0;
|
|
28289
|
+
let expression;
|
|
28290
|
+
try {
|
|
28291
|
+
expression = parseExpression(argument2.text);
|
|
28292
|
+
} catch (error) {
|
|
28293
|
+
if (error instanceof CompileError) return void 0;
|
|
28294
|
+
throw error;
|
|
28295
|
+
}
|
|
28296
|
+
return expression.kind === "contextualEnum" ? expression.name : void 0;
|
|
28297
|
+
}
|
|
28298
|
+
function inheritedEffectKind(inherited, name) {
|
|
28299
|
+
for (let index = inherited.length - 1; index >= 0; index -= 1) {
|
|
28300
|
+
const view = inherited[index];
|
|
28301
|
+
if (!namesEqual(view.member.name, name)) continue;
|
|
28302
|
+
const annotation2 = effectAnnotation(view.member);
|
|
28303
|
+
if (annotation2 !== void 0) return effectKind(annotation2);
|
|
28304
|
+
}
|
|
28305
|
+
return void 0;
|
|
28306
|
+
}
|
|
28307
|
+
function effectIneligibility(member) {
|
|
28308
|
+
if (member.modifiers.includes("static")) {
|
|
28309
|
+
return "a static function has no instance to run for";
|
|
28310
|
+
}
|
|
28311
|
+
if (member.modifiers.includes("native")) {
|
|
28312
|
+
return "a native function has no NeoScript reads to track";
|
|
28313
|
+
}
|
|
28314
|
+
if (member.modifiers.includes("async")) {
|
|
28315
|
+
return "an effect runs immediately and cannot be async";
|
|
28316
|
+
}
|
|
28317
|
+
if (member.type.name !== "void") return "an effect must return void";
|
|
28318
|
+
if (member.parameters.length > 0) return "an effect takes no parameters";
|
|
28319
|
+
return null;
|
|
28320
|
+
}
|
|
28237
28321
|
function isPlatformImplementedSystemMember(member) {
|
|
28238
28322
|
if (!member.modifiers.includes("protected")) return false;
|
|
28239
28323
|
return member.annotations.some((entry) => entry.name === "system");
|
|
@@ -28699,6 +28783,8 @@ var init_project_source_type_checker = __esm({
|
|
|
28699
28783
|
init_language_spec();
|
|
28700
28784
|
init_project_source_ast();
|
|
28701
28785
|
init_lexer();
|
|
28786
|
+
init_executable_parser();
|
|
28787
|
+
init_strict_compile_error();
|
|
28702
28788
|
init_project_source_accessors();
|
|
28703
28789
|
init_project_source_identifiers();
|
|
28704
28790
|
BUILTIN_ARITY = /* @__PURE__ */ new Map([
|
|
@@ -30106,6 +30192,7 @@ function projectDeclarationAnnotationNames(declaration) {
|
|
|
30106
30192
|
}
|
|
30107
30193
|
function projectMemberAnnotationNames(member) {
|
|
30108
30194
|
const names = ["id", "settings", "storage", "distribution"];
|
|
30195
|
+
if (member?.kind === "function") names.push("effect");
|
|
30109
30196
|
if (member?.type.name === "List") names.push("index", "column");
|
|
30110
30197
|
return names;
|
|
30111
30198
|
}
|
|
@@ -31770,6 +31857,8 @@ function annotationSignatureParameters(name) {
|
|
|
31770
31857
|
return ["StorageKind allowed"];
|
|
31771
31858
|
case "distribution":
|
|
31772
31859
|
return ["NeoSubtreeDistribution kind"];
|
|
31860
|
+
case "effect":
|
|
31861
|
+
return ["NeoEffectKind kind"];
|
|
31773
31862
|
case "relations":
|
|
31774
31863
|
return ["relation descriptors"];
|
|
31775
31864
|
case "incomplete":
|
|
@@ -38122,6 +38211,7 @@ var init_args = __esm({
|
|
|
38122
38211
|
"generate-ids",
|
|
38123
38212
|
"help",
|
|
38124
38213
|
"passWithNoTests",
|
|
38214
|
+
"runInBand",
|
|
38125
38215
|
"no-verify",
|
|
38126
38216
|
"fix",
|
|
38127
38217
|
"yes"
|
|
@@ -38173,9 +38263,11 @@ var init_args = __esm({
|
|
|
38173
38263
|
"outputFile",
|
|
38174
38264
|
"output-file",
|
|
38175
38265
|
"testNamePattern",
|
|
38266
|
+
"maxWorkers",
|
|
38176
38267
|
"test-timeout",
|
|
38177
38268
|
"testTimeout",
|
|
38178
38269
|
"passWithNoTests",
|
|
38270
|
+
"runInBand",
|
|
38179
38271
|
"no-verify"
|
|
38180
38272
|
]);
|
|
38181
38273
|
TEST_ONLY_FLAGS = /* @__PURE__ */ new Set([
|
|
@@ -38183,9 +38275,11 @@ var init_args = __esm({
|
|
|
38183
38275
|
"outputFile",
|
|
38184
38276
|
"output-file",
|
|
38185
38277
|
"testNamePattern",
|
|
38278
|
+
"maxWorkers",
|
|
38186
38279
|
"test-timeout",
|
|
38187
38280
|
"testTimeout",
|
|
38188
|
-
"passWithNoTests"
|
|
38281
|
+
"passWithNoTests",
|
|
38282
|
+
"runInBand"
|
|
38189
38283
|
]);
|
|
38190
38284
|
}
|
|
38191
38285
|
});
|
|
@@ -40016,7 +40110,7 @@ function assertMemberInvariants(member, path) {
|
|
|
40016
40110
|
fail2("script", "is required for a concrete scripted member.");
|
|
40017
40111
|
}
|
|
40018
40112
|
}
|
|
40019
|
-
var nonEmptyString, nullableString2, nullableId, finiteNumber, nullableNumber, nullableInteger, jsonValueSchema, schemaSourcePositionSchema, schemaSourceSpanSchema, schemaSourceSymbolKinds, schemaSourceIdentitySchema, memberSourceIdentitySchema, systemProtectionKindSchema, worldSystemClassKindSchema, schemaSystemMetadataSchema, schemaGenericBindingSchema, schemaGenericBindingRecordSchema, genericConstraintSchema, schemaGenericParameterSchema, primitiveTypeKinds, schemaTypeCache, returnTypeCache, schemaTypeSchema, schemaFunctionReturnTypeSchema, schemaParameterDefaultSchema, schemaFunctionArgumentSchema, memberOwnerSchema, schemaDefaultValueSchema, propertyScriptSchema, functionScriptSchema, commonMemberEntries, schemaMemberCommonSchema, simpleMemberSchemas, dictionaryKeySchema, schemaListIndexSchema, schemaListColumnSchema, callableEntries, schemaMemberSchema, SchemaMemberContractError;
|
|
40113
|
+
var nonEmptyString, nullableString2, nullableId, finiteNumber, nullableNumber, nullableInteger, jsonValueSchema, schemaSourcePositionSchema, schemaSourceSpanSchema, schemaSourceSymbolKinds, schemaSourceIdentitySchema, memberSourceIdentitySchema, systemProtectionKindSchema, worldSystemClassKindSchema, schemaSystemMetadataSchema, schemaGenericBindingSchema, schemaGenericBindingRecordSchema, genericConstraintSchema, schemaGenericParameterSchema, primitiveTypeKinds, schemaTypeCache, returnTypeCache, schemaTypeSchema, schemaFunctionReturnTypeSchema, schemaParameterDefaultSchema, schemaFunctionArgumentSchema, memberOwnerSchema, schemaDefaultValueSchema, propertyScriptSchema, functionScriptSchema, commonMemberEntries, schemaMemberCommonSchema, simpleMemberSchemas, dictionaryKeySchema, schemaListIndexSchema, schemaListColumnSchema, callableEntries, functionEffectSchema, schemaMemberSchema, SchemaMemberContractError;
|
|
40020
40114
|
var init_schema_member = __esm({
|
|
40021
40115
|
"../packages/manifest/src/schema-member.ts"() {
|
|
40022
40116
|
"use strict";
|
|
@@ -40341,6 +40435,7 @@ var init_schema_member = __esm({
|
|
|
40341
40435
|
returnType: schemaFunctionReturnTypeSchema,
|
|
40342
40436
|
arguments: array2(schemaFunctionArgumentSchema)
|
|
40343
40437
|
};
|
|
40438
|
+
functionEffectSchema = optional(picklist(["none", "auto"]));
|
|
40344
40439
|
schemaMemberSchema = variant("kind", [
|
|
40345
40440
|
...simpleMemberSchemas,
|
|
40346
40441
|
memberSchema("int", {
|
|
@@ -40403,11 +40498,13 @@ var init_schema_member = __esm({
|
|
|
40403
40498
|
}),
|
|
40404
40499
|
memberSchema("function", {
|
|
40405
40500
|
...callableEntries,
|
|
40406
|
-
deferred: boolean2()
|
|
40501
|
+
deferred: boolean2(),
|
|
40502
|
+
effect: functionEffectSchema
|
|
40407
40503
|
}),
|
|
40408
40504
|
memberSchema("scriptFunction", {
|
|
40409
40505
|
...callableEntries,
|
|
40410
40506
|
deferred: boolean2(),
|
|
40507
|
+
effect: functionEffectSchema,
|
|
40411
40508
|
bodyMode: optional(literal2("ui")),
|
|
40412
40509
|
uiAction: optional(jsonValueSchema),
|
|
40413
40510
|
script: nullable(functionScriptSchema)
|
|
@@ -40498,6 +40595,7 @@ var init_document_contracts = __esm({
|
|
|
40498
40595
|
"argumentTypes",
|
|
40499
40596
|
"dispatch",
|
|
40500
40597
|
"bodyMode",
|
|
40598
|
+
"effect",
|
|
40501
40599
|
"uiAction",
|
|
40502
40600
|
"templateId",
|
|
40503
40601
|
"genericParamId"
|
|
@@ -42202,12 +42300,24 @@ function memberFromDocument(record6, members, owners, classNames, context) {
|
|
|
42202
42300
|
FUNCTION_DISPATCH,
|
|
42203
42301
|
record6,
|
|
42204
42302
|
"dispatch"
|
|
42205
|
-
) === "asynchronous"
|
|
42303
|
+
) === "asynchronous",
|
|
42304
|
+
// The row's own value, not the chain's: an override without `@effect`
|
|
42305
|
+
// inherits, and resolving here would emit the ancestor's kind back
|
|
42306
|
+
// into the override's source as phantom drift.
|
|
42307
|
+
...data.effect === void 0 || data.effect === null ? {} : {
|
|
42308
|
+
effect: ordinalValue(
|
|
42309
|
+
data.effect,
|
|
42310
|
+
FUNCTION_EFFECT,
|
|
42311
|
+
record6,
|
|
42312
|
+
"effect"
|
|
42313
|
+
)
|
|
42314
|
+
}
|
|
42206
42315
|
};
|
|
42207
42316
|
if (kind === MEMBER_KIND.Function) {
|
|
42208
42317
|
return { ...common, kind: "function", ...signature };
|
|
42209
42318
|
}
|
|
42210
|
-
const
|
|
42319
|
+
const codeValue = field("code", null);
|
|
42320
|
+
const code = codeValue === "" ? "" : optionalStringOrNull(codeValue);
|
|
42211
42321
|
const bodyModeValue = ordinalValue(
|
|
42212
42322
|
field("bodyMode", 0),
|
|
42213
42323
|
FUNCTION_BODY,
|
|
@@ -42453,6 +42563,9 @@ function memberToDocumentFields(member, baseData3) {
|
|
|
42453
42563
|
if (member.deferred || isOverride) {
|
|
42454
42564
|
fields.dispatch = member.deferred ? 1 : 0;
|
|
42455
42565
|
}
|
|
42566
|
+
if (member.effect !== void 0) {
|
|
42567
|
+
fields.effect = FUNCTION_EFFECT.indexOf(member.effect);
|
|
42568
|
+
}
|
|
42456
42569
|
if (member.kind === "scriptFunction" && member.script !== null && member.bodyMode !== "ui") {
|
|
42457
42570
|
fields.code = member.script.sourceText;
|
|
42458
42571
|
}
|
|
@@ -43247,7 +43360,7 @@ function invalidDocument(record6, path, message) {
|
|
|
43247
43360
|
`${record6.recordKind}:${record6.recordId}.${path} ${message}.`
|
|
43248
43361
|
);
|
|
43249
43362
|
}
|
|
43250
|
-
var MEMBER_KIND, MEMBER_MODIFIERS, MEMBER_ACCESS, MEMBER_STORAGE, MEMBER_DISTRIBUTION, STRING_FORMAT, MEMBER_SEARCH_BY, MEMBER_SELECTION, FUNCTION_DISPATCH, FUNCTION_BODY, MEMBER_PAYLOAD, DICTIONARY_KEY, LIST_KIND, LIST_INDEX, COLUMN_VISIBILITY, COLUMN_PIN, COLUMN_OVERFLOW, GENERIC_BINDING, TYPE_KIND_BY_MEMBER_KIND, SIMPLE_MEMBER_KIND_BY_KIND, MEMBER_KIND_BY_KIND, TYPE_MEMBER_KIND_BY_KIND, MEMBER_IDENTITY_FIELDS, INHERITED_MEMBER_ORDINAL_FIELDS, NULLABLE_OVERRIDE_MEMBER_FIELDS;
|
|
43363
|
+
var MEMBER_KIND, MEMBER_MODIFIERS, MEMBER_ACCESS, MEMBER_STORAGE, MEMBER_DISTRIBUTION, STRING_FORMAT, MEMBER_SEARCH_BY, MEMBER_SELECTION, FUNCTION_DISPATCH, FUNCTION_BODY, FUNCTION_EFFECT, MEMBER_PAYLOAD, DICTIONARY_KEY, LIST_KIND, LIST_INDEX, COLUMN_VISIBILITY, COLUMN_PIN, COLUMN_OVERFLOW, GENERIC_BINDING, TYPE_KIND_BY_MEMBER_KIND, SIMPLE_MEMBER_KIND_BY_KIND, MEMBER_KIND_BY_KIND, TYPE_MEMBER_KIND_BY_KIND, MEMBER_IDENTITY_FIELDS, INHERITED_MEMBER_ORDINAL_FIELDS, NULLABLE_OVERRIDE_MEMBER_FIELDS;
|
|
43251
43364
|
var init_codecs = __esm({
|
|
43252
43365
|
"src/project-manifest/record-adapters/codecs.ts"() {
|
|
43253
43366
|
"use strict";
|
|
@@ -43298,6 +43411,7 @@ var init_codecs = __esm({
|
|
|
43298
43411
|
MEMBER_SELECTION = ["single", "multi"];
|
|
43299
43412
|
FUNCTION_DISPATCH = ["synchronous", "asynchronous"];
|
|
43300
43413
|
FUNCTION_BODY = ["code", "ui"];
|
|
43414
|
+
FUNCTION_EFFECT = ["none", "auto"];
|
|
43301
43415
|
MEMBER_PAYLOAD = ["full", "partial"];
|
|
43302
43416
|
DICTIONARY_KEY = ["string", "enum"];
|
|
43303
43417
|
LIST_KIND = ["ordered", "unordered"];
|
|
@@ -49165,6 +49279,9 @@ var init_structured_leaf_fields = __esm({
|
|
|
49165
49279
|
});
|
|
49166
49280
|
|
|
49167
49281
|
// ../src/models/members/member-kinds.ts
|
|
49282
|
+
function isFunctionEffectKind(value) {
|
|
49283
|
+
return value === 0 /* None */ || value === 1 /* Auto */;
|
|
49284
|
+
}
|
|
49168
49285
|
function isMemberAccessKind(value) {
|
|
49169
49286
|
return MEMBER_ACCESS_KINDS.includes(value);
|
|
49170
49287
|
}
|
|
@@ -49913,6 +50030,11 @@ function hasValidStorageField(v, allowNull) {
|
|
|
49913
50030
|
if (typeof v.kind !== "number") return false;
|
|
49914
50031
|
return memberKindSupportsStorage(v.kind);
|
|
49915
50032
|
}
|
|
50033
|
+
function hasValidEffectField(v) {
|
|
50034
|
+
if (v.effect === void 0) return true;
|
|
50035
|
+
if (!isFunctionEffectKind(v.effect)) return false;
|
|
50036
|
+
return v.kind === 13 /* Function */ || v.kind === 23 /* NSFunction */;
|
|
50037
|
+
}
|
|
49916
50038
|
function hasValidDistributionField(v) {
|
|
49917
50039
|
if (v.distribution === void 0) return true;
|
|
49918
50040
|
if (!isNeoSubtreeDistributionKind(v.distribution)) return false;
|
|
@@ -49943,6 +50065,7 @@ function isMemberBase(value) {
|
|
|
49943
50065
|
}
|
|
49944
50066
|
if (!hasValidStorageField(v, true)) return false;
|
|
49945
50067
|
if (!hasValidDistributionField(v)) return false;
|
|
50068
|
+
if (!hasValidEffectField(v)) return false;
|
|
49946
50069
|
const storageKey = getField(value, "storageKey");
|
|
49947
50070
|
if (storageKey !== void 0 && storageKey !== null && typeof storageKey !== "string")
|
|
49948
50071
|
return false;
|
|
@@ -50042,6 +50165,7 @@ function isMemberOverrideBase(value) {
|
|
|
50042
50165
|
}
|
|
50043
50166
|
if (!hasValidStorageField(v, false)) return false;
|
|
50044
50167
|
if (!hasValidDistributionField(v)) return false;
|
|
50168
|
+
if (!hasValidEffectField(v)) return false;
|
|
50045
50169
|
if (v.defaultValue !== void 0 && v.defaultValue !== null && !isMemberValueBase(v.defaultValue)) {
|
|
50046
50170
|
return false;
|
|
50047
50171
|
}
|
|
@@ -59701,6 +59825,7 @@ function emitMember(context, member, enclosingClassId) {
|
|
|
59701
59825
|
// P76 §1 is never materialized into source, so a member that omits the
|
|
59702
59826
|
// annotation round-trips as an omission.
|
|
59703
59827
|
...member.distribution ? [`@distribution(kind: .${enumCase(member.distribution)})`] : [],
|
|
59828
|
+
...(member.kind === "function" || member.kind === "scriptFunction") && member.effect !== void 0 ? [member.effect === "auto" ? "@effect" : "@effect(kind: .None)"] : [],
|
|
59704
59829
|
...memberSettings(context, member),
|
|
59705
59830
|
...listAnnotations(member),
|
|
59706
59831
|
...member.system ? [systemAnnotation2(member.system)] : []
|
|
@@ -62573,6 +62698,11 @@ function lowerMemberKind(context, ownerClass, declaration, id2, owner) {
|
|
|
62573
62698
|
};
|
|
62574
62699
|
}
|
|
62575
62700
|
);
|
|
62701
|
+
const effect = functionEffectValue(
|
|
62702
|
+
annotation(declaration.annotations, "effect"),
|
|
62703
|
+
ownerClass,
|
|
62704
|
+
declaration
|
|
62705
|
+
);
|
|
62576
62706
|
const settings = annotation(declaration.annotations, "settings");
|
|
62577
62707
|
const logicMode = contextualEnumArgument(settings, "logic");
|
|
62578
62708
|
if (logicMode !== null && logicMode !== "UI") {
|
|
@@ -62599,6 +62729,7 @@ function lowerMemberKind(context, ownerClass, declaration, id2, owner) {
|
|
|
62599
62729
|
returnType,
|
|
62600
62730
|
arguments: argumentsValue,
|
|
62601
62731
|
deferred: declaration.modifiers.includes("async"),
|
|
62732
|
+
...effect,
|
|
62602
62733
|
...logicMode === "UI" ? { bodyMode: "ui", uiAction } : {},
|
|
62603
62734
|
script: {
|
|
62604
62735
|
kind: "function",
|
|
@@ -62616,6 +62747,7 @@ function lowerMemberKind(context, ownerClass, declaration, id2, owner) {
|
|
|
62616
62747
|
returnType,
|
|
62617
62748
|
arguments: argumentsValue,
|
|
62618
62749
|
deferred: declaration.modifiers.includes("async"),
|
|
62750
|
+
...effect,
|
|
62619
62751
|
bodyMode: "ui",
|
|
62620
62752
|
...uiAction === void 0 ? {} : { uiAction },
|
|
62621
62753
|
script: null
|
|
@@ -62628,6 +62760,7 @@ function lowerMemberKind(context, ownerClass, declaration, id2, owner) {
|
|
|
62628
62760
|
returnType,
|
|
62629
62761
|
arguments: argumentsValue,
|
|
62630
62762
|
deferred: declaration.modifiers.includes("async"),
|
|
62763
|
+
...effect,
|
|
62631
62764
|
script: null
|
|
62632
62765
|
};
|
|
62633
62766
|
}
|
|
@@ -62636,7 +62769,8 @@ function lowerMemberKind(context, ownerClass, declaration, id2, owner) {
|
|
|
62636
62769
|
kind: "function",
|
|
62637
62770
|
returnType,
|
|
62638
62771
|
arguments: argumentsValue,
|
|
62639
|
-
deferred: declaration.modifiers.includes("async")
|
|
62772
|
+
deferred: declaration.modifiers.includes("async"),
|
|
62773
|
+
...effect
|
|
62640
62774
|
};
|
|
62641
62775
|
}
|
|
62642
62776
|
return lowerFieldMember(
|
|
@@ -62766,6 +62900,16 @@ function distributionValue(value, ownerClass, declaration) {
|
|
|
62766
62900
|
`@distribution on ${site} has unknown kind ".${kind}". Valid kinds are .Sparse and .Packed.`
|
|
62767
62901
|
);
|
|
62768
62902
|
}
|
|
62903
|
+
function functionEffectValue(value, ownerClass, declaration) {
|
|
62904
|
+
if (value === void 0) return {};
|
|
62905
|
+
if (value.arguments.length === 0) return { effect: "auto" };
|
|
62906
|
+
const kind = contextualEnumArgument(value, "kind");
|
|
62907
|
+
if (kind === "None") return { effect: "none" };
|
|
62908
|
+
if (kind === "Auto") return { effect: "auto" };
|
|
62909
|
+
throw new Error(
|
|
62910
|
+
`@effect on ${ownerClass.name}.${declaration.name} has unknown kind${kind === null ? "" : ` ".${kind}"`}. Valid kinds are .None and .Auto.`
|
|
62911
|
+
);
|
|
62912
|
+
}
|
|
62769
62913
|
function resolvedMemberStorage(context, memberId, visited = /* @__PURE__ */ new Set()) {
|
|
62770
62914
|
if (visited.has(memberId)) return null;
|
|
62771
62915
|
visited.add(memberId);
|
|
@@ -145290,6 +145434,113 @@ var init_project_integrity = __esm({
|
|
|
145290
145434
|
}
|
|
145291
145435
|
});
|
|
145292
145436
|
|
|
145437
|
+
// src/test-worker-pool.ts
|
|
145438
|
+
import { Worker as Worker5 } from "node:worker_threads";
|
|
145439
|
+
var TestWorkerPool;
|
|
145440
|
+
var init_test_worker_pool = __esm({
|
|
145441
|
+
"src/test-worker-pool.ts"() {
|
|
145442
|
+
"use strict";
|
|
145443
|
+
TestWorkerPool = class {
|
|
145444
|
+
constructor(workerUrl) {
|
|
145445
|
+
this.workerUrl = workerUrl;
|
|
145446
|
+
}
|
|
145447
|
+
workerUrl;
|
|
145448
|
+
interrupted = false;
|
|
145449
|
+
workers = [];
|
|
145450
|
+
failures = /* @__PURE__ */ new Map();
|
|
145451
|
+
pending = /* @__PURE__ */ new Map();
|
|
145452
|
+
async start(document, count) {
|
|
145453
|
+
await Promise.all(
|
|
145454
|
+
Array.from({ length: count }, async () => {
|
|
145455
|
+
const worker = new Worker5(this.workerUrl);
|
|
145456
|
+
this.workers.push(worker);
|
|
145457
|
+
worker.on(
|
|
145458
|
+
"error",
|
|
145459
|
+
(error) => this.fail(
|
|
145460
|
+
worker,
|
|
145461
|
+
error instanceof Error ? error : new Error(String(error))
|
|
145462
|
+
)
|
|
145463
|
+
);
|
|
145464
|
+
worker.on(
|
|
145465
|
+
"exit",
|
|
145466
|
+
(code) => this.fail(
|
|
145467
|
+
worker,
|
|
145468
|
+
new Error(
|
|
145469
|
+
`Test worker exited before completing its file (code ${code}).`
|
|
145470
|
+
)
|
|
145471
|
+
)
|
|
145472
|
+
);
|
|
145473
|
+
const response = await this.request(worker, { kind: "init", document });
|
|
145474
|
+
if (response.kind !== "ready")
|
|
145475
|
+
throw new Error("Test worker did not initialize its project.");
|
|
145476
|
+
})
|
|
145477
|
+
);
|
|
145478
|
+
}
|
|
145479
|
+
fail(worker, error) {
|
|
145480
|
+
this.failures.set(worker, error);
|
|
145481
|
+
this.pending.get(worker)?.(error);
|
|
145482
|
+
}
|
|
145483
|
+
request(worker, request) {
|
|
145484
|
+
const failure = this.failures.get(worker);
|
|
145485
|
+
if (failure !== void 0) return Promise.reject(failure);
|
|
145486
|
+
return new Promise((resolve5, reject) => {
|
|
145487
|
+
const cleanup = () => {
|
|
145488
|
+
worker.off("message", onMessage);
|
|
145489
|
+
this.pending.delete(worker);
|
|
145490
|
+
};
|
|
145491
|
+
const onMessage = (response) => {
|
|
145492
|
+
cleanup();
|
|
145493
|
+
if (response.kind === "error") reject(new Error(response.message));
|
|
145494
|
+
else resolve5(response);
|
|
145495
|
+
};
|
|
145496
|
+
const onError = (error) => {
|
|
145497
|
+
cleanup();
|
|
145498
|
+
reject(error);
|
|
145499
|
+
};
|
|
145500
|
+
this.pending.set(worker, onError);
|
|
145501
|
+
worker.once("message", onMessage);
|
|
145502
|
+
try {
|
|
145503
|
+
worker.postMessage(request);
|
|
145504
|
+
} catch (error) {
|
|
145505
|
+
onError(error instanceof Error ? error : new Error(String(error)));
|
|
145506
|
+
}
|
|
145507
|
+
});
|
|
145508
|
+
}
|
|
145509
|
+
async run(jobs, timeoutMs, onResult) {
|
|
145510
|
+
let next = 0;
|
|
145511
|
+
await Promise.all(
|
|
145512
|
+
this.workers.map(async (worker) => {
|
|
145513
|
+
while (!this.interrupted && next < jobs.length) {
|
|
145514
|
+
const job = jobs[next++];
|
|
145515
|
+
const response = await this.request(worker, {
|
|
145516
|
+
kind: "run",
|
|
145517
|
+
...job,
|
|
145518
|
+
timeoutMs
|
|
145519
|
+
});
|
|
145520
|
+
if (response.kind !== "result")
|
|
145521
|
+
throw new Error("Test worker returned no file result.");
|
|
145522
|
+
onResult(job.spec, response.result);
|
|
145523
|
+
}
|
|
145524
|
+
})
|
|
145525
|
+
);
|
|
145526
|
+
}
|
|
145527
|
+
interrupt() {
|
|
145528
|
+
this.interrupted = true;
|
|
145529
|
+
for (const worker of this.workers) {
|
|
145530
|
+
worker.postMessage({ kind: "interrupt" });
|
|
145531
|
+
}
|
|
145532
|
+
}
|
|
145533
|
+
async stop() {
|
|
145534
|
+
for (const reject of this.pending.values())
|
|
145535
|
+
reject(new Error("Test worker stopped."));
|
|
145536
|
+
await Promise.all(this.workers.map((worker) => worker.terminate()));
|
|
145537
|
+
this.workers.length = 0;
|
|
145538
|
+
this.failures.clear();
|
|
145539
|
+
}
|
|
145540
|
+
};
|
|
145541
|
+
}
|
|
145542
|
+
});
|
|
145543
|
+
|
|
145293
145544
|
// src/neoscript-language-adapter.ts
|
|
145294
145545
|
function createCliNeoScriptContext(options) {
|
|
145295
145546
|
const members = [...options.documents.members];
|
|
@@ -145299,12 +145550,7 @@ function createCliNeoScriptContext(options) {
|
|
|
145299
145550
|
members,
|
|
145300
145551
|
classes: [...options.documents.classes],
|
|
145301
145552
|
enums: [...options.documents.enums],
|
|
145302
|
-
interfaces: [...options.documents.interfaces]
|
|
145303
|
-
databaseVM: {
|
|
145304
|
-
memberById: (id2) => members.find(
|
|
145305
|
-
(member) => member.id === id2
|
|
145306
|
-
) ?? null
|
|
145307
|
-
}
|
|
145553
|
+
interfaces: [...options.documents.interfaces]
|
|
145308
145554
|
};
|
|
145309
145555
|
const compilerContext = createNeoScriptDocumentContext({
|
|
145310
145556
|
vm,
|
|
@@ -145346,7 +145592,7 @@ async function validateCliNeoScript(uri, source, context) {
|
|
|
145346
145592
|
service.closeDocument(uri);
|
|
145347
145593
|
}
|
|
145348
145594
|
}
|
|
145349
|
-
function compileCliNeoScript(uri, source, context) {
|
|
145595
|
+
function compileCliNeoScript(uri, source, context, projectIndex) {
|
|
145350
145596
|
const result = compileNeoScriptStrict(
|
|
145351
145597
|
{
|
|
145352
145598
|
uri,
|
|
@@ -145354,7 +145600,8 @@ function compileCliNeoScript(uri, source, context) {
|
|
|
145354
145600
|
version: 1,
|
|
145355
145601
|
text: source
|
|
145356
145602
|
},
|
|
145357
|
-
context
|
|
145603
|
+
context,
|
|
145604
|
+
{ projectIndex }
|
|
145358
145605
|
);
|
|
145359
145606
|
const error = result.diagnostics.find(
|
|
145360
145607
|
(diagnostic) => diagnostic.severity === "error"
|
|
@@ -147354,7 +147601,7 @@ var init_registry2 = __esm({
|
|
|
147354
147601
|
"../packages/manifest/schema-contract/registry.mjs"() {
|
|
147355
147602
|
"use strict";
|
|
147356
147603
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
147357
|
-
cliVersion: "0.
|
|
147604
|
+
cliVersion: "0.63.0",
|
|
147358
147605
|
projectFileUploadBatchSize: 32,
|
|
147359
147606
|
documentRecords: {
|
|
147360
147607
|
member: {
|
|
@@ -147406,6 +147653,10 @@ var init_registry2 = __esm({
|
|
|
147406
147653
|
"argumentTypes",
|
|
147407
147654
|
"dispatch",
|
|
147408
147655
|
"bodyMode",
|
|
147656
|
+
// P97 §1.1. No normalization rule, like `distribution`: absence means
|
|
147657
|
+
// unset (a declaration resolves to `.None`, an override inherits) and
|
|
147658
|
+
// explicit ordinal 0 is an authored `.None` that stops inheritance.
|
|
147659
|
+
"effect",
|
|
147409
147660
|
"uiAction",
|
|
147410
147661
|
"templateId",
|
|
147411
147662
|
"genericParamId"
|
|
@@ -147708,7 +147959,8 @@ var init_registry2 = __esm({
|
|
|
147708
147959
|
NeoColumnVisibility: ["Visible", "Hidden"],
|
|
147709
147960
|
NeoColumnPin: ["None", "Leading"],
|
|
147710
147961
|
NeoColumnOverflow: ["Clip", "Wrap"],
|
|
147711
|
-
NeoFileKind: ["Sprite", "Audio"]
|
|
147962
|
+
NeoFileKind: ["Sprite", "Audio"],
|
|
147963
|
+
NeoEffectKind: ["None", "Auto"]
|
|
147712
147964
|
},
|
|
147713
147965
|
markers: {
|
|
147714
147966
|
NeoSchemaClassAttribute: {
|
|
@@ -148773,8 +149025,10 @@ var init_registry2 = __esm({
|
|
|
148773
149025
|
// src/commands/test.ts
|
|
148774
149026
|
var test_exports = {};
|
|
148775
149027
|
__export(test_exports, {
|
|
149028
|
+
executeTestFile: () => executeTestFile,
|
|
148776
149029
|
inspectNeoTestCompilation: () => inspectNeoTestCompilation,
|
|
148777
149030
|
maintainNeoTestBuildCache: () => maintainNeoTestBuildCache,
|
|
149031
|
+
prepareTestEvaluator: () => prepareTestEvaluator,
|
|
148778
149032
|
runTest: () => runTest
|
|
148779
149033
|
});
|
|
148780
149034
|
import { createHash as createHash10, randomUUID as randomUUID6 } from "node:crypto";
|
|
@@ -148798,6 +149052,7 @@ import {
|
|
|
148798
149052
|
resolve as resolve4,
|
|
148799
149053
|
sep as sep8
|
|
148800
149054
|
} from "node:path";
|
|
149055
|
+
import { availableParallelism } from "node:os";
|
|
148801
149056
|
import { isDeepStrictEqual } from "node:util";
|
|
148802
149057
|
function isRecord11(value) {
|
|
148803
149058
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -149119,8 +149374,28 @@ function cacheTestCandidate(workspace, inputFingerprint, candidate) {
|
|
|
149119
149374
|
);
|
|
149120
149375
|
return { ...candidate, documentSha256 };
|
|
149121
149376
|
}
|
|
149122
|
-
function
|
|
149123
|
-
const
|
|
149377
|
+
function createSpecCompiler(document) {
|
|
149378
|
+
const context = withNeoTestPrelude({
|
|
149379
|
+
...createCliNeoScriptContext({
|
|
149380
|
+
documents: readDocumentArrays(document),
|
|
149381
|
+
kind: "function",
|
|
149382
|
+
thisClass: null
|
|
149383
|
+
}),
|
|
149384
|
+
kind: "function",
|
|
149385
|
+
projectSourceKind: "spec",
|
|
149386
|
+
returnType: { kind: "primitive", name: "void" }
|
|
149387
|
+
});
|
|
149388
|
+
const projectIndex = createProjectIndex(context.project);
|
|
149389
|
+
return (uri, source) => compileCliNeoScript(uri, source, context, projectIndex);
|
|
149390
|
+
}
|
|
149391
|
+
function lazySpecCompiler(document) {
|
|
149392
|
+
let compiler;
|
|
149393
|
+
return (uri, source) => {
|
|
149394
|
+
compiler ??= createSpecCompiler(document);
|
|
149395
|
+
return compiler(uri, source);
|
|
149396
|
+
};
|
|
149397
|
+
}
|
|
149398
|
+
function compileSpec(workspace, compile, absolutePath, projectCompilationHash2) {
|
|
149124
149399
|
const path = relative8(workspace.root, absolutePath).split(sep8).join("/");
|
|
149125
149400
|
const source = readFileSync19(absolutePath, "utf8");
|
|
149126
149401
|
const sourceHash = createHash10("sha256").update(source).digest("hex");
|
|
@@ -149143,21 +149418,10 @@ function compileSpec(workspace, document, absolutePath, projectCompilationHash2)
|
|
|
149143
149418
|
}
|
|
149144
149419
|
} catch {
|
|
149145
149420
|
}
|
|
149146
|
-
const baseContext2 = createCliNeoScriptContext({
|
|
149147
|
-
documents: scriptDocument,
|
|
149148
|
-
kind: "function",
|
|
149149
|
-
thisClass: null
|
|
149150
|
-
});
|
|
149151
|
-
const context = withNeoTestPrelude({
|
|
149152
|
-
...baseContext2,
|
|
149153
|
-
kind: "function",
|
|
149154
|
-
projectSourceKind: "spec",
|
|
149155
|
-
returnType: { kind: "primitive", name: "void" }
|
|
149156
|
-
});
|
|
149157
149421
|
const compiled = {
|
|
149158
149422
|
path,
|
|
149159
149423
|
source,
|
|
149160
|
-
action:
|
|
149424
|
+
action: compile(`file://${absolutePath}`, source)
|
|
149161
149425
|
};
|
|
149162
149426
|
atomicWrite(
|
|
149163
149427
|
artifactPath,
|
|
@@ -149837,6 +150101,18 @@ function failureFor(error, file, position, member = null) {
|
|
|
149837
150101
|
function suiteHasSelectedTests(suite, selected) {
|
|
149838
150102
|
return suite.tests.some((test) => selected.has(test.id)) || suite.suites.some((child) => suiteHasSelectedTests(child, selected));
|
|
149839
150103
|
}
|
|
150104
|
+
function prepareTestEvaluator(document) {
|
|
150105
|
+
sharedEvaluatorBase(document);
|
|
150106
|
+
}
|
|
150107
|
+
async function executeTestFile(spec, document, selected, timeoutMs, interrupted = () => false) {
|
|
150108
|
+
return executeRegisteredSpec(
|
|
150109
|
+
registerSpec(spec, document),
|
|
150110
|
+
document,
|
|
150111
|
+
selected,
|
|
150112
|
+
timeoutMs,
|
|
150113
|
+
interrupted
|
|
150114
|
+
);
|
|
150115
|
+
}
|
|
149840
150116
|
async function executeRegisteredSpec(registered, document, selected, timeoutMs, interrupted) {
|
|
149841
150117
|
const results = [];
|
|
149842
150118
|
const fileFailures = [];
|
|
@@ -150035,8 +150311,11 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
150035
150311
|
let testDurationMs = 0;
|
|
150036
150312
|
let exitCode = 0;
|
|
150037
150313
|
let interrupted = false;
|
|
150314
|
+
let workerPool;
|
|
150315
|
+
let parallelExecution = false;
|
|
150038
150316
|
const handleSigint = () => {
|
|
150039
150317
|
interrupted = true;
|
|
150318
|
+
workerPool?.interrupt();
|
|
150040
150319
|
};
|
|
150041
150320
|
const assertNotInterrupted = () => {
|
|
150042
150321
|
if (interrupted) {
|
|
@@ -150051,6 +150330,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
150051
150330
|
select: 0,
|
|
150052
150331
|
compile: 0,
|
|
150053
150332
|
register: 0,
|
|
150333
|
+
workers: 0,
|
|
150054
150334
|
execute: 0,
|
|
150055
150335
|
finalize: 0
|
|
150056
150336
|
};
|
|
@@ -150081,6 +150361,9 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
150081
150361
|
}
|
|
150082
150362
|
if (candidate === null) {
|
|
150083
150363
|
const prepared = dependencies.prepareLocalCandidate === void 0 ? await prepareLocalCandidateV4(workspace, {
|
|
150364
|
+
// Tests need the compiled, validated candidate. Serializing it
|
|
150365
|
+
// back to source and re-lowering is a push dry-run check.
|
|
150366
|
+
fullValidation: false,
|
|
150084
150367
|
onPhase: (label) => {
|
|
150085
150368
|
dependencies.progress?.update(label);
|
|
150086
150369
|
}
|
|
@@ -150132,8 +150415,9 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
150132
150415
|
);
|
|
150133
150416
|
}
|
|
150134
150417
|
enterPhase("compile", "Compiling test files\u2026");
|
|
150418
|
+
const compile = lazySpecCompiler(rawDocument);
|
|
150135
150419
|
specs = selectedPaths.map(
|
|
150136
|
-
(path) => compileSpec(workspace,
|
|
150420
|
+
(path) => compileSpec(workspace, compile, path, compilationHash)
|
|
150137
150421
|
);
|
|
150138
150422
|
let pattern = null;
|
|
150139
150423
|
if (options.testNamePattern !== null) {
|
|
@@ -150162,21 +150446,54 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
150162
150446
|
);
|
|
150163
150447
|
}
|
|
150164
150448
|
const selectedIds = new Set(selectedTests.map((test) => test.id));
|
|
150165
|
-
enterPhase("execute", "Running tests\u2026");
|
|
150166
150449
|
const timeoutMs = options.timeoutMs ?? workspace.config.test?.timeoutMs ?? 5e3;
|
|
150167
|
-
|
|
150168
|
-
|
|
150169
|
-
|
|
150170
|
-
|
|
150171
|
-
|
|
150172
|
-
|
|
150173
|
-
|
|
150174
|
-
|
|
150450
|
+
const maxWorkers = options.maxWorkers ?? workspace.config.test?.maxWorkers ?? Math.min(4, availableParallelism());
|
|
150451
|
+
if (!Number.isSafeInteger(maxWorkers) || maxWorkers <= 0) {
|
|
150452
|
+
throw new NeoTestUsageError("--maxWorkers must be a positive integer.");
|
|
150453
|
+
}
|
|
150454
|
+
const jobs = registered.filter(
|
|
150455
|
+
(entry) => (selectedTestCountByFile.get(entry.spec.path) ?? 0) > 0
|
|
150456
|
+
);
|
|
150457
|
+
const workerCount = options.runInBand === true ? 1 : Math.min(maxWorkers, jobs.length);
|
|
150458
|
+
const recordResult = (spec, executed) => {
|
|
150175
150459
|
results.push(...executed.tests);
|
|
150176
150460
|
testDurationMs += executed.testDurationMs;
|
|
150177
|
-
fileFailuresByPath.set(
|
|
150461
|
+
fileFailuresByPath.set(spec.path, executed.failures);
|
|
150462
|
+
};
|
|
150463
|
+
if (workerCount > 1) {
|
|
150464
|
+
enterPhase("workers", "Starting test workers\u2026");
|
|
150465
|
+
workerPool = new TestWorkerPool(
|
|
150466
|
+
new URL("./test-worker.mjs", import.meta.url)
|
|
150467
|
+
);
|
|
150468
|
+
await workerPool.start(rawDocument, workerCount);
|
|
150178
150469
|
assertNotInterrupted();
|
|
150470
|
+
parallelExecution = true;
|
|
150471
|
+
enterPhase("execute", "Running tests\u2026");
|
|
150472
|
+
await workerPool.run(
|
|
150473
|
+
jobs.map((entry) => ({
|
|
150474
|
+
spec: entry.spec,
|
|
150475
|
+
selectedIds: entry.tests.filter((test) => selectedIds.has(test.id)).map((test) => test.id)
|
|
150476
|
+
})),
|
|
150477
|
+
timeoutMs,
|
|
150478
|
+
recordResult
|
|
150479
|
+
);
|
|
150480
|
+
} else {
|
|
150481
|
+
enterPhase("execute", "Running tests\u2026");
|
|
150482
|
+
for (const entry of jobs) {
|
|
150483
|
+
recordResult(
|
|
150484
|
+
entry.spec,
|
|
150485
|
+
await executeRegisteredSpec(
|
|
150486
|
+
entry,
|
|
150487
|
+
rawDocument,
|
|
150488
|
+
selectedIds,
|
|
150489
|
+
timeoutMs,
|
|
150490
|
+
() => interrupted
|
|
150491
|
+
)
|
|
150492
|
+
);
|
|
150493
|
+
assertNotInterrupted();
|
|
150494
|
+
}
|
|
150179
150495
|
}
|
|
150496
|
+
assertNotInterrupted();
|
|
150180
150497
|
if (results.some((result) => result.status === "failed") || [...fileFailuresByPath.values()].some((failures) => failures.length > 0)) {
|
|
150181
150498
|
exitCode = 1;
|
|
150182
150499
|
}
|
|
@@ -150184,7 +150501,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
150184
150501
|
const buildManifest = {
|
|
150185
150502
|
version: 1,
|
|
150186
150503
|
cliVersion: PROJECT_SCHEMA_CONTRACT.cliVersion,
|
|
150187
|
-
runnerRevision:
|
|
150504
|
+
runnerRevision: 4,
|
|
150188
150505
|
compilerRevision: NEOSCRIPT_COMPILER_REVISION,
|
|
150189
150506
|
evaluatorRevision: 4,
|
|
150190
150507
|
projectFingerprint,
|
|
@@ -150204,12 +150521,12 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
150204
150521
|
`
|
|
150205
150522
|
);
|
|
150206
150523
|
} catch (error) {
|
|
150207
|
-
const diagnosticCode = error instanceof NeoTestInterruptedError ? "NEO_TEST_INTERRUPTED" : error instanceof NeoTestPreparedCandidateError ? "NEO_TEST_PREPARED_CANDIDATE" : error instanceof NeoTestUsageError ? "NEO_TEST_USAGE" : error instanceof NeoTestNoTestsError ? "NEO_TEST_NO_TESTS" : error instanceof NeoTestRegistrationError ? "NEO_TEST_REGISTRATION" : phase === "prepare" ? "NEO_TEST_PREPARATION" : phase === "compile" ? "NEO_TEST_COMPILE" : "NEO_TEST_RUNNER";
|
|
150208
|
-
exitCode = error instanceof NeoTestInterruptedError ? 130 : error instanceof NeoTestUsageError || error instanceof NeoTestReportWriteError || error instanceof NeoTestPreparedCandidateError || diagnosticCode === "NEO_TEST_RUNNER" ? 2 : 1;
|
|
150524
|
+
const diagnosticCode = interrupted || error instanceof NeoTestInterruptedError ? "NEO_TEST_INTERRUPTED" : error instanceof NeoTestPreparedCandidateError ? "NEO_TEST_PREPARED_CANDIDATE" : error instanceof NeoTestUsageError ? "NEO_TEST_USAGE" : error instanceof NeoTestNoTestsError ? "NEO_TEST_NO_TESTS" : error instanceof NeoTestRegistrationError ? "NEO_TEST_REGISTRATION" : phase === "prepare" ? "NEO_TEST_PREPARATION" : phase === "compile" ? "NEO_TEST_COMPILE" : "NEO_TEST_RUNNER";
|
|
150525
|
+
exitCode = interrupted || error instanceof NeoTestInterruptedError ? 130 : error instanceof NeoTestUsageError || error instanceof NeoTestReportWriteError || error instanceof NeoTestPreparedCandidateError || diagnosticCode === "NEO_TEST_RUNNER" ? 2 : 1;
|
|
150209
150526
|
diagnostics.push({
|
|
150210
150527
|
severity: "error",
|
|
150211
150528
|
code: diagnosticCode,
|
|
150212
|
-
message: errorMessage2(error),
|
|
150529
|
+
message: interrupted ? "Neo test was interrupted by SIGINT; partial results were written." : errorMessage2(error),
|
|
150213
150530
|
file: null,
|
|
150214
150531
|
line: null,
|
|
150215
150532
|
column: null,
|
|
@@ -150217,6 +150534,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
150217
150534
|
});
|
|
150218
150535
|
}
|
|
150219
150536
|
finishPhase();
|
|
150537
|
+
await workerPool?.stop();
|
|
150220
150538
|
dependencies.progress?.stop();
|
|
150221
150539
|
process.off("SIGINT", handleSigint);
|
|
150222
150540
|
const failed = results.filter((result) => result.status === "failed").length;
|
|
@@ -150226,21 +150544,33 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
150226
150544
|
);
|
|
150227
150545
|
const skipped = Math.max(0, selectedTestTotal - results.length);
|
|
150228
150546
|
const durationMs = performance.now() - performanceStarted;
|
|
150229
|
-
const startupDurationMs = Math.max(0, durationMs - testDurationMs);
|
|
150547
|
+
const startupDurationMs = parallelExecution ? Math.max(0, durationMs - phaseDurations.execute) : Math.max(0, durationMs - testDurationMs);
|
|
150230
150548
|
const perTestStartupDurationMs = results.reduce(
|
|
150231
150549
|
(sum, result) => sum + result.startupDurationMs,
|
|
150232
150550
|
0
|
|
150233
150551
|
);
|
|
150234
150552
|
const sharedStartupDurationMs = Math.max(
|
|
150235
150553
|
0,
|
|
150236
|
-
startupDurationMs - perTestStartupDurationMs
|
|
150554
|
+
startupDurationMs - (parallelExecution ? 0 : perTestStartupDurationMs)
|
|
150237
150555
|
);
|
|
150556
|
+
const testsByFile = /* @__PURE__ */ new Map();
|
|
150557
|
+
for (const result of results) {
|
|
150558
|
+
const tests = testsByFile.get(result.file) ?? [];
|
|
150559
|
+
tests.push(result);
|
|
150560
|
+
testsByFile.set(result.file, tests);
|
|
150561
|
+
}
|
|
150238
150562
|
const testFiles = specs.map((spec) => {
|
|
150239
|
-
const tests =
|
|
150563
|
+
const tests = testsByFile.get(spec.path) ?? [];
|
|
150240
150564
|
const failures = fileFailuresByPath.get(spec.path) ?? [];
|
|
150565
|
+
let status = "passed";
|
|
150566
|
+
if (tests.some((test) => test.status === "failed") || failures.length > 0) {
|
|
150567
|
+
status = "failed";
|
|
150568
|
+
} else if (tests.length < (selectedTestCountByFile.get(spec.path) ?? 0) && exitCode !== 0) {
|
|
150569
|
+
status = interrupted ? "interrupted" : "failed";
|
|
150570
|
+
}
|
|
150241
150571
|
return {
|
|
150242
150572
|
path: spec.path,
|
|
150243
|
-
status
|
|
150573
|
+
status,
|
|
150244
150574
|
tests,
|
|
150245
150575
|
failures
|
|
150246
150576
|
};
|
|
@@ -150276,6 +150606,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
150276
150606
|
selectMs: phaseDurations.select,
|
|
150277
150607
|
compileMs: phaseDurations.compile,
|
|
150278
150608
|
registerMs: phaseDurations.register,
|
|
150609
|
+
workerStartupMs: phaseDurations.workers,
|
|
150279
150610
|
executeMs: phaseDurations.execute,
|
|
150280
150611
|
finalizeMs: phaseDurations.finalize
|
|
150281
150612
|
},
|
|
@@ -150357,8 +150688,9 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
150357
150688
|
console.log(
|
|
150358
150689
|
` ${color.bold(pad("Tests", 11))} ${formatStatusCounts(report.summary.passed, report.summary.failed, report.summary.tests, report.summary.skipped)}`
|
|
150359
150690
|
);
|
|
150691
|
+
const timingDetail = parallelExecution ? `test work ${formatTestDuration(report.summary.testDurationMs)}, execution ${formatTestDuration(report.timings.executeMs)}, startup ${formatTestDuration(report.summary.startupDurationMs)}` : `test ${formatTestDuration(report.summary.testDurationMs)}, startup ${formatTestDuration(report.summary.startupDurationMs)}`;
|
|
150360
150692
|
console.log(
|
|
150361
|
-
` ${color.bold(pad("Duration", 11))} ${color.bold(`total ${formatTestDuration(report.summary.durationMs)}`)} ${color.dim(`(
|
|
150693
|
+
` ${color.bold(pad("Duration", 11))} ${color.bold(`total ${formatTestDuration(report.summary.durationMs)}`)} ${color.dim(`(${timingDetail})`)}`
|
|
150362
150694
|
);
|
|
150363
150695
|
}
|
|
150364
150696
|
if (!report.success) process.exitCode = exitCode;
|
|
@@ -150388,9 +150720,10 @@ async function inspectNeoTestCompilation(workspace, dependencies = {}) {
|
|
|
150388
150720
|
document
|
|
150389
150721
|
);
|
|
150390
150722
|
const errors = [];
|
|
150723
|
+
const compile = lazySpecCompiler(document);
|
|
150391
150724
|
for (const path of selectedPaths) {
|
|
150392
150725
|
try {
|
|
150393
|
-
compileSpec(workspace,
|
|
150726
|
+
compileSpec(workspace, compile, path, compilationHash);
|
|
150394
150727
|
} catch (error) {
|
|
150395
150728
|
errors.push({
|
|
150396
150729
|
file: relative8(workspace.root, path).split(sep8).join("/"),
|
|
@@ -150409,6 +150742,7 @@ var TEST_BUILD_CACHE_LIMIT_BYTES, ABANDONED_TEMP_MAX_AGE_MS, TEST_CANDIDATE_CACH
|
|
|
150409
150742
|
var init_test = __esm({
|
|
150410
150743
|
"src/commands/test.ts"() {
|
|
150411
150744
|
"use strict";
|
|
150745
|
+
init_test_worker_pool();
|
|
150412
150746
|
init_src();
|
|
150413
150747
|
init_members();
|
|
150414
150748
|
init_neoscript2();
|
|
@@ -155345,7 +155679,7 @@ function readManifest(path) {
|
|
|
155345
155679
|
});
|
|
155346
155680
|
return { projectId: data.projectId, files };
|
|
155347
155681
|
}
|
|
155348
|
-
function writeUnityGeneratedFiles(directory, projectId, files) {
|
|
155682
|
+
function writeUnityGeneratedFiles(directory, projectId, files, codegenRevision) {
|
|
155349
155683
|
if (!Array.isArray(files) || files.length === 0)
|
|
155350
155684
|
throw new Error(
|
|
155351
155685
|
"The export returned no generated files. Update the server before exporting Unity code."
|
|
@@ -155409,6 +155743,7 @@ function writeUnityGeneratedFiles(directory, projectId, files) {
|
|
|
155409
155743
|
{
|
|
155410
155744
|
schemaVersion: 1,
|
|
155411
155745
|
projectId,
|
|
155746
|
+
codegenRevision,
|
|
155412
155747
|
files: [...files].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0).map((file) => ({
|
|
155413
155748
|
id: file.id,
|
|
155414
155749
|
path: file.path,
|
|
@@ -155490,7 +155825,8 @@ async function runExportUnity(workspace, outDir) {
|
|
|
155490
155825
|
writeUnityGeneratedFiles(
|
|
155491
155826
|
scriptsDir,
|
|
155492
155827
|
response.projectId,
|
|
155493
|
-
response.generatedFiles
|
|
155828
|
+
response.generatedFiles,
|
|
155829
|
+
response.codegenRevision
|
|
155494
155830
|
);
|
|
155495
155831
|
writeFileSync16(join19(resourcesDir, "project.json"), response.projectJson);
|
|
155496
155832
|
for (const file of response.localizationFiles ?? []) {
|
|
@@ -155947,6 +156283,11 @@ ${h("Usage")}
|
|
|
155947
156283
|
neo test ${d("[file-or-directory ...]")}
|
|
155948
156284
|
neo test -t ${d('"name pattern"')}
|
|
155949
156285
|
neo test ${d("--reporter=json --outputFile=output.json")}
|
|
156286
|
+
neo test ${d("--maxWorkers=4")}
|
|
156287
|
+
neo test ${d("--runInBand")}
|
|
156288
|
+
|
|
156289
|
+
Files run in parallel, using up to four available CPU workers by default.
|
|
156290
|
+
--maxWorkers overrides neo.json test.maxWorkers; --runInBand runs serially.
|
|
155950
156291
|
|
|
155951
156292
|
Tests execute against the locally compiled candidate graph, including changes
|
|
155952
156293
|
that have not been pushed. Test files are never included in a push.
|
|
@@ -156034,7 +156375,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
156034
156375
|
async function main() {
|
|
156035
156376
|
const args = parseArgs(process.argv.slice(2));
|
|
156036
156377
|
if (args.command === "--version") {
|
|
156037
|
-
console.log("0.
|
|
156378
|
+
console.log("0.63.0");
|
|
156038
156379
|
return;
|
|
156039
156380
|
}
|
|
156040
156381
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
|
@@ -156360,6 +156701,11 @@ async function main() {
|
|
|
156360
156701
|
"--testTimeout must be a positive number of milliseconds."
|
|
156361
156702
|
);
|
|
156362
156703
|
}
|
|
156704
|
+
const maxWorkersValue = stringFlag(args, "maxWorkers");
|
|
156705
|
+
const maxWorkers = maxWorkersValue === null ? void 0 : Number(maxWorkersValue);
|
|
156706
|
+
if (maxWorkers !== void 0 && (!Number.isSafeInteger(maxWorkers) || maxWorkers <= 0)) {
|
|
156707
|
+
throw new NeoCliUsageError("--maxWorkers must be a positive integer.");
|
|
156708
|
+
}
|
|
156363
156709
|
const progress = reporterValue === "default" && process.stdout.isTTY === true ? spinner("Reading local workspace\u2026") : null;
|
|
156364
156710
|
try {
|
|
156365
156711
|
const workspace = loadWorkspaceForCommand(args);
|
|
@@ -156372,6 +156718,8 @@ async function main() {
|
|
|
156372
156718
|
reporter: reporterValue,
|
|
156373
156719
|
outputFile: stringFlag(args, "outputFile") ?? stringFlag(args, "output-file"),
|
|
156374
156720
|
passWithNoTests: boolFlag(args, "passWithNoTests"),
|
|
156721
|
+
runInBand: boolFlag(args, "runInBand"),
|
|
156722
|
+
...maxWorkers === void 0 ? {} : { maxWorkers },
|
|
156375
156723
|
...timeoutMs === void 0 ? {} : { timeoutMs }
|
|
156376
156724
|
},
|
|
156377
156725
|
progress === null ? {} : { progress }
|