@neocompose/cli 0.26.2 → 0.26.4
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,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.26.4] - 2026-08-10
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Read an omitted nullable member on a newly constructed class as `null`
|
|
8
|
+
instead of throwing a missing-object-key error. `neo test` can now assert
|
|
9
|
+
explicit nullable defaults without requiring an otherwise-empty value row.
|
|
10
|
+
- Let local candidate validation resolve an image or audio file created in the
|
|
11
|
+
same source change. `neo doctor`, `neo test`, and push dry runs now preserve
|
|
12
|
+
the pending file identity while rehearsing the uploaded project-file row.
|
|
13
|
+
|
|
14
|
+
## [0.26.3] - 2026-08-10
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Show a phase-aware loading spinner during interactive `neo test` runs, then
|
|
19
|
+
render files, tests, failures, counts, and durations with Vitest-style
|
|
20
|
+
grouping, alignment, color, and emphasis. JSON reports now expose prepare,
|
|
21
|
+
selection, compilation, registration, execution, and finalization timings.
|
|
22
|
+
- Reuse matcher dispatch metadata, build assertion diagnostics only on failure,
|
|
23
|
+
and compare structured values directly instead of serializing them to JSON.
|
|
24
|
+
This keeps successful `expect`, `toBe`, `toEqual`, `toHaveLength`,
|
|
25
|
+
`toContain`, `toMatchObject`, and mock assertions on a smaller hot path.
|
|
26
|
+
|
|
3
27
|
## [0.26.2] - 2026-08-10
|
|
4
28
|
|
|
5
29
|
### Changed
|
package/dist/neo.mjs
CHANGED
|
@@ -169,6 +169,9 @@ function warn(text) {
|
|
|
169
169
|
function note(text) {
|
|
170
170
|
console.log(color.dim(text));
|
|
171
171
|
}
|
|
172
|
+
function pad(text, width) {
|
|
173
|
+
return text.length >= width ? text : text + " ".repeat(width - text.length);
|
|
174
|
+
}
|
|
172
175
|
function paintChangeKind(kind) {
|
|
173
176
|
const painter = CHANGE_KIND_COLOR[kind];
|
|
174
177
|
return painter === void 0 ? kind : painter(kind);
|
|
@@ -46689,9 +46692,9 @@ ${namedArguments(
|
|
|
46689
46692
|
`;
|
|
46690
46693
|
}
|
|
46691
46694
|
function namedArguments(entries, spaces, raw = /* @__PURE__ */ new Set()) {
|
|
46692
|
-
const
|
|
46695
|
+
const pad2 = " ".repeat(spaces);
|
|
46693
46696
|
return entries.map(
|
|
46694
|
-
([name, value]) => `${
|
|
46697
|
+
([name, value]) => `${pad2}${name}: ${raw.has(name) ? rawValue(value) : jsonValue2(value)},`
|
|
46695
46698
|
).join("\n");
|
|
46696
46699
|
}
|
|
46697
46700
|
function rawValue(value) {
|
|
@@ -57376,6 +57379,13 @@ var init_NeoScriptScope = __esm({
|
|
|
57376
57379
|
setLocal(bindingId, value) {
|
|
57377
57380
|
this.#bindings.set(bindingId, value);
|
|
57378
57381
|
}
|
|
57382
|
+
bindInvocationEntry(bindingId, value) {
|
|
57383
|
+
this.#bindings.set(bindingId, value);
|
|
57384
|
+
}
|
|
57385
|
+
bindInvocationKeyAndEntry(keyBindingId, key, entryBindingId, entry) {
|
|
57386
|
+
this.#bindings.set(keyBindingId, key);
|
|
57387
|
+
this.#bindings.set(entryBindingId, entry);
|
|
57388
|
+
}
|
|
57379
57389
|
resetInvocationLocals(parameterCount) {
|
|
57380
57390
|
if (this.#bindings.size > parameterCount) this.#bindings.clear();
|
|
57381
57391
|
if (this.#readonlyBindingErrors.size > 0) {
|
|
@@ -61898,6 +61908,7 @@ function dispatchSchemaMember(receiver, schemaKey, ctx) {
|
|
|
61898
61908
|
};
|
|
61899
61909
|
}
|
|
61900
61910
|
if (!Object.prototype.hasOwnProperty.call(receiver, schemaKey)) {
|
|
61911
|
+
if (!member.required) return { kind: "ok", value: null };
|
|
61901
61912
|
return { kind: "no-info", matchedMember: true };
|
|
61902
61913
|
}
|
|
61903
61914
|
const at = receiver[schemaKey];
|
|
@@ -62423,6 +62434,211 @@ function evalDeclaredListIndex(info, scope, ctx) {
|
|
|
62423
62434
|
}
|
|
62424
62435
|
return Array.isArray(hit) ? [...hit] : [];
|
|
62425
62436
|
}
|
|
62437
|
+
function prepareCollectionCallback(callback, parentScope, ctx, isList, returnContract, onPredicateMatch) {
|
|
62438
|
+
const metrics = ctx.__collectionCallbackPreparationMetrics;
|
|
62439
|
+
if (metrics !== void 0) metrics.bodyValidations += 1;
|
|
62440
|
+
const compilerRevision = callback.compilerRevision ?? 1;
|
|
62441
|
+
if (!Number.isSafeInteger(compilerRevision)) {
|
|
62442
|
+
throw new NSGetterRuntimeError(
|
|
62443
|
+
"Collection callback compiler revision must be a safe integer."
|
|
62444
|
+
);
|
|
62445
|
+
}
|
|
62446
|
+
if (compilerRevision < 1) {
|
|
62447
|
+
throw new NSGetterRuntimeError(
|
|
62448
|
+
"Collection callback compiler revision must be at least 1."
|
|
62449
|
+
);
|
|
62450
|
+
}
|
|
62451
|
+
if (compilerRevision > NEOSCRIPT_COMPILER_REVISION) {
|
|
62452
|
+
throw new NSGetterRuntimeError(
|
|
62453
|
+
`Collection callback compiler revision ${String(compilerRevision)} is newer than supported revision ${String(NEOSCRIPT_COMPILER_REVISION)}.`
|
|
62454
|
+
);
|
|
62455
|
+
}
|
|
62456
|
+
if (!isNSFunctionWithReturnType(callback)) {
|
|
62457
|
+
throw new NSGetterRuntimeError(
|
|
62458
|
+
`Collection callback body metadata is invalid for compiler revision ${String(compilerRevision)}.`
|
|
62459
|
+
);
|
|
62460
|
+
}
|
|
62461
|
+
const parameters = callback.parameters;
|
|
62462
|
+
if (parameters.length < 1) {
|
|
62463
|
+
throw new NSGetterRuntimeError(
|
|
62464
|
+
"Collection callback requires at least one parameter."
|
|
62465
|
+
);
|
|
62466
|
+
}
|
|
62467
|
+
if (parameters.length > 2) {
|
|
62468
|
+
throw new NSGetterRuntimeError(
|
|
62469
|
+
`Collection callback supports at most two parameters, but received ${String(parameters.length)}.`
|
|
62470
|
+
);
|
|
62471
|
+
}
|
|
62472
|
+
if (returnContract === "predicate") {
|
|
62473
|
+
if (callback.typeInfo.type !== 1 /* Bool */) {
|
|
62474
|
+
throw new NSGetterRuntimeError(
|
|
62475
|
+
"Collection predicate callback must declare a Bool return type."
|
|
62476
|
+
);
|
|
62477
|
+
}
|
|
62478
|
+
if (!callback.typeInfo.required) {
|
|
62479
|
+
throw new NSGetterRuntimeError(
|
|
62480
|
+
"Collection predicate callback must declare a required return type."
|
|
62481
|
+
);
|
|
62482
|
+
}
|
|
62483
|
+
}
|
|
62484
|
+
const parameterCount = parameters.length;
|
|
62485
|
+
const callbackScope = ctx.__collectionCallbackStrategy === "fresh" ? null : createChildScope(parentScope);
|
|
62486
|
+
const callbackOptions = evaluationOptions(ctx, false);
|
|
62487
|
+
const instructions = callback.instructions;
|
|
62488
|
+
const returnTypeInfo = callback.typeInfo;
|
|
62489
|
+
const requiresInvocationReset = callbackBodyMayAddInvocationLocals(
|
|
62490
|
+
instructions,
|
|
62491
|
+
new Set(parameters.map((parameter4) => parameter4.id))
|
|
62492
|
+
);
|
|
62493
|
+
let finishBody;
|
|
62494
|
+
if (returnContract === "predicate") {
|
|
62495
|
+
finishBody = (innerScope2) => {
|
|
62496
|
+
const result = evalInstructions(
|
|
62497
|
+
instructions,
|
|
62498
|
+
innerScope2,
|
|
62499
|
+
ctx,
|
|
62500
|
+
callbackOptions
|
|
62501
|
+
);
|
|
62502
|
+
rejectEscapedLoopTransfer(result, "collection callback");
|
|
62503
|
+
if (result.kind !== "return") {
|
|
62504
|
+
throw new NSGetterRuntimeError(
|
|
62505
|
+
"Collection callback ended without returning a value."
|
|
62506
|
+
);
|
|
62507
|
+
}
|
|
62508
|
+
const value = result.value;
|
|
62509
|
+
if (typeof value !== "boolean") {
|
|
62510
|
+
throw new NSGetterRuntimeError(
|
|
62511
|
+
"Collection predicate callback returned a value that does not match its required Bool contract."
|
|
62512
|
+
);
|
|
62513
|
+
}
|
|
62514
|
+
return value;
|
|
62515
|
+
};
|
|
62516
|
+
} else {
|
|
62517
|
+
finishBody = (innerScope2) => {
|
|
62518
|
+
const result = evalInstructions(
|
|
62519
|
+
instructions,
|
|
62520
|
+
innerScope2,
|
|
62521
|
+
ctx,
|
|
62522
|
+
callbackOptions
|
|
62523
|
+
);
|
|
62524
|
+
rejectEscapedLoopTransfer(result, "collection callback");
|
|
62525
|
+
if (result.kind !== "return") {
|
|
62526
|
+
throw new NSGetterRuntimeError(
|
|
62527
|
+
"Collection callback ended without returning a value."
|
|
62528
|
+
);
|
|
62529
|
+
}
|
|
62530
|
+
let value = result.value;
|
|
62531
|
+
if (returnTypeInfo.type === 20 /* Decimal */ && typeof value === "number") {
|
|
62532
|
+
value = coerceDecimalOperand(value, "collection callback return");
|
|
62533
|
+
}
|
|
62534
|
+
if (!runtimeValueMatchesType(value, returnTypeInfo, ctx)) {
|
|
62535
|
+
throw new NSGetterRuntimeError(
|
|
62536
|
+
"Collection projection callback returned a value that does not match its compiled return type."
|
|
62537
|
+
);
|
|
62538
|
+
}
|
|
62539
|
+
return value;
|
|
62540
|
+
};
|
|
62541
|
+
}
|
|
62542
|
+
if (metrics !== void 0) metrics.bindingPlanCreations += 1;
|
|
62543
|
+
if (ctx.__collectionCallbackStrategy === "fresh" || ctx.__collectionCallbackStrategy === "prepared") {
|
|
62544
|
+
return (entry, key, valueId) => {
|
|
62545
|
+
if (onPredicateMatch !== void 0) {
|
|
62546
|
+
consumeBudget(ctx, "workUnits", 1, "work unit");
|
|
62547
|
+
}
|
|
62548
|
+
const innerScope2 = callbackScope ?? createChildScope(parentScope);
|
|
62549
|
+
if (callbackScope !== null) {
|
|
62550
|
+
callbackScope.resetInvocationLocals(parameterCount);
|
|
62551
|
+
}
|
|
62552
|
+
if (parameters.length === 1) {
|
|
62553
|
+
innerScope2.setLocal(parameters[0].id, entry);
|
|
62554
|
+
} else if (parameters.length === 2) {
|
|
62555
|
+
innerScope2.setLocal(
|
|
62556
|
+
parameters[0].id,
|
|
62557
|
+
isList ? Number(key) : String(key)
|
|
62558
|
+
);
|
|
62559
|
+
innerScope2.setLocal(parameters[1].id, entry);
|
|
62560
|
+
}
|
|
62561
|
+
const value = finishBody(innerScope2);
|
|
62562
|
+
if (onPredicateMatch === void 0) return value;
|
|
62563
|
+
return value === true ? onPredicateMatch(entry, key, valueId) : 0 /* Continue */;
|
|
62564
|
+
};
|
|
62565
|
+
}
|
|
62566
|
+
const innerScope = callbackScope ?? createChildScope(parentScope);
|
|
62567
|
+
let bindValues;
|
|
62568
|
+
if (parameterCount === 1) {
|
|
62569
|
+
const entryParameterId = parameters[0].id;
|
|
62570
|
+
bindValues = (entry) => {
|
|
62571
|
+
innerScope.bindInvocationEntry(entryParameterId, entry);
|
|
62572
|
+
};
|
|
62573
|
+
} else {
|
|
62574
|
+
const keyParameterId = parameters[0].id;
|
|
62575
|
+
const entryParameterId = parameters[1].id;
|
|
62576
|
+
bindValues = (entry, key) => {
|
|
62577
|
+
innerScope.bindInvocationKeyAndEntry(
|
|
62578
|
+
keyParameterId,
|
|
62579
|
+
key,
|
|
62580
|
+
entryParameterId,
|
|
62581
|
+
entry
|
|
62582
|
+
);
|
|
62583
|
+
};
|
|
62584
|
+
}
|
|
62585
|
+
if (returnContract === "predicate") {
|
|
62586
|
+
if (onPredicateMatch === void 0) {
|
|
62587
|
+
throw new NSGetterRuntimeError(
|
|
62588
|
+
"Collection predicate preparation requires a match handler."
|
|
62589
|
+
);
|
|
62590
|
+
}
|
|
62591
|
+
if (requiresInvocationReset) {
|
|
62592
|
+
return (entry, key, valueId) => {
|
|
62593
|
+
consumeBudget(ctx, "workUnits", 1, "work unit");
|
|
62594
|
+
innerScope.resetInvocationLocals(parameterCount);
|
|
62595
|
+
bindValues(entry, key);
|
|
62596
|
+
return finishBody(innerScope) === true ? onPredicateMatch(entry, key, valueId) : 0 /* Continue */;
|
|
62597
|
+
};
|
|
62598
|
+
}
|
|
62599
|
+
return (entry, key, valueId) => {
|
|
62600
|
+
consumeBudget(ctx, "workUnits", 1, "work unit");
|
|
62601
|
+
bindValues(entry, key);
|
|
62602
|
+
return finishBody(innerScope) === true ? onPredicateMatch(entry, key, valueId) : 0 /* Continue */;
|
|
62603
|
+
};
|
|
62604
|
+
}
|
|
62605
|
+
if (requiresInvocationReset) {
|
|
62606
|
+
return (entry, key) => {
|
|
62607
|
+
innerScope.resetInvocationLocals(parameterCount);
|
|
62608
|
+
bindValues(entry, key);
|
|
62609
|
+
return finishBody(innerScope);
|
|
62610
|
+
};
|
|
62611
|
+
}
|
|
62612
|
+
return (entry, key) => {
|
|
62613
|
+
bindValues(entry, key);
|
|
62614
|
+
return finishBody(innerScope);
|
|
62615
|
+
};
|
|
62616
|
+
}
|
|
62617
|
+
function callbackBodyMayAddInvocationLocals(instructions, parameterIds) {
|
|
62618
|
+
return instructions.some((instruction) => {
|
|
62619
|
+
switch (instruction.type) {
|
|
62620
|
+
case "variable" /* variable */:
|
|
62621
|
+
return !parameterIds.has(instruction.variable.id);
|
|
62622
|
+
case "assign" /* assign */:
|
|
62623
|
+
return instruction.target.pointer.type === "variable" /* variable */ && !parameterIds.has(instruction.target.pointer.variableId);
|
|
62624
|
+
case "if" /* if */:
|
|
62625
|
+
case "for" /* for */:
|
|
62626
|
+
case "forEach" /* forEach */:
|
|
62627
|
+
case "switch" /* switch */:
|
|
62628
|
+
case "try" /* try */:
|
|
62629
|
+
return true;
|
|
62630
|
+
default:
|
|
62631
|
+
return false;
|
|
62632
|
+
}
|
|
62633
|
+
});
|
|
62634
|
+
}
|
|
62635
|
+
function isListCollection(collection) {
|
|
62636
|
+
if (Array.isArray(collection)) return true;
|
|
62637
|
+
if (typeof collection === "object" && collection !== null) return false;
|
|
62638
|
+
throw new NSGetterRuntimeError(
|
|
62639
|
+
"Collection callback receiver must be a present List or Dictionary value."
|
|
62640
|
+
);
|
|
62641
|
+
}
|
|
62426
62642
|
function evalFunction(fn, scope, ctx) {
|
|
62427
62643
|
switch (fn.type) {
|
|
62428
62644
|
case "classConstructor" /* classConstructor */:
|
|
@@ -62609,34 +62825,15 @@ function evalFunction(fn, scope, ctx) {
|
|
|
62609
62825
|
case "where" /* where */: {
|
|
62610
62826
|
const c = evalPointer(fn.info.collectionPointer, scope, ctx);
|
|
62611
62827
|
const innerFn = fn.info.function;
|
|
62612
|
-
const isList =
|
|
62828
|
+
const isList = isListCollection(c);
|
|
62613
62829
|
const out = isList ? [] : {};
|
|
62614
|
-
const
|
|
62615
|
-
|
|
62616
|
-
|
|
62617
|
-
|
|
62618
|
-
|
|
62619
|
-
|
|
62620
|
-
|
|
62621
|
-
if (callbackScope !== null) {
|
|
62622
|
-
callbackScope.resetInvocationLocals(callbackParameterCount);
|
|
62623
|
-
if (callbackParameterCount === 1) {
|
|
62624
|
-
callbackScope.setLocal(innerFn.parameters[0].id, entry);
|
|
62625
|
-
} else if (callbackParameterCount === 2) {
|
|
62626
|
-
callbackScope.setLocal(
|
|
62627
|
-
innerFn.parameters[0].id,
|
|
62628
|
-
isList ? Number(key) : String(key)
|
|
62629
|
-
);
|
|
62630
|
-
callbackScope.setLocal(innerFn.parameters[1].id, entry);
|
|
62631
|
-
}
|
|
62632
|
-
}
|
|
62633
|
-
const result = evalInstructions(
|
|
62634
|
-
innerFn.instructions,
|
|
62635
|
-
innerScope,
|
|
62636
|
-
ctx,
|
|
62637
|
-
callbackOptions ?? evaluationOptions(ctx, false)
|
|
62638
|
-
);
|
|
62639
|
-
if (result.kind === "return" && result.value === true) {
|
|
62830
|
+
const callback = prepareCollectionCallback(
|
|
62831
|
+
innerFn,
|
|
62832
|
+
scope,
|
|
62833
|
+
ctx,
|
|
62834
|
+
isList,
|
|
62835
|
+
"predicate",
|
|
62836
|
+
(entry, key, valueId) => {
|
|
62640
62837
|
consumeBudget(
|
|
62641
62838
|
ctx,
|
|
62642
62839
|
"producedCollectionEntries",
|
|
@@ -62648,53 +62845,38 @@ function evalFunction(fn, scope, ctx) {
|
|
|
62648
62845
|
} else {
|
|
62649
62846
|
out[String(key)] = valueId ?? entry;
|
|
62650
62847
|
}
|
|
62848
|
+
return 0 /* Continue */;
|
|
62651
62849
|
}
|
|
62652
|
-
|
|
62653
|
-
|
|
62850
|
+
);
|
|
62851
|
+
iterateCollection(c, ctx, callback);
|
|
62654
62852
|
return out;
|
|
62655
62853
|
}
|
|
62656
62854
|
case "first" /* first */:
|
|
62657
62855
|
case "firstOrDefault" /* firstOrDefault */: {
|
|
62658
62856
|
const c = evalPointer(fn.info.collectionPointer, scope, ctx);
|
|
62659
62857
|
const innerFn = fn.info.function ?? null;
|
|
62660
|
-
const isList =
|
|
62858
|
+
const isList = isListCollection(c);
|
|
62661
62859
|
const sentinel = /* @__PURE__ */ Symbol("not-found");
|
|
62662
|
-
const useFreshCallbackScope = ctx.__collectionCallbackStrategy === "fresh";
|
|
62663
|
-
const callbackScope = innerFn === null || useFreshCallbackScope ? null : createChildScope(scope);
|
|
62664
|
-
const callbackOptions = innerFn === null || useFreshCallbackScope ? null : evaluationOptions(ctx, false);
|
|
62665
|
-
const callbackParameterCount = innerFn !== null && (innerFn.parameters.length === 1 || innerFn.parameters.length === 2) ? innerFn.parameters.length : 0;
|
|
62666
62860
|
let found = sentinel;
|
|
62667
|
-
|
|
62668
|
-
|
|
62861
|
+
if (innerFn === null) {
|
|
62862
|
+
iterateCollection(c, ctx, (entry) => {
|
|
62669
62863
|
found = entry;
|
|
62670
62864
|
return 1 /* Break */;
|
|
62671
|
-
}
|
|
62672
|
-
|
|
62673
|
-
const
|
|
62674
|
-
|
|
62675
|
-
|
|
62676
|
-
if (callbackParameterCount === 1) {
|
|
62677
|
-
callbackScope.setLocal(innerFn.parameters[0].id, entry);
|
|
62678
|
-
} else if (callbackParameterCount === 2) {
|
|
62679
|
-
callbackScope.setLocal(
|
|
62680
|
-
innerFn.parameters[0].id,
|
|
62681
|
-
isList ? Number(key) : String(key)
|
|
62682
|
-
);
|
|
62683
|
-
callbackScope.setLocal(innerFn.parameters[1].id, entry);
|
|
62684
|
-
}
|
|
62685
|
-
}
|
|
62686
|
-
const result = evalInstructions(
|
|
62687
|
-
innerFn.instructions,
|
|
62688
|
-
innerScope,
|
|
62865
|
+
});
|
|
62866
|
+
} else {
|
|
62867
|
+
const callback = prepareCollectionCallback(
|
|
62868
|
+
innerFn,
|
|
62869
|
+
scope,
|
|
62689
62870
|
ctx,
|
|
62690
|
-
|
|
62871
|
+
isList,
|
|
62872
|
+
"predicate",
|
|
62873
|
+
(entry) => {
|
|
62874
|
+
found = entry;
|
|
62875
|
+
return 1 /* Break */;
|
|
62876
|
+
}
|
|
62691
62877
|
);
|
|
62692
|
-
|
|
62693
|
-
|
|
62694
|
-
return 1 /* Break */;
|
|
62695
|
-
}
|
|
62696
|
-
return 0 /* Continue */;
|
|
62697
|
-
});
|
|
62878
|
+
iterateCollection(c, ctx, callback);
|
|
62879
|
+
}
|
|
62698
62880
|
if (found !== sentinel) return found;
|
|
62699
62881
|
if (fn.type === "first" /* first */) {
|
|
62700
62882
|
throw new NSGetterRuntimeError(
|
|
@@ -62705,43 +62887,26 @@ function evalFunction(fn, scope, ctx) {
|
|
|
62705
62887
|
}
|
|
62706
62888
|
case "select" /* select */: {
|
|
62707
62889
|
const c = evalPointer(fn.info.collectionPointer, scope, ctx);
|
|
62708
|
-
const useFreshCallbackScope = ctx.__collectionCallbackStrategy === "fresh";
|
|
62709
|
-
const callbackScope = useFreshCallbackScope ? null : createChildScope(scope);
|
|
62710
|
-
const callbackOptions = useFreshCallbackScope ? null : evaluationOptions(ctx, false);
|
|
62711
62890
|
const innerFn = fn.info.function;
|
|
62712
|
-
const
|
|
62713
|
-
const
|
|
62891
|
+
const isList = isListCollection(c);
|
|
62892
|
+
const callback = prepareCollectionCallback(
|
|
62893
|
+
innerFn,
|
|
62894
|
+
scope,
|
|
62895
|
+
ctx,
|
|
62896
|
+
isList,
|
|
62897
|
+
"projection"
|
|
62898
|
+
);
|
|
62714
62899
|
const out = [];
|
|
62715
|
-
iterateCollection(c, ctx, (entry, key) => {
|
|
62900
|
+
iterateCollection(c, ctx, (entry, key, valueId) => {
|
|
62716
62901
|
consumeBudget(ctx, "workUnits", 1, "work unit");
|
|
62717
|
-
const
|
|
62718
|
-
|
|
62719
|
-
callbackScope.resetInvocationLocals(callbackParameterCount);
|
|
62720
|
-
if (callbackParameterCount === 1) {
|
|
62721
|
-
callbackScope.setLocal(innerFn.parameters[0].id, entry);
|
|
62722
|
-
} else if (callbackParameterCount === 2) {
|
|
62723
|
-
callbackScope.setLocal(
|
|
62724
|
-
innerFn.parameters[0].id,
|
|
62725
|
-
isList ? Number(key) : String(key)
|
|
62726
|
-
);
|
|
62727
|
-
callbackScope.setLocal(innerFn.parameters[1].id, entry);
|
|
62728
|
-
}
|
|
62729
|
-
}
|
|
62730
|
-
const result = evalInstructions(
|
|
62731
|
-
innerFn.instructions,
|
|
62732
|
-
innerScope,
|
|
62902
|
+
const value = callback(entry, key, valueId);
|
|
62903
|
+
consumeBudget(
|
|
62733
62904
|
ctx,
|
|
62734
|
-
|
|
62905
|
+
"producedCollectionEntries",
|
|
62906
|
+
1,
|
|
62907
|
+
"produced collection entry"
|
|
62735
62908
|
);
|
|
62736
|
-
|
|
62737
|
-
consumeBudget(
|
|
62738
|
-
ctx,
|
|
62739
|
-
"producedCollectionEntries",
|
|
62740
|
-
1,
|
|
62741
|
-
"produced collection entry"
|
|
62742
|
-
);
|
|
62743
|
-
out.push(result.value);
|
|
62744
|
-
}
|
|
62909
|
+
out.push(value);
|
|
62745
62910
|
return 0 /* Continue */;
|
|
62746
62911
|
});
|
|
62747
62912
|
return out;
|
|
@@ -65294,17 +65459,6 @@ function iterateCollection(c, ctx, callback) {
|
|
|
65294
65459
|
return callback(entry, key, valueId);
|
|
65295
65460
|
});
|
|
65296
65461
|
}
|
|
65297
|
-
function pushParams(parent, parameters, positional, isList) {
|
|
65298
|
-
const child = createChildScope(parent);
|
|
65299
|
-
if (parameters.length === 1) {
|
|
65300
|
-
child.setLocal(parameters[0].id, positional[1]);
|
|
65301
|
-
} else if (parameters.length === 2) {
|
|
65302
|
-
const first = isList ? Number(positional[0]) : String(positional[0]);
|
|
65303
|
-
child.setLocal(parameters[0].id, first);
|
|
65304
|
-
child.setLocal(parameters[1].id, positional[1]);
|
|
65305
|
-
}
|
|
65306
|
-
return child;
|
|
65307
|
-
}
|
|
65308
65462
|
var DELEGATE_LEXICAL_THIS, DELEGATE_LEXICAL_ROOT, NonCatchableNSGetterRuntimeError, NativeFunctionDelegateUnavailableError, CorruptNeoScriptIRError, NeoScriptResourceLimitError, NeoScriptWallClockTimeoutError, DEFAULT_NEO_SCRIPT_EXECUTION_BUDGET_LIMITS, liveListIndexesByProject, evaluatorOwnershipCachesByBase, MAX_CONSTRUCTION_DEPTH, MAX_LOOP_ITERATIONS, resolutionCacheByMembers, NO_SCHEMA_REVISION, LazyValueOverlay, READONLY_FOREACH_BINDING_ERROR, READONLY_CATCH_BINDING_ERROR;
|
|
65309
65463
|
var init_evaluateNSGetter = __esm({
|
|
65310
65464
|
"../src/view-models/neoscript-evaluator/evaluateNSGetter.ts"() {
|
|
@@ -65318,6 +65472,7 @@ var init_evaluateNSGetter = __esm({
|
|
|
65318
65472
|
init_neoscript();
|
|
65319
65473
|
init_NSGetterRuntimeError();
|
|
65320
65474
|
init_value_row_owner_members();
|
|
65475
|
+
init_src();
|
|
65321
65476
|
init_decimal();
|
|
65322
65477
|
init_members();
|
|
65323
65478
|
init_core();
|
|
@@ -83124,6 +83279,15 @@ function applyProjectVersionWriteChanges(document, changes) {
|
|
|
83124
83279
|
"constructor"
|
|
83125
83280
|
),
|
|
83126
83281
|
values: applyArrayChanges(document.values ?? [], changes, "value"),
|
|
83282
|
+
// Project-file staging finalizes pending uploads before schema
|
|
83283
|
+
// preparation. Defaults and authored instance graphs may reference a file
|
|
83284
|
+
// created by the same source transaction, so every construction pass must
|
|
83285
|
+
// see that finalized row in its post-write document.
|
|
83286
|
+
projectFiles: applyArrayChanges(
|
|
83287
|
+
document.projectFiles ?? [],
|
|
83288
|
+
changes,
|
|
83289
|
+
"project-file"
|
|
83290
|
+
),
|
|
83127
83291
|
internalRecordRelations: applyArrayChanges(
|
|
83128
83292
|
document.internalRecordRelations ?? [],
|
|
83129
83293
|
changes,
|
|
@@ -100901,7 +101065,11 @@ async function prepareLocalPushArtifactsV4(workspace, status, onPhase = () => vo
|
|
|
100901
101065
|
);
|
|
100902
101066
|
preparedChanges = assertServerPreparationSucceeds({
|
|
100903
101067
|
workspace,
|
|
100904
|
-
changes:
|
|
101068
|
+
changes: completeLocallyStagedProjectFileChanges({
|
|
101069
|
+
projectId: workspace.config.projectId,
|
|
101070
|
+
changes: transportChanges,
|
|
101071
|
+
stagedRecordIds: new Set(preparedFiles.map((file) => file.recordId))
|
|
101072
|
+
}),
|
|
100905
101073
|
authoredValueSeeds: transportSeeds,
|
|
100906
101074
|
sourceByRecord: status.reconstructed,
|
|
100907
101075
|
localInitializerMaterialization: pendingAssignment.localInitializerMaterialization,
|
|
@@ -101024,6 +101192,33 @@ async function prepareLocalCandidateV4(workspace, options = {}) {
|
|
|
101024
101192
|
preparedLocal
|
|
101025
101193
|
};
|
|
101026
101194
|
}
|
|
101195
|
+
function completeLocallyStagedProjectFileChanges(args) {
|
|
101196
|
+
return args.changes.map((change) => {
|
|
101197
|
+
if (!args.stagedRecordIds.has(change.recordId)) return change;
|
|
101198
|
+
if (change.recordKind !== "project-file") {
|
|
101199
|
+
throw new Error(
|
|
101200
|
+
`Staged project file ${change.recordId} matched a ${change.recordKind} change.`
|
|
101201
|
+
);
|
|
101202
|
+
}
|
|
101203
|
+
if (!isObjectRecord2(change.nextData)) {
|
|
101204
|
+
throw new Error(
|
|
101205
|
+
`Staged project file ${change.recordId} has no local source record.`
|
|
101206
|
+
);
|
|
101207
|
+
}
|
|
101208
|
+
const completed = {
|
|
101209
|
+
...change,
|
|
101210
|
+
nextData: {
|
|
101211
|
+
...change.nextData,
|
|
101212
|
+
id: change.recordId,
|
|
101213
|
+
projectId: args.projectId,
|
|
101214
|
+
status: "uploaded",
|
|
101215
|
+
storageKey: `local-candidate/${change.recordId}`,
|
|
101216
|
+
storageETag: "local-candidate"
|
|
101217
|
+
}
|
|
101218
|
+
};
|
|
101219
|
+
return completed;
|
|
101220
|
+
});
|
|
101221
|
+
}
|
|
101027
101222
|
function transportChangesForStatus(status) {
|
|
101028
101223
|
return status.changes.map((change) => ({
|
|
101029
101224
|
recordKind: change.recordKind,
|
|
@@ -102478,7 +102673,7 @@ var init_registry2 = __esm({
|
|
|
102478
102673
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
102479
102674
|
formatVersion: 3,
|
|
102480
102675
|
contractVersion: "3.9",
|
|
102481
|
-
cliVersion: "0.26.
|
|
102676
|
+
cliVersion: "0.26.4",
|
|
102482
102677
|
projectFileUploadBatchSize: 32,
|
|
102483
102678
|
documentRecords: {
|
|
102484
102679
|
member: {
|
|
@@ -103792,6 +103987,7 @@ import {
|
|
|
103792
103987
|
resolve as resolve3,
|
|
103793
103988
|
sep as sep5
|
|
103794
103989
|
} from "node:path";
|
|
103990
|
+
import { isDeepStrictEqual } from "node:util";
|
|
103795
103991
|
function isRecord10(value) {
|
|
103796
103992
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
103797
103993
|
}
|
|
@@ -103875,9 +104071,46 @@ function stableTestValue(value) {
|
|
|
103875
104071
|
function display(value) {
|
|
103876
104072
|
return stableTestValue(value);
|
|
103877
104073
|
}
|
|
103878
|
-
function
|
|
103879
|
-
|
|
103880
|
-
|
|
104074
|
+
function matcherFailureMessage(kind, expectationValue, expected, received, details) {
|
|
104075
|
+
const actual = expectationValue.actual;
|
|
104076
|
+
const negation = expectationValue.negated ? "not " : "";
|
|
104077
|
+
switch (kind) {
|
|
104078
|
+
case "toBe":
|
|
104079
|
+
return `Expected ${display(actual)} ${negation}to be ${display(expected)}.`;
|
|
104080
|
+
case "toEqual":
|
|
104081
|
+
return `Expected ${display(actual)} ${negation}to equal ${display(expected)}.`;
|
|
104082
|
+
case "toBeNull":
|
|
104083
|
+
return `Expected ${display(actual)} ${negation}to be null.`;
|
|
104084
|
+
case "boolean":
|
|
104085
|
+
return `Expected ${display(actual)} ${negation}to be ${String(expected)}.`;
|
|
104086
|
+
case "numeric":
|
|
104087
|
+
return `Expected ${display(actual)} ${negation}to satisfy numeric comparison with ${display(expected)}.`;
|
|
104088
|
+
case "toContain":
|
|
104089
|
+
return `Expected ${display(actual)} ${negation}to contain ${display(expected)}.`;
|
|
104090
|
+
case "toHaveLength":
|
|
104091
|
+
return `Expected length ${String(expected)}, received ${String(received)}.`;
|
|
104092
|
+
case "toMatchObject":
|
|
104093
|
+
return `Expected ${display(actual)} ${negation}to match ${display(expected)}.`;
|
|
104094
|
+
case "toThrow":
|
|
104095
|
+
return `Expected callback ${negation}to throw${details === void 0 ? "" : ` a message containing ${display(details)}`}.`;
|
|
104096
|
+
case "mock":
|
|
104097
|
+
return `Expected mock ${negation}to match recorded calls ${display(details)}.`;
|
|
104098
|
+
}
|
|
104099
|
+
}
|
|
104100
|
+
function assertMatcher(condition, expectationValue, messageKind, expected, received = expectationValue.actual, details) {
|
|
104101
|
+
if (condition === expectationValue.negated) {
|
|
104102
|
+
throw new NeoTestAssertionError(
|
|
104103
|
+
matcherFailureMessage(
|
|
104104
|
+
messageKind,
|
|
104105
|
+
expectationValue,
|
|
104106
|
+
expected,
|
|
104107
|
+
received,
|
|
104108
|
+
details
|
|
104109
|
+
),
|
|
104110
|
+
expected,
|
|
104111
|
+
received
|
|
104112
|
+
);
|
|
104113
|
+
}
|
|
103881
104114
|
}
|
|
103882
104115
|
function errorMessage2(error) {
|
|
103883
104116
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -104426,8 +104659,7 @@ function mockResponse(environment, mock, selected2, call) {
|
|
|
104426
104659
|
};
|
|
104427
104660
|
}
|
|
104428
104661
|
function partialObjectMatch(actual, expected) {
|
|
104429
|
-
if (!isRecord10(expected))
|
|
104430
|
-
return stableTestValue(actual) === stableTestValue(expected);
|
|
104662
|
+
if (!isRecord10(expected)) return isDeepStrictEqual(actual, expected);
|
|
104431
104663
|
if (!isRecord10(actual)) return false;
|
|
104432
104664
|
return Object.entries(expected).every(
|
|
104433
104665
|
([key, value]) => partialObjectMatch(actual[key], value)
|
|
@@ -104584,56 +104816,28 @@ function interceptTestCallCore(environment, call) {
|
|
|
104584
104816
|
}
|
|
104585
104817
|
return { handled: true, value: null };
|
|
104586
104818
|
}
|
|
104587
|
-
|
|
104588
|
-
NEO_TEST_IDS.toBe,
|
|
104589
|
-
NEO_TEST_IDS.toEqual,
|
|
104590
|
-
NEO_TEST_IDS.toBeNull,
|
|
104591
|
-
NEO_TEST_IDS.toBeTrue,
|
|
104592
|
-
NEO_TEST_IDS.toBeFalse,
|
|
104593
|
-
NEO_TEST_IDS.toBeGreaterThan,
|
|
104594
|
-
NEO_TEST_IDS.toBeGreaterThanOrEqual,
|
|
104595
|
-
NEO_TEST_IDS.toBeLessThan,
|
|
104596
|
-
NEO_TEST_IDS.toBeLessThanOrEqual,
|
|
104597
|
-
NEO_TEST_IDS.toContain,
|
|
104598
|
-
NEO_TEST_IDS.toHaveLength,
|
|
104599
|
-
NEO_TEST_IDS.toMatchObject,
|
|
104600
|
-
NEO_TEST_IDS.toThrow,
|
|
104601
|
-
NEO_TEST_IDS.toHaveBeenCalled,
|
|
104602
|
-
NEO_TEST_IDS.toHaveBeenCalledTimes,
|
|
104603
|
-
NEO_TEST_IDS.toHaveBeenCalledWith
|
|
104604
|
-
]);
|
|
104605
|
-
if (!matcherIds.has(call.memberId)) return { handled: false };
|
|
104819
|
+
if (!MATCHER_IDS.has(call.memberId)) return { handled: false };
|
|
104606
104820
|
const expectationValue = readExpectation(call.receiver);
|
|
104607
104821
|
const actual = expectationValue.actual;
|
|
104608
104822
|
if (call.memberId === NEO_TEST_IDS.toBe) {
|
|
104609
104823
|
assertMatcher(
|
|
104610
104824
|
Object.is(actual, call.args[0]),
|
|
104611
104825
|
expectationValue,
|
|
104612
|
-
|
|
104826
|
+
"toBe",
|
|
104613
104827
|
call.args[0]
|
|
104614
104828
|
);
|
|
104615
104829
|
} else if (call.memberId === NEO_TEST_IDS.toEqual) {
|
|
104616
104830
|
assertMatcher(
|
|
104617
|
-
|
|
104831
|
+
isDeepStrictEqual(actual, call.args[0]),
|
|
104618
104832
|
expectationValue,
|
|
104619
|
-
|
|
104833
|
+
"toEqual",
|
|
104620
104834
|
call.args[0]
|
|
104621
104835
|
);
|
|
104622
104836
|
} else if (call.memberId === NEO_TEST_IDS.toBeNull) {
|
|
104623
|
-
assertMatcher(
|
|
104624
|
-
actual === null,
|
|
104625
|
-
expectationValue,
|
|
104626
|
-
`Expected ${display(actual)} ${expectationValue.negated ? "not " : ""}to be null.`,
|
|
104627
|
-
null
|
|
104628
|
-
);
|
|
104837
|
+
assertMatcher(actual === null, expectationValue, "toBeNull", null);
|
|
104629
104838
|
} else if (call.memberId === NEO_TEST_IDS.toBeTrue || call.memberId === NEO_TEST_IDS.toBeFalse) {
|
|
104630
104839
|
const expected = call.memberId === NEO_TEST_IDS.toBeTrue;
|
|
104631
|
-
assertMatcher(
|
|
104632
|
-
actual === expected,
|
|
104633
|
-
expectationValue,
|
|
104634
|
-
`Expected ${display(actual)} ${expectationValue.negated ? "not " : ""}to be ${String(expected)}.`,
|
|
104635
|
-
expected
|
|
104636
|
-
);
|
|
104840
|
+
assertMatcher(actual === expected, expectationValue, "boolean", expected);
|
|
104637
104841
|
} else if (call.memberId === NEO_TEST_IDS.toBeGreaterThan || call.memberId === NEO_TEST_IDS.toBeGreaterThanOrEqual || call.memberId === NEO_TEST_IDS.toBeLessThan || call.memberId === NEO_TEST_IDS.toBeLessThanOrEqual) {
|
|
104638
104842
|
const left = Number(actual);
|
|
104639
104843
|
const right = Number(call.args[0]);
|
|
@@ -104641,25 +104845,18 @@ function interceptTestCallCore(environment, call) {
|
|
|
104641
104845
|
assertMatcher(
|
|
104642
104846
|
Number.isFinite(left) && Number.isFinite(right) && matches,
|
|
104643
104847
|
expectationValue,
|
|
104644
|
-
|
|
104848
|
+
"numeric",
|
|
104645
104849
|
call.args[0]
|
|
104646
104850
|
);
|
|
104647
104851
|
} else if (call.memberId === NEO_TEST_IDS.toContain) {
|
|
104648
|
-
const contains2 = typeof actual === "string" ? actual.includes(String(call.args[0])) : Array.isArray(actual) && actual.some(
|
|
104649
|
-
|
|
104650
|
-
);
|
|
104651
|
-
assertMatcher(
|
|
104652
|
-
contains2,
|
|
104653
|
-
expectationValue,
|
|
104654
|
-
`Expected ${display(actual)} ${expectationValue.negated ? "not " : ""}to contain ${display(call.args[0])}.`,
|
|
104655
|
-
call.args[0]
|
|
104656
|
-
);
|
|
104852
|
+
const contains2 = typeof actual === "string" ? actual.includes(String(call.args[0])) : Array.isArray(actual) && actual.some((entry) => isDeepStrictEqual(entry, call.args[0]));
|
|
104853
|
+
assertMatcher(contains2, expectationValue, "toContain", call.args[0]);
|
|
104657
104854
|
} else if (call.memberId === NEO_TEST_IDS.toHaveLength) {
|
|
104658
104855
|
const length = typeof actual === "string" || Array.isArray(actual) ? actual.length : isRecord10(actual) ? Object.keys(actual).length : -1;
|
|
104659
104856
|
assertMatcher(
|
|
104660
104857
|
length === call.args[0],
|
|
104661
104858
|
expectationValue,
|
|
104662
|
-
|
|
104859
|
+
"toHaveLength",
|
|
104663
104860
|
call.args[0],
|
|
104664
104861
|
length
|
|
104665
104862
|
);
|
|
@@ -104667,7 +104864,7 @@ function interceptTestCallCore(environment, call) {
|
|
|
104667
104864
|
assertMatcher(
|
|
104668
104865
|
partialObjectMatch(actual, call.args[0]),
|
|
104669
104866
|
expectationValue,
|
|
104670
|
-
|
|
104867
|
+
"toMatchObject",
|
|
104671
104868
|
call.args[0]
|
|
104672
104869
|
);
|
|
104673
104870
|
} else if (call.memberId === NEO_TEST_IDS.toThrow) {
|
|
@@ -104683,9 +104880,10 @@ function interceptTestCallCore(environment, call) {
|
|
|
104683
104880
|
assertMatcher(
|
|
104684
104881
|
matches,
|
|
104685
104882
|
expectationValue,
|
|
104686
|
-
|
|
104883
|
+
"toThrow",
|
|
104687
104884
|
pattern ?? "a catchable NeoScript error",
|
|
104688
|
-
thrown === void 0 ? "no throw" : errorMessage2(thrown)
|
|
104885
|
+
thrown === void 0 ? "no throw" : errorMessage2(thrown),
|
|
104886
|
+
pattern
|
|
104689
104887
|
);
|
|
104690
104888
|
} else {
|
|
104691
104889
|
const handle = readMockHandle(actual);
|
|
@@ -104695,15 +104893,14 @@ function interceptTestCallCore(environment, call) {
|
|
|
104695
104893
|
"Expected value is not an active mock handle."
|
|
104696
104894
|
);
|
|
104697
104895
|
}
|
|
104698
|
-
const matches = call.memberId === NEO_TEST_IDS.toHaveBeenCalled ? mock.calls.length > 0 : call.memberId === NEO_TEST_IDS.toHaveBeenCalledTimes ? mock.calls.length === call.args[0] : mock.calls.some(
|
|
104699
|
-
(args) => stableTestValue(args) === stableTestValue(call.args)
|
|
104700
|
-
);
|
|
104896
|
+
const matches = call.memberId === NEO_TEST_IDS.toHaveBeenCalled ? mock.calls.length > 0 : call.memberId === NEO_TEST_IDS.toHaveBeenCalledTimes ? mock.calls.length === call.args[0] : mock.calls.some((args) => isDeepStrictEqual(args, call.args));
|
|
104701
104897
|
assertMatcher(
|
|
104702
104898
|
matches,
|
|
104703
104899
|
expectationValue,
|
|
104704
|
-
|
|
104900
|
+
"mock",
|
|
104705
104901
|
call.memberId === NEO_TEST_IDS.toHaveBeenCalled ? "at least one call" : call.memberId === NEO_TEST_IDS.toHaveBeenCalledTimes ? call.args[0] : call.args,
|
|
104706
|
-
call.memberId === NEO_TEST_IDS.toHaveBeenCalledTimes ? mock.calls.length : mock.calls
|
|
104902
|
+
call.memberId === NEO_TEST_IDS.toHaveBeenCalledTimes ? mock.calls.length : mock.calls,
|
|
104903
|
+
mock.calls
|
|
104707
104904
|
);
|
|
104708
104905
|
}
|
|
104709
104906
|
return { handled: true, value: null };
|
|
@@ -104994,8 +105191,24 @@ function maintainNeoTestBuildCache(root, maxBytes = TEST_BUILD_CACHE_LIMIT_BYTES
|
|
|
104994
105191
|
}
|
|
104995
105192
|
}
|
|
104996
105193
|
function formatTestDuration(durationMs) {
|
|
105194
|
+
if (durationMs >= 1e3) {
|
|
105195
|
+
const seconds = durationMs / 1e3;
|
|
105196
|
+
return `${seconds < 10 ? seconds.toFixed(2) : seconds.toFixed(1)}s`;
|
|
105197
|
+
}
|
|
104997
105198
|
return `${durationMs < 10 ? durationMs.toFixed(2) : durationMs.toFixed(1)}ms`;
|
|
104998
105199
|
}
|
|
105200
|
+
function paintTestDuration(durationMs) {
|
|
105201
|
+
const formatted = formatTestDuration(durationMs);
|
|
105202
|
+
return durationMs >= 300 ? color.yellow(formatted) : color.dim(formatted);
|
|
105203
|
+
}
|
|
105204
|
+
function formatStatusCounts(passed, failed, total, skipped = 0) {
|
|
105205
|
+
const parts = [
|
|
105206
|
+
failed > 0 ? color.red(`${failed} failed`) : null,
|
|
105207
|
+
passed > 0 ? color.green(`${passed} passed`) : null,
|
|
105208
|
+
skipped > 0 ? color.yellow(`${skipped} skipped`) : null
|
|
105209
|
+
].filter((part) => part !== null);
|
|
105210
|
+
return `${parts.join(color.dim(" | "))} ${color.dim(`(${total})`)}`;
|
|
105211
|
+
}
|
|
104999
105212
|
async function runTest(workspace, options, dependencies = {}) {
|
|
105000
105213
|
const started = Date.now();
|
|
105001
105214
|
const performanceStarted = performance.now();
|
|
@@ -105025,7 +105238,29 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
105025
105238
|
}
|
|
105026
105239
|
};
|
|
105027
105240
|
process.on("SIGINT", handleSigint);
|
|
105241
|
+
const phaseDurations = {
|
|
105242
|
+
prepare: 0,
|
|
105243
|
+
select: 0,
|
|
105244
|
+
compile: 0,
|
|
105245
|
+
register: 0,
|
|
105246
|
+
execute: 0,
|
|
105247
|
+
finalize: 0
|
|
105248
|
+
};
|
|
105028
105249
|
let phase = "prepare";
|
|
105250
|
+
let phaseStarted = performanceStarted;
|
|
105251
|
+
const enterPhase = (next, label) => {
|
|
105252
|
+
const finished = performance.now();
|
|
105253
|
+
phaseDurations[phase] += finished - phaseStarted;
|
|
105254
|
+
phase = next;
|
|
105255
|
+
phaseStarted = finished;
|
|
105256
|
+
dependencies.progress?.update(label);
|
|
105257
|
+
};
|
|
105258
|
+
const finishPhase = () => {
|
|
105259
|
+
const finished = performance.now();
|
|
105260
|
+
phaseDurations[phase] += finished - phaseStarted;
|
|
105261
|
+
phaseStarted = finished;
|
|
105262
|
+
};
|
|
105263
|
+
dependencies.progress?.update("Preparing test project\u2026");
|
|
105029
105264
|
try {
|
|
105030
105265
|
let candidate = dependencies.prepareLocalCandidate === void 0 ? preparedHookCandidate(workspace) : null;
|
|
105031
105266
|
let candidateInputFingerprint = null;
|
|
@@ -105037,7 +105272,11 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
105037
105272
|
candidate = cachedTestCandidate(workspace, candidateInputFingerprint);
|
|
105038
105273
|
}
|
|
105039
105274
|
if (candidate === null) {
|
|
105040
|
-
const prepared = dependencies.prepareLocalCandidate === void 0 ? await prepareLocalCandidateV4(workspace
|
|
105275
|
+
const prepared = dependencies.prepareLocalCandidate === void 0 ? await prepareLocalCandidateV4(workspace, {
|
|
105276
|
+
onPhase: (label) => {
|
|
105277
|
+
dependencies.progress?.update(label);
|
|
105278
|
+
}
|
|
105279
|
+
}) : await dependencies.prepareLocalCandidate(workspace);
|
|
105041
105280
|
if (prepared.document === null) {
|
|
105042
105281
|
throw new NeoTestReportWriteError(
|
|
105043
105282
|
"Local test preparation did not produce a project document."
|
|
@@ -105069,7 +105308,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
105069
105308
|
rawDocument,
|
|
105070
105309
|
candidate.documentSha256
|
|
105071
105310
|
);
|
|
105072
|
-
|
|
105311
|
+
enterPhase("select", "Selecting test files\u2026");
|
|
105073
105312
|
let selectedPaths;
|
|
105074
105313
|
try {
|
|
105075
105314
|
selectedPaths = selectedSpecPaths(workspace, options.selectors);
|
|
@@ -105084,7 +105323,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
105084
105323
|
"No .spec.neo files matched. Pass --passWithNoTests to treat this as success."
|
|
105085
105324
|
);
|
|
105086
105325
|
}
|
|
105087
|
-
|
|
105326
|
+
enterPhase("compile", "Compiling test files\u2026");
|
|
105088
105327
|
specs = selectedPaths.map(
|
|
105089
105328
|
(path) => compileSpec(workspace, rawDocument, path, compilationHash)
|
|
105090
105329
|
);
|
|
@@ -105098,7 +105337,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
105098
105337
|
);
|
|
105099
105338
|
}
|
|
105100
105339
|
}
|
|
105101
|
-
|
|
105340
|
+
enterPhase("register", "Registering tests\u2026");
|
|
105102
105341
|
const registered = specs.map((spec) => registerSpec(spec, rawDocument));
|
|
105103
105342
|
const selectedTests = registered.flatMap((entry) => entry.tests).filter((test) => pattern === null || pattern.test(test.fullName));
|
|
105104
105343
|
for (const entry of registered) {
|
|
@@ -105115,7 +105354,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
105115
105354
|
);
|
|
105116
105355
|
}
|
|
105117
105356
|
const selectedIds = new Set(selectedTests.map((test) => test.id));
|
|
105118
|
-
|
|
105357
|
+
enterPhase("execute", "Running tests\u2026");
|
|
105119
105358
|
const timeoutMs = options.timeoutMs ?? workspace.config.test?.timeoutMs ?? 5e3;
|
|
105120
105359
|
for (const entry of registered) {
|
|
105121
105360
|
const executed = await executeRegisteredSpec(
|
|
@@ -105133,6 +105372,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
105133
105372
|
if (results.some((result) => result.status === "failed") || [...fileFailuresByPath.values()].some((failures) => failures.length > 0)) {
|
|
105134
105373
|
exitCode = 1;
|
|
105135
105374
|
}
|
|
105375
|
+
enterPhase("finalize", "Finalizing test report\u2026");
|
|
105136
105376
|
const buildManifest = {
|
|
105137
105377
|
version: 1,
|
|
105138
105378
|
cliVersion: PROJECT_SCHEMA_CONTRACT.cliVersion,
|
|
@@ -105168,6 +105408,8 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
105168
105408
|
related: []
|
|
105169
105409
|
});
|
|
105170
105410
|
}
|
|
105411
|
+
finishPhase();
|
|
105412
|
+
dependencies.progress?.stop();
|
|
105171
105413
|
process.off("SIGINT", handleSigint);
|
|
105172
105414
|
const failed = results.filter((result) => result.status === "failed").length;
|
|
105173
105415
|
const selectedTestTotal = [...selectedTestCountByFile.values()].reduce(
|
|
@@ -105221,6 +105463,14 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
105221
105463
|
sharedStartupDurationMs,
|
|
105222
105464
|
testDurationMs
|
|
105223
105465
|
},
|
|
105466
|
+
timings: {
|
|
105467
|
+
prepareMs: phaseDurations.prepare,
|
|
105468
|
+
selectMs: phaseDurations.select,
|
|
105469
|
+
compileMs: phaseDurations.compile,
|
|
105470
|
+
registerMs: phaseDurations.register,
|
|
105471
|
+
executeMs: phaseDurations.execute,
|
|
105472
|
+
finalizeMs: phaseDurations.finalize
|
|
105473
|
+
},
|
|
105224
105474
|
testFiles,
|
|
105225
105475
|
diagnostics,
|
|
105226
105476
|
startedAt
|
|
@@ -105244,33 +105494,63 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
105244
105494
|
if (options.reporter === "json") {
|
|
105245
105495
|
if (options.outputFile === null) process.stdout.write(serialized);
|
|
105246
105496
|
} else {
|
|
105497
|
+
console.log("");
|
|
105247
105498
|
console.log(
|
|
105248
|
-
|
|
105499
|
+
` ${color.bold("RUN")} ${color.dim(`neo ${PROJECT_SCHEMA_CONTRACT.cliVersion} ${workspace.root}`)}`
|
|
105249
105500
|
);
|
|
105250
|
-
|
|
105501
|
+
console.log("");
|
|
105502
|
+
console.log(
|
|
105503
|
+
` ${color.cyan("\u21BB")} ${color.dim("shared startup")} ${paintTestDuration(report.summary.sharedStartupDurationMs)}`
|
|
105504
|
+
);
|
|
105505
|
+
for (const file of testFiles) {
|
|
105506
|
+
const fileDurationMs = file.tests.reduce(
|
|
105507
|
+
(sum, test) => sum + test.durationMs,
|
|
105508
|
+
0
|
|
105509
|
+
);
|
|
105510
|
+
const fileSymbol = file.status === "passed" ? color.green("\u2713") : file.status === "failed" ? color.red("\xD7") : color.yellow("!");
|
|
105511
|
+
const testLabel = `${file.tests.length} ${file.tests.length === 1 ? "test" : "tests"}`;
|
|
105251
105512
|
console.log(
|
|
105252
|
-
|
|
105513
|
+
` ${fileSymbol} ${color.bold(file.path)} ${color.dim(`(${testLabel})`)} ${paintTestDuration(fileDurationMs)}`
|
|
105253
105514
|
);
|
|
105254
|
-
for (const
|
|
105255
|
-
|
|
105256
|
-
|
|
105257
|
-
|
|
105515
|
+
for (const result of file.tests) {
|
|
105516
|
+
const resultSymbol = result.status === "passed" ? color.green("\u2713") : color.red("\xD7");
|
|
105517
|
+
console.log(
|
|
105518
|
+
` ${resultSymbol} ${result.name} ${color.dim("total")} ${paintTestDuration(result.durationMs)} ${color.dim(`(test ${formatTestDuration(result.testDurationMs)}, startup ${formatTestDuration(result.startupDurationMs)})`)}`
|
|
105519
|
+
);
|
|
105520
|
+
for (const failure of result.failures) {
|
|
105521
|
+
console.log(` ${color.red(failure.message)}`);
|
|
105522
|
+
}
|
|
105523
|
+
}
|
|
105258
105524
|
if (file.status === "interrupted") {
|
|
105259
105525
|
console.log(
|
|
105260
|
-
|
|
105526
|
+
` ${color.yellow("!")} interrupted before all selected tests ran`
|
|
105261
105527
|
);
|
|
105262
105528
|
}
|
|
105263
105529
|
for (const failure of file.failures) {
|
|
105264
105530
|
console.log(
|
|
105265
|
-
|
|
105531
|
+
` ${color.red("\xD7")} ${failure.frames[0]?.member ?? "suite hook"}`
|
|
105266
105532
|
);
|
|
105267
|
-
console.log(`
|
|
105533
|
+
console.log(` ${color.red(failure.message)}`);
|
|
105268
105534
|
}
|
|
105269
105535
|
}
|
|
105270
|
-
for (const diagnostic of diagnostics)
|
|
105271
|
-
console.log(
|
|
105536
|
+
for (const diagnostic of diagnostics) {
|
|
105537
|
+
console.log(` ${color.red("\xD7")} ${diagnostic.message}`);
|
|
105538
|
+
}
|
|
105539
|
+
console.log("");
|
|
105540
|
+
const passedFiles = testFiles.filter(
|
|
105541
|
+
(file) => file.status === "passed"
|
|
105542
|
+
).length;
|
|
105543
|
+
const failedFiles = testFiles.filter(
|
|
105544
|
+
(file) => file.status === "failed"
|
|
105545
|
+
).length;
|
|
105546
|
+
console.log(
|
|
105547
|
+
` ${color.bold(pad("Test Files", 11))} ${formatStatusCounts(passedFiles, failedFiles, report.summary.files)}`
|
|
105548
|
+
);
|
|
105272
105549
|
console.log(
|
|
105273
|
-
|
|
105550
|
+
` ${color.bold(pad("Tests", 11))} ${formatStatusCounts(report.summary.passed, report.summary.failed, report.summary.tests, report.summary.skipped)}`
|
|
105551
|
+
);
|
|
105552
|
+
console.log(
|
|
105553
|
+
` ${color.bold(pad("Duration", 11))} ${color.bold(`total ${formatTestDuration(report.summary.durationMs)}`)} ${color.dim(`(test ${formatTestDuration(report.summary.testDurationMs)}, startup ${formatTestDuration(report.summary.startupDurationMs)})`)}`
|
|
105274
105554
|
);
|
|
105275
105555
|
}
|
|
105276
105556
|
if (!report.success) process.exitCode = exitCode;
|
|
@@ -105317,7 +105597,7 @@ async function inspectNeoTestCompilation(workspace, dependencies = {}) {
|
|
|
105317
105597
|
errors
|
|
105318
105598
|
};
|
|
105319
105599
|
}
|
|
105320
|
-
var TEST_BUILD_CACHE_LIMIT_BYTES, ABANDONED_TEMP_MAX_AGE_MS, TEST_CANDIDATE_CACHE_REVISION, NeoTestUsageError, NeoTestNoTestsError, NeoTestRegistrationError, NeoTestReportWriteError, NeoTestPreparedCandidateError, NeoTestInterruptedError, NeoTestAssertionError, ERROR_SOURCE_POSITIONS, SHARED_EVALUATOR_BASES, REGISTRATION_IDS;
|
|
105600
|
+
var TEST_BUILD_CACHE_LIMIT_BYTES, ABANDONED_TEMP_MAX_AGE_MS, TEST_CANDIDATE_CACHE_REVISION, NeoTestUsageError, NeoTestNoTestsError, NeoTestRegistrationError, NeoTestReportWriteError, NeoTestPreparedCandidateError, NeoTestInterruptedError, NeoTestAssertionError, ERROR_SOURCE_POSITIONS, SHARED_EVALUATOR_BASES, REGISTRATION_IDS, MATCHER_IDS;
|
|
105321
105601
|
var init_test = __esm({
|
|
105322
105602
|
"src/commands/test.ts"() {
|
|
105323
105603
|
"use strict";
|
|
@@ -105330,6 +105610,7 @@ var init_test = __esm({
|
|
|
105330
105610
|
init_push();
|
|
105331
105611
|
init_registry2();
|
|
105332
105612
|
init_push_hook();
|
|
105613
|
+
init_ui();
|
|
105333
105614
|
TEST_BUILD_CACHE_LIMIT_BYTES = 512 * 1024 * 1024;
|
|
105334
105615
|
ABANDONED_TEMP_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
105335
105616
|
TEST_CANDIDATE_CACHE_REVISION = 1;
|
|
@@ -105374,6 +105655,24 @@ var init_test = __esm({
|
|
|
105374
105655
|
NEO_TEST_IDS.beforeEach,
|
|
105375
105656
|
NEO_TEST_IDS.afterEach
|
|
105376
105657
|
]);
|
|
105658
|
+
MATCHER_IDS = /* @__PURE__ */ new Set([
|
|
105659
|
+
NEO_TEST_IDS.toBe,
|
|
105660
|
+
NEO_TEST_IDS.toEqual,
|
|
105661
|
+
NEO_TEST_IDS.toBeNull,
|
|
105662
|
+
NEO_TEST_IDS.toBeTrue,
|
|
105663
|
+
NEO_TEST_IDS.toBeFalse,
|
|
105664
|
+
NEO_TEST_IDS.toBeGreaterThan,
|
|
105665
|
+
NEO_TEST_IDS.toBeGreaterThanOrEqual,
|
|
105666
|
+
NEO_TEST_IDS.toBeLessThan,
|
|
105667
|
+
NEO_TEST_IDS.toBeLessThanOrEqual,
|
|
105668
|
+
NEO_TEST_IDS.toContain,
|
|
105669
|
+
NEO_TEST_IDS.toHaveLength,
|
|
105670
|
+
NEO_TEST_IDS.toMatchObject,
|
|
105671
|
+
NEO_TEST_IDS.toThrow,
|
|
105672
|
+
NEO_TEST_IDS.toHaveBeenCalled,
|
|
105673
|
+
NEO_TEST_IDS.toHaveBeenCalledTimes,
|
|
105674
|
+
NEO_TEST_IDS.toHaveBeenCalledWith
|
|
105675
|
+
]);
|
|
105377
105676
|
}
|
|
105378
105677
|
});
|
|
105379
105678
|
|
|
@@ -108939,7 +109238,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
108939
109238
|
async function main() {
|
|
108940
109239
|
const args = parseArgs(process.argv.slice(2));
|
|
108941
109240
|
if (args.command === "--version") {
|
|
108942
|
-
console.log("0.26.
|
|
109241
|
+
console.log("0.26.4");
|
|
108943
109242
|
return;
|
|
108944
109243
|
}
|
|
108945
109244
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
|
@@ -109223,15 +109522,25 @@ async function main() {
|
|
|
109223
109522
|
"--testTimeout must be a positive number of milliseconds."
|
|
109224
109523
|
);
|
|
109225
109524
|
}
|
|
109226
|
-
const
|
|
109227
|
-
|
|
109228
|
-
|
|
109229
|
-
|
|
109230
|
-
|
|
109231
|
-
|
|
109232
|
-
|
|
109233
|
-
|
|
109234
|
-
|
|
109525
|
+
const progress = reporterValue === "default" && process.stdout.isTTY === true ? spinner("Preparing test project\u2026") : null;
|
|
109526
|
+
try {
|
|
109527
|
+
const { runTest: runTest2 } = await Promise.resolve().then(() => (init_test(), test_exports));
|
|
109528
|
+
await runTest2(
|
|
109529
|
+
workspace,
|
|
109530
|
+
{
|
|
109531
|
+
selectors: args.positional,
|
|
109532
|
+
testNamePattern: stringFlag(args, "testNamePattern"),
|
|
109533
|
+
reporter: reporterValue,
|
|
109534
|
+
outputFile: stringFlag(args, "outputFile") ?? stringFlag(args, "output-file"),
|
|
109535
|
+
passWithNoTests: boolFlag(args, "passWithNoTests"),
|
|
109536
|
+
...timeoutMs === void 0 ? {} : { timeoutMs }
|
|
109537
|
+
},
|
|
109538
|
+
progress === null ? {} : { progress }
|
|
109539
|
+
);
|
|
109540
|
+
} catch (error) {
|
|
109541
|
+
progress?.fail("Test run failed.");
|
|
109542
|
+
throw error;
|
|
109543
|
+
}
|
|
109235
109544
|
return;
|
|
109236
109545
|
}
|
|
109237
109546
|
case "dev": {
|
package/package.json
CHANGED
|
@@ -83,7 +83,7 @@ wrappers.
|
|
|
83
83
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
84
84
|
|
|
85
85
|
```html
|
|
86
|
-
<!-- reviewed-through-cli: 0.26.
|
|
86
|
+
<!-- reviewed-through-cli: 0.26.4 -->
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
The quoted version above is checked too, so this instruction cannot go stale
|