@neocompose/cli 0.26.1 → 0.26.3
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 +26 -0
- package/README.md +12 -4
- package/dist/neo.mjs +1517 -329
- package/package.json +1 -1
- package/skills/neocompose-cli/SKILL.md +1 -1
- package/skills/neocompose-cli/references/cli-development.md +1 -1
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);
|
|
@@ -2143,16 +2146,28 @@ function complete(snapshot, position) {
|
|
|
2143
2146
|
candidates = switchCaseCandidates;
|
|
2144
2147
|
} else if (tail && (tail.kind === "punctuation" && tail.text === "." || tail.kind === "operator" && tail.text === "?.")) {
|
|
2145
2148
|
const receiverTokens = expressionTokensBefore(tokens, tokens.length - 1);
|
|
2146
|
-
|
|
2147
|
-
|
|
2149
|
+
if (receiverTokens.length === 0 || isContextualCompletionDot(snapshot.source.text, word.start)) {
|
|
2150
|
+
candidates = contextualEnumCompletionItems(
|
|
2151
|
+
snapshot,
|
|
2152
|
+
expectedTypeAt(snapshot, word.start),
|
|
2153
|
+
word
|
|
2154
|
+
);
|
|
2155
|
+
} else {
|
|
2156
|
+
const resolved = resolveChain(snapshot, receiverTokens, offset);
|
|
2157
|
+
candidates = completionItemsForResolution(snapshot, resolved, word);
|
|
2158
|
+
}
|
|
2148
2159
|
} else if (tail?.kind === "identifier" && tail.text === NEOSCRIPT_CONSTRUCTOR_KEYWORD) {
|
|
2149
|
-
candidates = constructorCompletionItems(
|
|
2160
|
+
candidates = constructorCompletionItems(
|
|
2161
|
+
snapshot,
|
|
2162
|
+
word,
|
|
2163
|
+
expectedTypeAt(snapshot, word.start)
|
|
2164
|
+
);
|
|
2150
2165
|
} else if (isTypePosition(tokens)) {
|
|
2151
2166
|
candidates = typeCompletionItems(snapshot, word);
|
|
2152
2167
|
} else if (isLambdaParameterPosition(tokens)) {
|
|
2153
2168
|
candidates = [];
|
|
2154
2169
|
} else {
|
|
2155
|
-
candidates =
|
|
2170
|
+
candidates = contextualCompletionItems(snapshot, offset, word);
|
|
2156
2171
|
}
|
|
2157
2172
|
return {
|
|
2158
2173
|
isIncomplete: hasUnclosedConstruct(snapshot.lexed.tokens, offset),
|
|
@@ -2230,12 +2245,33 @@ function signatureHelp(snapshot, position) {
|
|
|
2230
2245
|
if (call.kind === "constructor") {
|
|
2231
2246
|
const type = resolution?.staticType;
|
|
2232
2247
|
const constructor2 = type?.constructorSignature;
|
|
2233
|
-
|
|
2248
|
+
const declared = type?.declaredConstructors ?? [];
|
|
2249
|
+
if (!type) return null;
|
|
2234
2250
|
const activeParameter2 = countTopLevelCommas(
|
|
2235
2251
|
snapshot.source.text,
|
|
2236
2252
|
call.openParenOffset + 1,
|
|
2237
2253
|
offset
|
|
2238
2254
|
);
|
|
2255
|
+
if (declared.length > 0) {
|
|
2256
|
+
return {
|
|
2257
|
+
signatures: declared.map((candidate) => ({
|
|
2258
|
+
label: `${type.name}(${candidate.parameters.map(
|
|
2259
|
+
(parameter4) => `${formatType(parameter4.type, snapshot.project)} ${parameter4.name}`
|
|
2260
|
+
).join(", ")})`,
|
|
2261
|
+
...candidate.documentation ? { documentation: candidate.documentation } : {},
|
|
2262
|
+
parameters: candidate.parameters.map((parameter4) => ({
|
|
2263
|
+
label: `${formatType(parameter4.type, snapshot.project)} ${parameter4.name}`,
|
|
2264
|
+
...parameter4.documentation ? { documentation: parameter4.documentation } : {}
|
|
2265
|
+
}))
|
|
2266
|
+
})),
|
|
2267
|
+
activeSignature: 0,
|
|
2268
|
+
activeParameter: Math.min(
|
|
2269
|
+
activeParameter2,
|
|
2270
|
+
Math.max(0, (declared[0]?.parameters.length ?? 1) - 1)
|
|
2271
|
+
)
|
|
2272
|
+
};
|
|
2273
|
+
}
|
|
2274
|
+
if (!constructor2) return null;
|
|
2239
2275
|
return {
|
|
2240
2276
|
signatures: [
|
|
2241
2277
|
{
|
|
@@ -2283,19 +2319,18 @@ function inlayHints(snapshot, range2) {
|
|
|
2283
2319
|
const hints = [];
|
|
2284
2320
|
for (const call of snapshot.parsed.calls) {
|
|
2285
2321
|
if (call.kind !== "constructor") continue;
|
|
2286
|
-
const
|
|
2287
|
-
|
|
2288
|
-
)
|
|
2289
|
-
if (!constructor2) continue;
|
|
2322
|
+
const type = snapshot.project.typeByName.get(call.name);
|
|
2323
|
+
const parameterNames = constructorParameterNames(type);
|
|
2324
|
+
if (!parameterNames) continue;
|
|
2290
2325
|
for (let index = 0; index < call.argumentRanges.length; index++) {
|
|
2291
2326
|
const argumentRange = call.argumentRanges[index];
|
|
2292
|
-
const
|
|
2293
|
-
if (!argumentRange || !
|
|
2327
|
+
const parameterName = parameterNames[index];
|
|
2328
|
+
if (!argumentRange || !parameterName) continue;
|
|
2294
2329
|
const position = firstNonWhitespacePosition(snapshot, argumentRange);
|
|
2295
2330
|
if (range2 && !positionInRange(position, range2)) continue;
|
|
2296
2331
|
hints.push({
|
|
2297
2332
|
position,
|
|
2298
|
-
label: `${
|
|
2333
|
+
label: `${parameterName}:`,
|
|
2299
2334
|
kind: "parameter",
|
|
2300
2335
|
paddingRight: true
|
|
2301
2336
|
});
|
|
@@ -2303,6 +2338,22 @@ function inlayHints(snapshot, range2) {
|
|
|
2303
2338
|
}
|
|
2304
2339
|
return hints;
|
|
2305
2340
|
}
|
|
2341
|
+
function constructorParameterNames(type) {
|
|
2342
|
+
const declared = type?.declaredConstructors ?? [];
|
|
2343
|
+
if (declared.length > 0) {
|
|
2344
|
+
const arity = Math.max(
|
|
2345
|
+
...declared.map((constructor2) => constructor2.parameters.length)
|
|
2346
|
+
);
|
|
2347
|
+
return Array.from({ length: arity }, (_, index) => {
|
|
2348
|
+
const names = new Set(
|
|
2349
|
+
declared.map((constructor2) => constructor2.parameters[index]?.name)
|
|
2350
|
+
);
|
|
2351
|
+
const [name] = names;
|
|
2352
|
+
return names.size === 1 && name ? name : null;
|
|
2353
|
+
});
|
|
2354
|
+
}
|
|
2355
|
+
return type?.constructorSignature?.parameters.map((parameter4) => parameter4.name) ?? null;
|
|
2356
|
+
}
|
|
2306
2357
|
function documentSymbols(snapshot) {
|
|
2307
2358
|
const unitSymbols = snapshot.parsed.units.map((unit) => ({
|
|
2308
2359
|
name: unit.kind,
|
|
@@ -2439,8 +2490,9 @@ function isValidNeoIdentifier(name) {
|
|
|
2439
2490
|
function isValidRenameIdentifier(name) {
|
|
2440
2491
|
return isValidNeoIdentifier(name);
|
|
2441
2492
|
}
|
|
2442
|
-
function
|
|
2493
|
+
function contextualCompletionItems(snapshot, offset, word) {
|
|
2443
2494
|
const items = [];
|
|
2495
|
+
const expectedType = expectedTypeAt(snapshot, word.start);
|
|
2444
2496
|
if (insideCatchBody(snapshot, offset)) {
|
|
2445
2497
|
items.push(
|
|
2446
2498
|
completion(
|
|
@@ -2454,7 +2506,12 @@ function topLevelCompletionItems(snapshot, offset, word) {
|
|
|
2454
2506
|
)
|
|
2455
2507
|
);
|
|
2456
2508
|
}
|
|
2509
|
+
const statementStart = isStatementStart(snapshot.lexed.tokens, word.start);
|
|
2457
2510
|
for (const keyword of NEOSCRIPT_KEYWORDS) {
|
|
2511
|
+
if (!statementStart && statementOnlyKeyword(keyword)) continue;
|
|
2512
|
+
if (!statementStart && expectedType !== null && !literalKeywordMatchesExpectedType(keyword, expectedType)) {
|
|
2513
|
+
continue;
|
|
2514
|
+
}
|
|
2458
2515
|
items.push(
|
|
2459
2516
|
completion(
|
|
2460
2517
|
keyword,
|
|
@@ -2467,6 +2524,7 @@ function topLevelCompletionItems(snapshot, offset, word) {
|
|
|
2467
2524
|
);
|
|
2468
2525
|
}
|
|
2469
2526
|
for (const snippet of NEOSCRIPT_STATEMENT_SNIPPETS) {
|
|
2527
|
+
if (!statementStart) continue;
|
|
2470
2528
|
items.push(
|
|
2471
2529
|
completion(
|
|
2472
2530
|
snippet.label,
|
|
@@ -2479,60 +2537,282 @@ function topLevelCompletionItems(snapshot, offset, word) {
|
|
|
2479
2537
|
)
|
|
2480
2538
|
);
|
|
2481
2539
|
}
|
|
2482
|
-
|
|
2483
|
-
completion(
|
|
2484
|
-
NEOSCRIPT_INFERRED_LOCAL_KEYWORD,
|
|
2485
|
-
"snippet",
|
|
2486
|
-
"var ${1:name} = ${0:value};",
|
|
2487
|
-
"Inferred local declaration",
|
|
2488
|
-
word,
|
|
2489
|
-
snapshot,
|
|
2490
|
-
"snippet"
|
|
2491
|
-
)
|
|
2492
|
-
);
|
|
2493
|
-
items.push(
|
|
2494
|
-
completion(
|
|
2495
|
-
NEOSCRIPT_CONSTRUCTOR_KEYWORD,
|
|
2496
|
-
"snippet",
|
|
2497
|
-
"new ${1:ClassName}(${0})",
|
|
2498
|
-
"Construct a Class value",
|
|
2499
|
-
word,
|
|
2500
|
-
snapshot,
|
|
2501
|
-
"snippet"
|
|
2502
|
-
)
|
|
2503
|
-
);
|
|
2504
|
-
for (const primitive3 of NEOSCRIPT_PRIMITIVE_TYPES) {
|
|
2540
|
+
if (statementStart) {
|
|
2505
2541
|
items.push(
|
|
2506
2542
|
completion(
|
|
2507
|
-
|
|
2508
|
-
"
|
|
2509
|
-
|
|
2510
|
-
"
|
|
2543
|
+
NEOSCRIPT_INFERRED_LOCAL_KEYWORD,
|
|
2544
|
+
"snippet",
|
|
2545
|
+
"var ${1:name} = ${0:value};",
|
|
2546
|
+
"Inferred local declaration",
|
|
2511
2547
|
word,
|
|
2512
|
-
snapshot
|
|
2548
|
+
snapshot,
|
|
2549
|
+
"snippet"
|
|
2550
|
+
)
|
|
2551
|
+
);
|
|
2552
|
+
}
|
|
2553
|
+
const expectedNamed = expectedType?.kind === "named" ? snapshot.project.typeById.get(expectedType.typeId) : void 0;
|
|
2554
|
+
if (expectedType === null || expectedNamed?.kind === "class" || expectedNamed?.kind === "interface") {
|
|
2555
|
+
items.push(
|
|
2556
|
+
completion(
|
|
2557
|
+
NEOSCRIPT_CONSTRUCTOR_KEYWORD,
|
|
2558
|
+
"snippet",
|
|
2559
|
+
"new ${1:ClassName}(${0})",
|
|
2560
|
+
"Construct a Class value",
|
|
2561
|
+
word,
|
|
2562
|
+
snapshot,
|
|
2563
|
+
"snippet"
|
|
2564
|
+
)
|
|
2565
|
+
);
|
|
2566
|
+
}
|
|
2567
|
+
if (statementStart && expectedType === null) {
|
|
2568
|
+
for (const primitive3 of NEOSCRIPT_PRIMITIVE_TYPES) {
|
|
2569
|
+
items.push(
|
|
2570
|
+
completion(
|
|
2571
|
+
primitive3,
|
|
2572
|
+
"keyword",
|
|
2573
|
+
primitive3,
|
|
2574
|
+
"Primitive type",
|
|
2575
|
+
word,
|
|
2576
|
+
snapshot
|
|
2577
|
+
)
|
|
2578
|
+
);
|
|
2579
|
+
}
|
|
2580
|
+
items.push(
|
|
2581
|
+
completion(
|
|
2582
|
+
"Dictionary",
|
|
2583
|
+
"snippet",
|
|
2584
|
+
"Dictionary<string, ${1:T}>",
|
|
2585
|
+
"Dictionary type",
|
|
2586
|
+
word,
|
|
2587
|
+
snapshot,
|
|
2588
|
+
"snippet"
|
|
2513
2589
|
)
|
|
2514
2590
|
);
|
|
2515
2591
|
}
|
|
2516
|
-
items.push(
|
|
2517
|
-
completion(
|
|
2518
|
-
"Dictionary",
|
|
2519
|
-
"snippet",
|
|
2520
|
-
"Dictionary<string, ${1:T}>",
|
|
2521
|
-
"Dictionary type",
|
|
2522
|
-
word,
|
|
2523
|
-
snapshot,
|
|
2524
|
-
"snippet"
|
|
2525
|
-
)
|
|
2526
|
-
);
|
|
2527
2592
|
for (const symbol of scopeAt(snapshot, offset)) {
|
|
2593
|
+
if (expectedType !== null && !isNeoScriptTypeAssignable(
|
|
2594
|
+
symbol.returnType ?? symbol.type,
|
|
2595
|
+
expectedType,
|
|
2596
|
+
snapshot.project
|
|
2597
|
+
)) {
|
|
2598
|
+
continue;
|
|
2599
|
+
}
|
|
2528
2600
|
items.push(symbolCompletion(symbol, word, snapshot));
|
|
2529
2601
|
}
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2602
|
+
if (statementStart && expectedType === null) {
|
|
2603
|
+
for (const type of snapshot.project.typeByName.values()) {
|
|
2604
|
+
if (type.kind === "builtin" && type.name.startsWith("__")) continue;
|
|
2605
|
+
items.push(typeCompletion(type, word, snapshot));
|
|
2606
|
+
}
|
|
2533
2607
|
}
|
|
2534
2608
|
return items;
|
|
2535
2609
|
}
|
|
2610
|
+
function contextualEnumCompletionItems(snapshot, expected, word) {
|
|
2611
|
+
if (expected?.kind !== "named") return [];
|
|
2612
|
+
const type = snapshot.project.typeById.get(expected.typeId);
|
|
2613
|
+
if (type?.kind !== "enum") return [];
|
|
2614
|
+
return type.members.filter((member) => member.kind === "enumMember").map((member) => {
|
|
2615
|
+
const item = symbolCompletion(member, word, snapshot);
|
|
2616
|
+
return {
|
|
2617
|
+
...item,
|
|
2618
|
+
label: `.${member.name}`,
|
|
2619
|
+
insertText: member.name,
|
|
2620
|
+
textEdit: {
|
|
2621
|
+
range: snapshot.source.range(word.start, word.end),
|
|
2622
|
+
newText: member.name
|
|
2623
|
+
}
|
|
2624
|
+
};
|
|
2625
|
+
});
|
|
2626
|
+
}
|
|
2627
|
+
function isContextualCompletionDot(text, wordStart) {
|
|
2628
|
+
if (text[wordStart - 1] !== ".") return false;
|
|
2629
|
+
let cursor = wordStart - 2;
|
|
2630
|
+
while (cursor >= 0 && /\s/.test(text[cursor] ?? "")) cursor--;
|
|
2631
|
+
const beforeDot = text[cursor];
|
|
2632
|
+
if (beforeDot !== void 0 && /[A-Za-z0-9_]/.test(beforeDot)) {
|
|
2633
|
+
const precedingWord = /[A-Za-z_][A-Za-z0-9_]*$/.exec(
|
|
2634
|
+
text.slice(0, cursor + 1)
|
|
2635
|
+
)?.[0];
|
|
2636
|
+
return precedingWord === "return" || precedingWord === "case";
|
|
2637
|
+
}
|
|
2638
|
+
return beforeDot === void 0 || !/[A-Za-z0-9_\])}]/.test(beforeDot);
|
|
2639
|
+
}
|
|
2640
|
+
function expectedTypeAt(snapshot, offset) {
|
|
2641
|
+
const call = [...snapshot.parsed.calls].filter(
|
|
2642
|
+
(candidate) => candidate.openParenOffset < offset && (candidate.closeParenOffset === void 0 || candidate.closeParenOffset >= offset)
|
|
2643
|
+
).sort((left, right) => right.openParenOffset - left.openParenOffset)[0];
|
|
2644
|
+
if (call) {
|
|
2645
|
+
const reference2 = snapshot.parsed.references.find(
|
|
2646
|
+
(candidate) => candidate.range.start.line === call.nameRange.start.line && candidate.range.start.character === call.nameRange.start.character
|
|
2647
|
+
);
|
|
2648
|
+
const resolution = reference2 ? resolveReference(snapshot, reference2) : null;
|
|
2649
|
+
const index = countTopLevelCommas(
|
|
2650
|
+
snapshot.source.text,
|
|
2651
|
+
call.openParenOffset + 1,
|
|
2652
|
+
offset
|
|
2653
|
+
);
|
|
2654
|
+
const parameterType = call.kind === "constructor" ? constructorParameterTypeAt(resolution?.staticType, index, snapshot) : resolution?.symbol?.parameters?.[index]?.type;
|
|
2655
|
+
if (parameterType) {
|
|
2656
|
+
return expectedCollectionElementType(
|
|
2657
|
+
parameterType,
|
|
2658
|
+
snapshot.lexed.tokens,
|
|
2659
|
+
call.openParenOffset + 1,
|
|
2660
|
+
offset
|
|
2661
|
+
);
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
const local = snapshot.parsed.locals.filter((candidate) => {
|
|
2665
|
+
const first = candidate.initializerTokens?.[0];
|
|
2666
|
+
return !candidate.inferred && first !== void 0 && first.start <= offset && offset <= snapshot.source.offsetAt(candidate.declarationRange.end);
|
|
2667
|
+
}).sort((left, right) => right.scopeStart - left.scopeStart)[0];
|
|
2668
|
+
if (local) {
|
|
2669
|
+
const first = local.initializerTokens?.[0];
|
|
2670
|
+
return expectedCollectionElementType(
|
|
2671
|
+
resolveDeclaredType(local, snapshot),
|
|
2672
|
+
snapshot.lexed.tokens,
|
|
2673
|
+
first?.start ?? offset,
|
|
2674
|
+
offset
|
|
2675
|
+
);
|
|
2676
|
+
}
|
|
2677
|
+
const tokens = significantTokensBefore(snapshot.lexed.tokens, offset);
|
|
2678
|
+
const boundary = lastStatementBoundary(tokens);
|
|
2679
|
+
for (let index = tokens.length - 1; index > boundary; index--) {
|
|
2680
|
+
const token = tokens[index];
|
|
2681
|
+
if (token?.kind !== "operator" || token.text !== "=") continue;
|
|
2682
|
+
const left = expressionTokensBefore(tokens, index);
|
|
2683
|
+
const resolution = resolveChain(snapshot, left, offset);
|
|
2684
|
+
if (resolution) {
|
|
2685
|
+
return expectedCollectionElementType(
|
|
2686
|
+
resolution.type,
|
|
2687
|
+
tokens,
|
|
2688
|
+
token.end,
|
|
2689
|
+
offset
|
|
2690
|
+
);
|
|
2691
|
+
}
|
|
2692
|
+
break;
|
|
2693
|
+
}
|
|
2694
|
+
for (let index = tokens.length - 1; index > boundary; index--) {
|
|
2695
|
+
const token = tokens[index];
|
|
2696
|
+
if (token?.kind !== "operator" || token.text !== "==" && token.text !== "!=") {
|
|
2697
|
+
continue;
|
|
2698
|
+
}
|
|
2699
|
+
const left = expressionTokensBefore(tokens, index);
|
|
2700
|
+
const type = resolveChain(snapshot, left, offset)?.type ?? inferExpressionType(left, snapshot, left[0]?.start ?? offset);
|
|
2701
|
+
if (!isUnknownExpectedType(type)) return type;
|
|
2702
|
+
}
|
|
2703
|
+
const futureComparison = expectedTypeFromComparisonRight(snapshot, offset);
|
|
2704
|
+
if (futureComparison) return futureComparison;
|
|
2705
|
+
const tail = tokens.at(-1);
|
|
2706
|
+
if (tail?.kind === "operator" && ["!", "&&", "||"].includes(tail.text) || tail?.kind === "punctuation" && tail.text === "(" && tokens.at(-2)?.kind === "keyword" && ["if", "while"].includes(tokens.at(-2)?.text ?? "")) {
|
|
2707
|
+
return { kind: "primitive", name: "bool" };
|
|
2708
|
+
}
|
|
2709
|
+
const throwToken = tokens.slice(boundary + 1).find((token) => token.kind === "keyword" && token.text === "throw");
|
|
2710
|
+
if (throwToken) return { kind: "primitive", name: "string" };
|
|
2711
|
+
const returnToken = tokens.slice(boundary + 1).find((token) => token.kind === "keyword" && token.text === "return");
|
|
2712
|
+
if (returnToken && snapshot.context.returnType) {
|
|
2713
|
+
return expectedCollectionElementType(
|
|
2714
|
+
snapshot.context.returnType,
|
|
2715
|
+
tokens,
|
|
2716
|
+
returnToken.end,
|
|
2717
|
+
offset
|
|
2718
|
+
);
|
|
2719
|
+
}
|
|
2720
|
+
return null;
|
|
2721
|
+
}
|
|
2722
|
+
function expectedTypeFromComparisonRight(snapshot, offset) {
|
|
2723
|
+
const tokens = snapshot.lexed.tokens.filter(
|
|
2724
|
+
(token) => token.kind !== "comment" && token.kind !== "eof"
|
|
2725
|
+
);
|
|
2726
|
+
let operatorIndex = -1;
|
|
2727
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
2728
|
+
const token = tokens[index];
|
|
2729
|
+
if (!token || token.start < offset) continue;
|
|
2730
|
+
if (token.kind === "punctuation" && [";", "{", "}"].includes(token.text)) {
|
|
2731
|
+
break;
|
|
2732
|
+
}
|
|
2733
|
+
if (token.kind === "operator" && (token.text === "==" || token.text === "!=")) {
|
|
2734
|
+
operatorIndex = index;
|
|
2735
|
+
break;
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
if (operatorIndex < 0) return null;
|
|
2739
|
+
const right = [];
|
|
2740
|
+
let depth = 0;
|
|
2741
|
+
for (let index = operatorIndex + 1; index < tokens.length; index++) {
|
|
2742
|
+
const token = tokens[index];
|
|
2743
|
+
if (!token) continue;
|
|
2744
|
+
if (token.kind === "punctuation" && ["(", "["].includes(token.text)) {
|
|
2745
|
+
depth++;
|
|
2746
|
+
} else if (token.kind === "punctuation" && [")", "]"].includes(token.text)) {
|
|
2747
|
+
if (depth === 0) break;
|
|
2748
|
+
depth--;
|
|
2749
|
+
}
|
|
2750
|
+
if (depth === 0 && token.kind === "punctuation" && [";", ",", "{"].includes(token.text)) {
|
|
2751
|
+
break;
|
|
2752
|
+
}
|
|
2753
|
+
right.push(token);
|
|
2754
|
+
}
|
|
2755
|
+
const type = inferExpressionType(right, snapshot, right[0]?.start ?? offset);
|
|
2756
|
+
return isUnknownExpectedType(type) ? null : type;
|
|
2757
|
+
}
|
|
2758
|
+
function isUnknownExpectedType(type) {
|
|
2759
|
+
return type.kind === "primitive" && type.name === "unknown";
|
|
2760
|
+
}
|
|
2761
|
+
function constructorParameterTypeAt(type, index, snapshot) {
|
|
2762
|
+
const declared = (type?.declaredConstructors ?? []).map((constructor2) => constructor2.parameters[index]?.type).filter(
|
|
2763
|
+
(candidate) => candidate !== void 0
|
|
2764
|
+
);
|
|
2765
|
+
if ((type?.declaredConstructors?.length ?? 0) === 0) {
|
|
2766
|
+
return type?.constructorSignature?.parameters[index]?.parameterType;
|
|
2767
|
+
}
|
|
2768
|
+
if (declared.length === 0) return void 0;
|
|
2769
|
+
const first = declared[0];
|
|
2770
|
+
return declared.every(
|
|
2771
|
+
(candidate) => isNeoScriptTypeAssignable(candidate, first, snapshot.project) && isNeoScriptTypeAssignable(first, candidate, snapshot.project)
|
|
2772
|
+
) ? first : void 0;
|
|
2773
|
+
}
|
|
2774
|
+
function expectedCollectionElementType(initial, tokens, start, end) {
|
|
2775
|
+
let expected = initial;
|
|
2776
|
+
const stack = [];
|
|
2777
|
+
for (const token of tokens) {
|
|
2778
|
+
if (token.start < start || token.end > end || token.kind !== "punctuation") {
|
|
2779
|
+
continue;
|
|
2780
|
+
}
|
|
2781
|
+
if (token.text === "[") {
|
|
2782
|
+
stack.push(expected);
|
|
2783
|
+
if (expected.kind === "list" || expected.kind === "set") {
|
|
2784
|
+
expected = expected.elementType;
|
|
2785
|
+
}
|
|
2786
|
+
} else if (token.text === "]") {
|
|
2787
|
+
expected = stack.pop() ?? expected;
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
return expected;
|
|
2791
|
+
}
|
|
2792
|
+
function lastStatementBoundary(tokens) {
|
|
2793
|
+
for (let index = tokens.length - 1; index >= 0; index--) {
|
|
2794
|
+
const token = tokens[index];
|
|
2795
|
+
if (token?.kind === "punctuation" && (token.text === ";" || token.text === "{" || token.text === "}")) {
|
|
2796
|
+
return index;
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
return -1;
|
|
2800
|
+
}
|
|
2801
|
+
function isStatementStart(tokens, offset) {
|
|
2802
|
+
const significant = significantTokensBefore(tokens, offset);
|
|
2803
|
+
const tail = significant.at(-1);
|
|
2804
|
+
return tail === void 0 || tail.kind === "punctuation" && (tail.text === ";" || tail.text === "{" || tail.text === "}") || tail.kind === "punctuation" && tail.text === ":";
|
|
2805
|
+
}
|
|
2806
|
+
function statementOnlyKeyword(keyword) {
|
|
2807
|
+
return !["true", "false", "null", "is"].includes(keyword);
|
|
2808
|
+
}
|
|
2809
|
+
function literalKeywordMatchesExpectedType(keyword, expected) {
|
|
2810
|
+
if (keyword === "true" || keyword === "false") {
|
|
2811
|
+
return expected.kind === "primitive" && expected.name === "bool";
|
|
2812
|
+
}
|
|
2813
|
+
if (keyword === "null") return expected.nullable === true;
|
|
2814
|
+
return false;
|
|
2815
|
+
}
|
|
2536
2816
|
function catchFilterCompletionItems(snapshot, offset, word) {
|
|
2537
2817
|
const prefix = snapshot.source.text.slice(0, offset);
|
|
2538
2818
|
if (!/\bcatch\s*\(\s*string\s+[A-Za-z_][A-Za-z0-9_]*\s*\)\s*$/.test(prefix)) {
|
|
@@ -2682,16 +2962,24 @@ function typeCompletionItems(snapshot, word) {
|
|
|
2682
2962
|
}
|
|
2683
2963
|
return items;
|
|
2684
2964
|
}
|
|
2685
|
-
function constructorCompletionItems(snapshot, word) {
|
|
2965
|
+
function constructorCompletionItems(snapshot, word, expected = null) {
|
|
2686
2966
|
return [...snapshot.project.typeByName.values()].flatMap((type) => {
|
|
2687
2967
|
const signature = type.constructorSignature;
|
|
2688
|
-
|
|
2968
|
+
const declared = type.declaredConstructors ?? [];
|
|
2969
|
+
if (!signature && declared.length === 0) return [];
|
|
2970
|
+
if (expected !== null && !isNeoScriptTypeAssignable(
|
|
2971
|
+
{ kind: "named", typeId: type.id },
|
|
2972
|
+
expected,
|
|
2973
|
+
snapshot.project
|
|
2974
|
+
)) {
|
|
2975
|
+
return [];
|
|
2976
|
+
}
|
|
2689
2977
|
const insertText = `${type.name}(`;
|
|
2690
2978
|
return [
|
|
2691
2979
|
{
|
|
2692
2980
|
label: type.name,
|
|
2693
2981
|
kind: "class",
|
|
2694
|
-
detail: formatConstructorSignature(type.name, signature, snapshot),
|
|
2982
|
+
detail: declared.length > 0 ? `${type.name} \u2014 ${declared.length} declared constructor${declared.length === 1 ? "" : "s"}` : signature ? formatConstructorSignature(type.name, signature, snapshot) : type.name,
|
|
2695
2983
|
...type.documentation ? { documentation: type.documentation } : {},
|
|
2696
2984
|
insertText,
|
|
2697
2985
|
textEdit: {
|
|
@@ -2764,6 +3052,22 @@ function membersForType(snapshot, type) {
|
|
|
2764
3052
|
return [];
|
|
2765
3053
|
}
|
|
2766
3054
|
function resolveReference(snapshot, reference2) {
|
|
3055
|
+
if (!reference2.member && (isTypeAnnotationReference(snapshot, reference2) || isConstructorTypeReference(snapshot, reference2))) {
|
|
3056
|
+
const type = snapshot.project.typeByName.get(reference2.name);
|
|
3057
|
+
if (type) {
|
|
3058
|
+
return {
|
|
3059
|
+
type: { kind: "named", typeId: type.id },
|
|
3060
|
+
staticType: type
|
|
3061
|
+
};
|
|
3062
|
+
}
|
|
3063
|
+
}
|
|
3064
|
+
if (reference2.member && isContextualCompletionDot(snapshot.source.text, reference2.start)) {
|
|
3065
|
+
const contextual = resolveContextualExpectedEnumReference(
|
|
3066
|
+
snapshot,
|
|
3067
|
+
reference2
|
|
3068
|
+
);
|
|
3069
|
+
if (contextual) return contextual;
|
|
3070
|
+
}
|
|
2767
3071
|
const tokens = snapshot.lexed.tokens.filter(
|
|
2768
3072
|
(token) => token.kind !== "comment" && token.kind !== "eof" && token.end <= reference2.end
|
|
2769
3073
|
);
|
|
@@ -2814,6 +3118,16 @@ function resolveContextualSwitchEnumReference(snapshot, reference2) {
|
|
|
2814
3118
|
);
|
|
2815
3119
|
return symbol ? { type: symbol.type, symbol } : null;
|
|
2816
3120
|
}
|
|
3121
|
+
function resolveContextualExpectedEnumReference(snapshot, reference2) {
|
|
3122
|
+
const expected = expectedTypeAt(snapshot, reference2.start);
|
|
3123
|
+
if (expected?.kind !== "named") return null;
|
|
3124
|
+
const type = snapshot.project.typeById.get(expected.typeId);
|
|
3125
|
+
if (type?.kind !== "enum") return null;
|
|
3126
|
+
const symbol = type.members.find(
|
|
3127
|
+
(member) => member.kind === "enumMember" && member.name === reference2.name
|
|
3128
|
+
);
|
|
3129
|
+
return symbol ? { type: symbol.type, symbol } : null;
|
|
3130
|
+
}
|
|
2817
3131
|
function switchCaseEnumContext(snapshot, offset) {
|
|
2818
3132
|
for (const statement of snapshot.parsed.switches) {
|
|
2819
3133
|
for (const section of statement.sections) {
|
|
@@ -3067,6 +3381,19 @@ function scopeAt(snapshot, offset) {
|
|
|
3067
3381
|
)
|
|
3068
3382
|
);
|
|
3069
3383
|
}
|
|
3384
|
+
const declaringType = snapshot.context.declaringType;
|
|
3385
|
+
if (snapshot.context.implicitMemberAccess === true && declaringType?.kind === "named") {
|
|
3386
|
+
const owner = snapshot.project.typeById.get(declaringType.typeId);
|
|
3387
|
+
if (owner) {
|
|
3388
|
+
for (const member of owner.members) {
|
|
3389
|
+
if (snapshot.context.staticMember === true && member.static !== true) {
|
|
3390
|
+
continue;
|
|
3391
|
+
}
|
|
3392
|
+
if (!isMemberCompletionAccessible(snapshot, owner, member)) continue;
|
|
3393
|
+
result.push(withScope(member, 0, snapshot.source.text.length));
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
}
|
|
3070
3397
|
if (effectiveDocumentKind(snapshot, offset) === "setter" && snapshot.context.returnType) {
|
|
3071
3398
|
result.push(
|
|
3072
3399
|
withScope(
|
|
@@ -3903,6 +4230,11 @@ function isTypeAnnotationReference(snapshot, reference2) {
|
|
|
3903
4230
|
(local) => local.typeTokens.some((token) => token.start === reference2.start)
|
|
3904
4231
|
);
|
|
3905
4232
|
}
|
|
4233
|
+
function isConstructorTypeReference(snapshot, reference2) {
|
|
4234
|
+
return snapshot.parsed.calls.some(
|
|
4235
|
+
(call) => call.kind === "constructor" && call.nameRange.start.line === reference2.range.start.line && call.nameRange.start.character === reference2.range.start.character
|
|
4236
|
+
);
|
|
4237
|
+
}
|
|
3906
4238
|
var IDENTIFIER_PATTERN, RESERVED_NAMES;
|
|
3907
4239
|
var init_analyzer = __esm({
|
|
3908
4240
|
"../packages/neoscript-language/src/analyzer.ts"() {
|
|
@@ -21592,6 +21924,7 @@ function compileProjectSourceBodies(documents) {
|
|
|
21592
21924
|
const graph = buildProjectGraph(documents);
|
|
21593
21925
|
const projectIndex = createProjectIndex(graph.project);
|
|
21594
21926
|
const bodies = [];
|
|
21927
|
+
const contexts = [];
|
|
21595
21928
|
const diagnostics = [];
|
|
21596
21929
|
for (const [uri, document] of documents) {
|
|
21597
21930
|
if (document.kind !== "definition") continue;
|
|
@@ -21636,6 +21969,7 @@ function compileProjectSourceBodies(documents) {
|
|
|
21636
21969
|
},
|
|
21637
21970
|
projectIndex,
|
|
21638
21971
|
bodies,
|
|
21972
|
+
contexts,
|
|
21639
21973
|
diagnostics
|
|
21640
21974
|
});
|
|
21641
21975
|
}
|
|
@@ -21671,6 +22005,7 @@ function compileProjectSourceBodies(documents) {
|
|
|
21671
22005
|
},
|
|
21672
22006
|
projectIndex,
|
|
21673
22007
|
bodies,
|
|
22008
|
+
contexts,
|
|
21674
22009
|
diagnostics
|
|
21675
22010
|
});
|
|
21676
22011
|
}
|
|
@@ -21711,6 +22046,7 @@ function compileProjectSourceBodies(documents) {
|
|
|
21711
22046
|
},
|
|
21712
22047
|
projectIndex,
|
|
21713
22048
|
bodies,
|
|
22049
|
+
contexts,
|
|
21714
22050
|
diagnostics
|
|
21715
22051
|
});
|
|
21716
22052
|
continue;
|
|
@@ -21735,15 +22071,24 @@ function compileProjectSourceBodies(documents) {
|
|
|
21735
22071
|
context: { ...baseContext2, kind: unit },
|
|
21736
22072
|
projectIndex,
|
|
21737
22073
|
bodies,
|
|
22074
|
+
contexts,
|
|
21738
22075
|
diagnostics
|
|
21739
22076
|
});
|
|
21740
22077
|
}
|
|
21741
22078
|
}
|
|
21742
22079
|
}
|
|
21743
22080
|
}
|
|
21744
|
-
return { project: graph.project, bodies, diagnostics };
|
|
22081
|
+
return { project: graph.project, bodies, contexts, diagnostics };
|
|
21745
22082
|
}
|
|
21746
22083
|
function compileBody(args) {
|
|
22084
|
+
args.contexts.push({
|
|
22085
|
+
uri: args.uri,
|
|
22086
|
+
ownerName: args.owner.declaration.name,
|
|
22087
|
+
memberName: args.memberName,
|
|
22088
|
+
unit: args.unit,
|
|
22089
|
+
range: args.range,
|
|
22090
|
+
context: args.context
|
|
22091
|
+
});
|
|
21747
22092
|
const source = new SourceText(args.document.sourceText);
|
|
21748
22093
|
const start = source.offsetAt(args.range.start);
|
|
21749
22094
|
const end = source.offsetAt(args.range.end);
|
|
@@ -24063,6 +24408,7 @@ function analyzeNeoProjectSources(inputs, parsedDocuments = /* @__PURE__ */ new
|
|
|
24063
24408
|
symbols,
|
|
24064
24409
|
project: bodyCompilation.project,
|
|
24065
24410
|
compiledBodies: bodyCompilation.bodies,
|
|
24411
|
+
bodyContexts: bodyCompilation.contexts,
|
|
24066
24412
|
diagnostics
|
|
24067
24413
|
};
|
|
24068
24414
|
}
|
|
@@ -24890,9 +25236,25 @@ var init_quick_fixes = __esm({
|
|
|
24890
25236
|
|
|
24891
25237
|
// ../packages/neoscript-language/src/project-source-language-features.ts
|
|
24892
25238
|
function projectDiagnostics(analysis, uri) {
|
|
24893
|
-
return analysis.diagnostics.filter((diagnostic) => diagnostic.uri === uri).map((
|
|
25239
|
+
return analysis.diagnostics.filter((diagnostic) => diagnostic.uri === uri).map((diagnostic) => ({
|
|
25240
|
+
range: diagnostic.range,
|
|
25241
|
+
severity: diagnostic.severity,
|
|
25242
|
+
message: diagnostic.message,
|
|
25243
|
+
...diagnostic.code === void 0 ? {} : { code: diagnostic.code },
|
|
25244
|
+
...diagnostic.source === void 0 ? {} : { source: diagnostic.source },
|
|
25245
|
+
...diagnostic.relatedInformation === void 0 ? {} : { relatedInformation: diagnostic.relatedInformation },
|
|
25246
|
+
...diagnostic.suggestions === void 0 ? {} : { suggestions: diagnostic.suggestions }
|
|
25247
|
+
}));
|
|
24894
25248
|
}
|
|
24895
25249
|
function projectCompletions(analysis, document, position) {
|
|
25250
|
+
const body = projectBodySnapshotAt(analysis, document, position);
|
|
25251
|
+
if (body) return complete(body, position);
|
|
25252
|
+
const annotations = projectAnnotationCompletions(
|
|
25253
|
+
analysis,
|
|
25254
|
+
document,
|
|
25255
|
+
position
|
|
25256
|
+
);
|
|
25257
|
+
if (annotations) return { isIncomplete: false, items: annotations };
|
|
24896
25258
|
const members = projectMemberCompletions(analysis, document, position);
|
|
24897
25259
|
if (members) {
|
|
24898
25260
|
return {
|
|
@@ -24977,13 +25339,126 @@ function projectCompletions(analysis, document, position) {
|
|
|
24977
25339
|
if (initializerMembers) {
|
|
24978
25340
|
return { isIncomplete: false, items: initializerMembers };
|
|
24979
25341
|
}
|
|
25342
|
+
const contextualEnum = projectContextualEnumCompletions(
|
|
25343
|
+
analysis,
|
|
25344
|
+
document,
|
|
25345
|
+
position
|
|
25346
|
+
);
|
|
25347
|
+
if (contextualEnum) {
|
|
25348
|
+
return { isIncomplete: false, items: contextualEnum };
|
|
25349
|
+
}
|
|
25350
|
+
return projectFallbackCompletions(analysis, document, position);
|
|
25351
|
+
}
|
|
25352
|
+
function projectAnnotationCompletions(analysis, document, position) {
|
|
25353
|
+
const source = new SourceText(document.text);
|
|
25354
|
+
const offset = source.offsetAt(position);
|
|
25355
|
+
const word = projectWordRange(document.text, offset);
|
|
25356
|
+
if (document.text[word.start - 1] !== "@") return null;
|
|
25357
|
+
if (initializerRootAt(analysis, document, position)) return [];
|
|
25358
|
+
const names = projectAnnotationNamesAt(analysis, document, position);
|
|
25359
|
+
return names.map((name) => ({
|
|
25360
|
+
label: `@${name}`,
|
|
25361
|
+
kind: "snippet",
|
|
25362
|
+
insertText: name,
|
|
25363
|
+
textEdit: {
|
|
25364
|
+
range: source.range(word.start, word.end),
|
|
25365
|
+
newText: name
|
|
25366
|
+
}
|
|
25367
|
+
}));
|
|
25368
|
+
}
|
|
25369
|
+
function projectAnnotationNamesAt(analysis, document, position) {
|
|
25370
|
+
const source = analysis.documents.get(document.uri);
|
|
25371
|
+
if (!source) return [];
|
|
25372
|
+
if (document.languageId === "neoflow") {
|
|
25373
|
+
return ["id", "primary", "incomplete"];
|
|
25374
|
+
}
|
|
25375
|
+
const offset = new SourceText(document.text).offsetAt(position);
|
|
25376
|
+
const followingDeclaration = /^\s*(class|interface|enum)\b([^{}]*)/.exec(
|
|
25377
|
+
document.text.slice(offset)
|
|
25378
|
+
);
|
|
25379
|
+
if (followingDeclaration?.[1] === "class") {
|
|
25380
|
+
return [
|
|
25381
|
+
"id",
|
|
25382
|
+
"hidden",
|
|
25383
|
+
"settings",
|
|
25384
|
+
"storage",
|
|
25385
|
+
"relations",
|
|
25386
|
+
.../\bDialogue\b/.test(followingDeclaration[2] ?? "") ? ["incomplete"] : []
|
|
25387
|
+
];
|
|
25388
|
+
}
|
|
25389
|
+
if (followingDeclaration) return ["id"];
|
|
25390
|
+
const containing = declarationContaining(source, position);
|
|
25391
|
+
if (containing?.kind === "enum") return ["id"];
|
|
25392
|
+
if (containing?.kind === "class" || containing?.kind === "interface") {
|
|
25393
|
+
if (positionCompare(position, containing.nameRange.start) < 0) {
|
|
25394
|
+
return projectDeclarationAnnotationNames(containing);
|
|
25395
|
+
}
|
|
25396
|
+
const member = containing.members.find(
|
|
25397
|
+
(candidate) => rangeContains(candidate.range, position) || positionCompare(position, candidate.range.start) <= 0
|
|
25398
|
+
);
|
|
25399
|
+
return projectMemberAnnotationNames(member);
|
|
25400
|
+
}
|
|
25401
|
+
const following = source.declarations.find(
|
|
25402
|
+
(declaration) => positionCompare(position, declaration.range.start) <= 0
|
|
25403
|
+
);
|
|
25404
|
+
if (following) return projectDeclarationAnnotationNames(following);
|
|
25405
|
+
return ["id"];
|
|
25406
|
+
}
|
|
25407
|
+
function projectDeclarationAnnotationNames(declaration) {
|
|
25408
|
+
if (declaration.kind !== "class") return ["id"];
|
|
25409
|
+
return [
|
|
25410
|
+
"id",
|
|
25411
|
+
"hidden",
|
|
25412
|
+
"settings",
|
|
25413
|
+
"storage",
|
|
25414
|
+
"relations",
|
|
25415
|
+
...declaration.baseTypes.some((type) => type.name === "Dialogue") ? ["incomplete"] : []
|
|
25416
|
+
];
|
|
25417
|
+
}
|
|
25418
|
+
function projectMemberAnnotationNames(member) {
|
|
25419
|
+
const names = ["id", "settings", "storage", "locked"];
|
|
25420
|
+
if (member?.type.name === "List") names.push("index", "column");
|
|
25421
|
+
return names;
|
|
25422
|
+
}
|
|
25423
|
+
function projectContextualEnumCompletions(analysis, document, position) {
|
|
25424
|
+
const source = new SourceText(document.text);
|
|
25425
|
+
const offset = source.offsetAt(position);
|
|
25426
|
+
const word = projectWordRange(document.text, offset);
|
|
25427
|
+
if (!isContextualDot(document.text, word.start)) return null;
|
|
25428
|
+
const typeName = constructionSiteAt(
|
|
25429
|
+
analysis,
|
|
25430
|
+
document,
|
|
25431
|
+
position
|
|
25432
|
+
)?.expectedTypeName;
|
|
25433
|
+
if (!typeName) return null;
|
|
25434
|
+
const type = analysis.project.types.find(
|
|
25435
|
+
(candidate) => candidate.kind === "enum" && candidate.name === typeName
|
|
25436
|
+
);
|
|
25437
|
+
if (!type) return null;
|
|
25438
|
+
return type.members.filter((member) => member.kind === "enumMember").map((member) => ({
|
|
25439
|
+
label: `.${member.name}`,
|
|
25440
|
+
kind: "enumMember",
|
|
25441
|
+
detail: type.name,
|
|
25442
|
+
insertText: member.name,
|
|
25443
|
+
textEdit: {
|
|
25444
|
+
range: source.range(word.start, word.end),
|
|
25445
|
+
newText: member.name
|
|
25446
|
+
},
|
|
25447
|
+
symbolId: member.id
|
|
25448
|
+
}));
|
|
25449
|
+
}
|
|
25450
|
+
function projectFallbackCompletions(analysis, document, position) {
|
|
24980
25451
|
const items = /* @__PURE__ */ new Map();
|
|
24981
|
-
|
|
24982
|
-
|
|
24983
|
-
|
|
24984
|
-
|
|
24985
|
-
|
|
24986
|
-
|
|
25452
|
+
const construction = constructionSiteAt(analysis, document, position);
|
|
25453
|
+
const recoveredInitializerType = projectInitializerExpectedTypeNameAt(
|
|
25454
|
+
document,
|
|
25455
|
+
position
|
|
25456
|
+
);
|
|
25457
|
+
const expression = construction !== null || recoveredInitializerType !== null;
|
|
25458
|
+
const expectedTypeName = construction?.expectedTypeName ?? recoveredInitializerType;
|
|
25459
|
+
const afterNew = expression && projectAfterNewAt(document, position);
|
|
25460
|
+
const typePosition = projectTypePositionAt(analysis, document, position);
|
|
25461
|
+
const keywords = expression ? afterNew ? [] : ["new"] : typePosition ? [] : [
|
|
24987
25462
|
"class",
|
|
24988
25463
|
"interface",
|
|
24989
25464
|
"enum",
|
|
@@ -24993,16 +25468,20 @@ function projectCompletions(analysis, document, position) {
|
|
|
24993
25468
|
"override",
|
|
24994
25469
|
"readonly",
|
|
24995
25470
|
"virtual",
|
|
24996
|
-
"static"
|
|
24997
|
-
|
|
24998
|
-
|
|
25471
|
+
"static"
|
|
25472
|
+
];
|
|
25473
|
+
for (const keyword of keywords) {
|
|
24999
25474
|
items.set(keyword, {
|
|
25000
25475
|
label: keyword,
|
|
25001
|
-
kind:
|
|
25476
|
+
kind: "keyword",
|
|
25002
25477
|
insertText: keyword
|
|
25003
25478
|
});
|
|
25004
25479
|
}
|
|
25005
|
-
for (const typeName of
|
|
25480
|
+
for (const typeName of [
|
|
25481
|
+
...NEOSCRIPT_PRIMITIVE_TYPES,
|
|
25482
|
+
...NEOSCRIPT_BUILTIN_TYPES
|
|
25483
|
+
]) {
|
|
25484
|
+
if (expression) continue;
|
|
25006
25485
|
items.set(typeName, {
|
|
25007
25486
|
label: typeName,
|
|
25008
25487
|
kind: "class",
|
|
@@ -25010,10 +25489,31 @@ function projectCompletions(analysis, document, position) {
|
|
|
25010
25489
|
insertText: typeName
|
|
25011
25490
|
});
|
|
25012
25491
|
}
|
|
25492
|
+
const source = analysis.documents.get(document.uri);
|
|
25493
|
+
const owner = source ? declarationContaining(source, position)?.name : void 0;
|
|
25013
25494
|
for (const symbol of analysis.symbols) {
|
|
25014
25495
|
if (symbol.scopeRange && (symbol.location.uri !== document.uri || !rangeContains(symbol.scopeRange, position))) {
|
|
25015
25496
|
continue;
|
|
25016
25497
|
}
|
|
25498
|
+
const isType = symbol.kind === "class" || symbol.kind === "interface" || symbol.kind === "enum" || symbol.kind === "genericParameter";
|
|
25499
|
+
if (typePosition && !isType) continue;
|
|
25500
|
+
if (expression) {
|
|
25501
|
+
if (afterNew) {
|
|
25502
|
+
if (!isType || symbol.kind !== "class" || expectedTypeName !== null && !projectTypeNameAssignable(analysis, symbol.name, expectedTypeName)) {
|
|
25503
|
+
continue;
|
|
25504
|
+
}
|
|
25505
|
+
} else {
|
|
25506
|
+
const isValue = symbol.kind === "parameter" || symbol.kind === "flowBinding" || symbol.kind === "graphChild" || symbol.kind === "global" || symbol.kind === "member" && symbol.ownerName === owner;
|
|
25507
|
+
if (!isValue) continue;
|
|
25508
|
+
if (expectedTypeName !== null && (symbol.detail === void 0 || !projectTypeNameAssignable(
|
|
25509
|
+
analysis,
|
|
25510
|
+
symbol.detail,
|
|
25511
|
+
expectedTypeName
|
|
25512
|
+
))) {
|
|
25513
|
+
continue;
|
|
25514
|
+
}
|
|
25515
|
+
}
|
|
25516
|
+
}
|
|
25017
25517
|
const kind = projectCompletionKind(symbol);
|
|
25018
25518
|
items.set(symbol.name, {
|
|
25019
25519
|
label: symbol.name,
|
|
@@ -25025,6 +25525,168 @@ function projectCompletions(analysis, document, position) {
|
|
|
25025
25525
|
}
|
|
25026
25526
|
return { isIncomplete: false, items: [...items.values()] };
|
|
25027
25527
|
}
|
|
25528
|
+
function projectInitializerExpectedTypeNameAt(document, position) {
|
|
25529
|
+
const prefix = documentPrefix(document.text, position);
|
|
25530
|
+
const line = prefix.slice(prefix.lastIndexOf("\n") + 1);
|
|
25531
|
+
return /^(?:\s*@\w+(?:\([^)]*\))?)*\s*(?:(?:public|protected|private|abstract|async|native|override|readonly|sealed|static|virtual)\s+)*([A-Za-z_][A-Za-z0-9_]*)(?:\s*<[^>]*>)?\s+[A-Za-z_][A-Za-z0-9_]*\s*=\s*[^;]*$/.exec(
|
|
25532
|
+
line
|
|
25533
|
+
)?.[1] ?? null;
|
|
25534
|
+
}
|
|
25535
|
+
function projectAfterNewAt(document, position) {
|
|
25536
|
+
const tokens = tokensBeforePosition(document.text, position);
|
|
25537
|
+
let cursor = tokens.length - 1;
|
|
25538
|
+
const current = tokens[cursor];
|
|
25539
|
+
const offset = new SourceText(document.text).offsetAt(position);
|
|
25540
|
+
if (current?.kind === "identifier" && current.text !== "new" && /[A-Za-z0-9_]$/.test(document.text.slice(0, offset))) {
|
|
25541
|
+
cursor--;
|
|
25542
|
+
}
|
|
25543
|
+
return tokens[cursor]?.text === "new";
|
|
25544
|
+
}
|
|
25545
|
+
function projectTypeNameAssignable(analysis, sourceName, targetName) {
|
|
25546
|
+
if (sourceName === targetName) return true;
|
|
25547
|
+
if (sourceName === "int" && (targetName === "float" || targetName === "decimal")) {
|
|
25548
|
+
return true;
|
|
25549
|
+
}
|
|
25550
|
+
const source = analysis.project.types.find(
|
|
25551
|
+
(type) => type.name === sourceName
|
|
25552
|
+
);
|
|
25553
|
+
const target = analysis.project.types.find(
|
|
25554
|
+
(type) => type.name === targetName
|
|
25555
|
+
);
|
|
25556
|
+
if (!source || !target) return false;
|
|
25557
|
+
const visited = /* @__PURE__ */ new Set();
|
|
25558
|
+
const derivesFrom = (typeId) => {
|
|
25559
|
+
if (typeId === target.id) return true;
|
|
25560
|
+
if (visited.has(typeId)) return false;
|
|
25561
|
+
visited.add(typeId);
|
|
25562
|
+
const type = analysis.project.types.find(
|
|
25563
|
+
(candidate) => candidate.id === typeId
|
|
25564
|
+
);
|
|
25565
|
+
return [
|
|
25566
|
+
...type?.baseTypeIds ?? [],
|
|
25567
|
+
...type?.interfaceTypeIds ?? []
|
|
25568
|
+
].some(derivesFrom);
|
|
25569
|
+
};
|
|
25570
|
+
return derivesFrom(source.id);
|
|
25571
|
+
}
|
|
25572
|
+
function projectBodySnapshotAt(analysis, document, position) {
|
|
25573
|
+
const body = analysis.bodyContexts.find(
|
|
25574
|
+
(candidate) => candidate.uri === document.uri && rangeContains(candidate.range, position)
|
|
25575
|
+
);
|
|
25576
|
+
return body ? projectBodySnapshot(analysis, document, body) : null;
|
|
25577
|
+
}
|
|
25578
|
+
function projectBodySnapshot(analysis, document, body) {
|
|
25579
|
+
let snapshots = PROJECT_BODY_SNAPSHOT_CACHE.get(analysis);
|
|
25580
|
+
if (!snapshots) {
|
|
25581
|
+
snapshots = /* @__PURE__ */ new Map();
|
|
25582
|
+
PROJECT_BODY_SNAPSHOT_CACHE.set(analysis, snapshots);
|
|
25583
|
+
}
|
|
25584
|
+
const cached = snapshots.get(body);
|
|
25585
|
+
if (cached) return cached;
|
|
25586
|
+
const source = new SourceText(document.text);
|
|
25587
|
+
const start = source.offsetAt(body.range.start);
|
|
25588
|
+
const end = source.offsetAt(body.range.end);
|
|
25589
|
+
const text = maskOutsideProjectBody(document.text, start, end);
|
|
25590
|
+
const syntax = analyzeNeoScriptSyntax(text, body.context.kind);
|
|
25591
|
+
const context = { ...body.context, project: analysis.project };
|
|
25592
|
+
const snapshot = {
|
|
25593
|
+
uri: document.uri,
|
|
25594
|
+
source: syntax.lexed.source,
|
|
25595
|
+
lexed: syntax.lexed,
|
|
25596
|
+
parsed: syntax.parsed,
|
|
25597
|
+
context,
|
|
25598
|
+
project: buildProjectIndexWithBuiltins(context)
|
|
25599
|
+
};
|
|
25600
|
+
snapshots.set(body, snapshot);
|
|
25601
|
+
return snapshot;
|
|
25602
|
+
}
|
|
25603
|
+
function maskOutsideProjectBody(text, start, end) {
|
|
25604
|
+
let masked = "";
|
|
25605
|
+
for (let index = 0; index < text.length; index++) {
|
|
25606
|
+
const character = text[index] ?? "";
|
|
25607
|
+
masked += index >= start && index < end || character === "\n" || character === "\r" ? character : " ";
|
|
25608
|
+
}
|
|
25609
|
+
return masked;
|
|
25610
|
+
}
|
|
25611
|
+
function projectWordRange(text, offset) {
|
|
25612
|
+
let start = offset;
|
|
25613
|
+
let end = offset;
|
|
25614
|
+
while (start > 0 && /[A-Za-z0-9_]/.test(text[start - 1] ?? "")) start--;
|
|
25615
|
+
while (end < text.length && /[A-Za-z0-9_]/.test(text[end] ?? "")) end++;
|
|
25616
|
+
return { start, end };
|
|
25617
|
+
}
|
|
25618
|
+
function isContextualDot(text, wordStart) {
|
|
25619
|
+
if (text[wordStart - 1] !== ".") return false;
|
|
25620
|
+
let cursor = wordStart - 2;
|
|
25621
|
+
while (cursor >= 0 && /\s/.test(text[cursor] ?? "")) cursor--;
|
|
25622
|
+
const beforeDot = text[cursor];
|
|
25623
|
+
if (beforeDot !== void 0 && /[A-Za-z0-9_]/.test(beforeDot)) {
|
|
25624
|
+
const precedingWord = /[A-Za-z_][A-Za-z0-9_]*$/.exec(
|
|
25625
|
+
text.slice(0, cursor + 1)
|
|
25626
|
+
)?.[0];
|
|
25627
|
+
return precedingWord === "return" || precedingWord === "case";
|
|
25628
|
+
}
|
|
25629
|
+
return beforeDot === void 0 || !/[A-Za-z0-9_\])}]/.test(beforeDot);
|
|
25630
|
+
}
|
|
25631
|
+
function projectTypePositionAt(analysis, document, position) {
|
|
25632
|
+
const source = analysis.documents.get(document.uri);
|
|
25633
|
+
if (source && sourceTypeAt(source, position)) return true;
|
|
25634
|
+
const prefix = documentPrefix(document.text, position);
|
|
25635
|
+
const line = prefix.slice(prefix.lastIndexOf("\n") + 1);
|
|
25636
|
+
return /(?:^|[{:;,])\s*(?:(?:public|protected|private|abstract|async|native|override|readonly|sealed|static|virtual)\s+)*[A-Za-z_][A-Za-z0-9_]*(?:\s*<[^;={}()]*)?$/.test(
|
|
25637
|
+
line
|
|
25638
|
+
);
|
|
25639
|
+
}
|
|
25640
|
+
function sourceTypeAt(document, position) {
|
|
25641
|
+
const contains2 = (type) => {
|
|
25642
|
+
for (const argument2 of type.typeArguments) {
|
|
25643
|
+
const nested = contains2(argument2);
|
|
25644
|
+
if (nested) return nested;
|
|
25645
|
+
}
|
|
25646
|
+
return rangeContains(type.range, position) ? type : null;
|
|
25647
|
+
};
|
|
25648
|
+
const parameterType = (parameters) => {
|
|
25649
|
+
for (const parameter4 of parameters ?? []) {
|
|
25650
|
+
const match = contains2(parameter4.type);
|
|
25651
|
+
if (match) return match;
|
|
25652
|
+
}
|
|
25653
|
+
return null;
|
|
25654
|
+
};
|
|
25655
|
+
for (const declaration of document.declarations) {
|
|
25656
|
+
if (declaration.kind === "global") {
|
|
25657
|
+
const match = contains2(declaration.type);
|
|
25658
|
+
if (match) return match;
|
|
25659
|
+
continue;
|
|
25660
|
+
}
|
|
25661
|
+
if (declaration.kind === "enum") continue;
|
|
25662
|
+
for (const base of declaration.baseTypes) {
|
|
25663
|
+
const match = contains2(base);
|
|
25664
|
+
if (match) return match;
|
|
25665
|
+
}
|
|
25666
|
+
if (declaration.kind === "class") {
|
|
25667
|
+
const header = parameterType(declaration.headerParameters);
|
|
25668
|
+
if (header) return header;
|
|
25669
|
+
for (const generic of declaration.genericParameters) {
|
|
25670
|
+
if (!generic.constraint) continue;
|
|
25671
|
+
const match = contains2(generic.constraint);
|
|
25672
|
+
if (match) return match;
|
|
25673
|
+
}
|
|
25674
|
+
for (const constructor2 of declaration.constructors) {
|
|
25675
|
+
const match = parameterType(constructor2.parameters);
|
|
25676
|
+
if (match) return match;
|
|
25677
|
+
}
|
|
25678
|
+
}
|
|
25679
|
+
for (const member of declaration.members) {
|
|
25680
|
+
const memberType2 = contains2(member.type);
|
|
25681
|
+
if (memberType2) return memberType2;
|
|
25682
|
+
if (member.kind === "function") {
|
|
25683
|
+
const match = parameterType(member.parameters);
|
|
25684
|
+
if (match) return match;
|
|
25685
|
+
}
|
|
25686
|
+
}
|
|
25687
|
+
}
|
|
25688
|
+
return null;
|
|
25689
|
+
}
|
|
25028
25690
|
function projectMemberCompletions(analysis, document, position) {
|
|
25029
25691
|
const tokens = projectTokens(document).filter(
|
|
25030
25692
|
(token) => token.kind !== "eof" && token.kind !== "comment" && positionCompare(token.range.start, position) <= 0
|
|
@@ -25262,6 +25924,8 @@ function activeNamedArgument(text, position) {
|
|
|
25262
25924
|
return /([A-Za-z_][A-Za-z0-9_]*)\s*:\s*\.[A-Za-z0-9_]*$/.exec(prefix)?.[1] ?? null;
|
|
25263
25925
|
}
|
|
25264
25926
|
function projectHover(analysis, document, position) {
|
|
25927
|
+
const body = projectBodySnapshotAt(analysis, document, position);
|
|
25928
|
+
if (body) return hover(body, position);
|
|
25265
25929
|
const resolved = projectSymbolAt(analysis, document, position);
|
|
25266
25930
|
if (!resolved) return null;
|
|
25267
25931
|
const owner = resolved.symbol.ownerName ? ` on \`${resolved.symbol.ownerName}\`` : "";
|
|
@@ -25309,6 +25973,8 @@ Construct with \`new(${parameters})\` \u2014 this class declares a required cons
|
|
|
25309
25973
|
${lines.join("\n\n")}`;
|
|
25310
25974
|
}
|
|
25311
25975
|
function projectDefinition(analysis, document, position) {
|
|
25976
|
+
const body = projectBodySnapshotAt(analysis, document, position);
|
|
25977
|
+
if (body) return definition(body, position);
|
|
25312
25978
|
const resolved = projectSymbolAt(analysis, document, position);
|
|
25313
25979
|
return resolved ? [resolved.symbol.location] : [];
|
|
25314
25980
|
}
|
|
@@ -25375,6 +26041,8 @@ function requiredDestinationEdit(document, initializer, destination) {
|
|
|
25375
26041
|
return open && close ? trailingBlockReturnEdit(document.text, open, close, destination) : null;
|
|
25376
26042
|
}
|
|
25377
26043
|
function projectSignatureHelp(analysis, document, position) {
|
|
26044
|
+
const body = projectBodySnapshotAt(analysis, document, position);
|
|
26045
|
+
if (body) return signatureHelp(body, position);
|
|
25378
26046
|
const tokens = tokensBeforePosition(document.text, position);
|
|
25379
26047
|
const openIndex = activeCallOpenIndex(tokens, position);
|
|
25380
26048
|
if (openIndex < 0) return null;
|
|
@@ -25436,6 +26104,9 @@ function projectSignatureHelp(analysis, document, position) {
|
|
|
25436
26104
|
};
|
|
25437
26105
|
}
|
|
25438
26106
|
function projectInlayHints(analysis, document, range2) {
|
|
26107
|
+
const bodyContexts = analysis.bodyContexts.filter(
|
|
26108
|
+
(body) => body.uri === document.uri
|
|
26109
|
+
);
|
|
25439
26110
|
const tokens = lex(document.text).tokens.filter(
|
|
25440
26111
|
(token) => token.kind !== "comment" && token.kind !== "eof"
|
|
25441
26112
|
);
|
|
@@ -25450,6 +26121,9 @@ function projectInlayHints(analysis, document, range2) {
|
|
|
25450
26121
|
if (!callee || callee.kind !== "identifier" && callee.kind !== "type") {
|
|
25451
26122
|
continue;
|
|
25452
26123
|
}
|
|
26124
|
+
if (bodyContexts.some((body) => rangeContains(body.range, callee.range.start))) {
|
|
26125
|
+
continue;
|
|
26126
|
+
}
|
|
25453
26127
|
if (!open || open.text !== "(") continue;
|
|
25454
26128
|
const beforeCallee = tokens[index - 1];
|
|
25455
26129
|
if (beforeCallee?.text === "@") continue;
|
|
@@ -25476,6 +26150,14 @@ function projectInlayHints(analysis, document, range2) {
|
|
|
25476
26150
|
});
|
|
25477
26151
|
}
|
|
25478
26152
|
}
|
|
26153
|
+
for (const body of bodyContexts) {
|
|
26154
|
+
const snapshot = projectBodySnapshot(analysis, document, body);
|
|
26155
|
+
hints.push(
|
|
26156
|
+
...inlayHints(snapshot, range2).filter(
|
|
26157
|
+
(hint) => rangeContains(body.range, hint.position)
|
|
26158
|
+
)
|
|
26159
|
+
);
|
|
26160
|
+
}
|
|
25479
26161
|
return hints;
|
|
25480
26162
|
}
|
|
25481
26163
|
function projectCallParameterNames(analysis, document, callee, beforeCallee) {
|
|
@@ -25677,8 +26359,14 @@ function symbolsDeclaredAt(index, uri, range2) {
|
|
|
25677
26359
|
function projectSemanticTokens(document, analysis) {
|
|
25678
26360
|
const index = buildProjectSymbolIndex(analysis.symbols);
|
|
25679
26361
|
const tokens = projectTokens(document);
|
|
25680
|
-
|
|
26362
|
+
const bodyContexts = analysis.bodyContexts.filter(
|
|
26363
|
+
(body) => body.uri === document.uri
|
|
26364
|
+
);
|
|
26365
|
+
const result = tokens.flatMap((token, tokenIndex) => {
|
|
25681
26366
|
if (token.kind === "eof" || token.kind === "error") return [];
|
|
26367
|
+
if (bodyContexts.some((body) => rangeContains(body.range, token.range.start))) {
|
|
26368
|
+
return [];
|
|
26369
|
+
}
|
|
25682
26370
|
const declaration = symbolsDeclaredAt(index, document.uri, token.range)[0];
|
|
25683
26371
|
const resolved = token.kind === "identifier" ? indexedProjectSymbolAt(analysis, document, token.range.start, index)?.symbol : void 0;
|
|
25684
26372
|
let type;
|
|
@@ -25705,6 +26393,17 @@ function projectSemanticTokens(document, analysis) {
|
|
|
25705
26393
|
}
|
|
25706
26394
|
];
|
|
25707
26395
|
});
|
|
26396
|
+
for (const body of bodyContexts) {
|
|
26397
|
+
const snapshot = projectBodySnapshot(analysis, document, body);
|
|
26398
|
+
result.push(
|
|
26399
|
+
...semanticTokens(snapshot).filter(
|
|
26400
|
+
(token) => rangeContains(body.range, token.range.start)
|
|
26401
|
+
)
|
|
26402
|
+
);
|
|
26403
|
+
}
|
|
26404
|
+
return result.sort(
|
|
26405
|
+
(left, right) => positionCompare(left.range.start, right.range.start)
|
|
26406
|
+
);
|
|
25708
26407
|
}
|
|
25709
26408
|
function isProjectContextualKeyword(tokens, tokenIndex) {
|
|
25710
26409
|
const token = tokens[tokenIndex];
|
|
@@ -25729,6 +26428,17 @@ function indexedProjectSymbolAt(analysis, document, position, index) {
|
|
|
25729
26428
|
if (exact.length === 1) return { token, symbol: exact[0] };
|
|
25730
26429
|
const candidates = index.byName.get(token.text) ?? [];
|
|
25731
26430
|
if (candidates.length === 0) return null;
|
|
26431
|
+
const sourceTokens = projectTokens(document);
|
|
26432
|
+
const tokenIndex = sourceTokens.findIndex(
|
|
26433
|
+
(candidate) => candidate.start === token.start && candidate.end === token.end
|
|
26434
|
+
);
|
|
26435
|
+
const source = analysis.documents.get(document.uri);
|
|
26436
|
+
if (source && sourceTypeAt(source, token.range.start) || sourceTokens[tokenIndex - 1]?.text === "new") {
|
|
26437
|
+
const types = candidates.filter(
|
|
26438
|
+
(symbol) => symbol.kind === "class" || symbol.kind === "interface" || symbol.kind === "enum" || symbol.kind === "genericParameter"
|
|
26439
|
+
);
|
|
26440
|
+
if (types.length === 1) return { token, symbol: types[0] };
|
|
26441
|
+
}
|
|
25732
26442
|
const scoped = candidates.filter(
|
|
25733
26443
|
(symbol) => symbol.scopeRange && symbol.location.uri === document.uri && rangeContains(symbol.scopeRange, token.range.start)
|
|
25734
26444
|
).sort(
|
|
@@ -25740,10 +26450,6 @@ function indexedProjectSymbolAt(analysis, document, position, index) {
|
|
|
25740
26450
|
return { token, symbol: visibleCandidates[0] };
|
|
25741
26451
|
}
|
|
25742
26452
|
if (visibleCandidates.length === 0) return null;
|
|
25743
|
-
const sourceTokens = projectTokens(document);
|
|
25744
|
-
const tokenIndex = sourceTokens.findIndex(
|
|
25745
|
-
(candidate) => candidate.start === token.start && candidate.end === token.end
|
|
25746
|
-
);
|
|
25747
26453
|
if (sourceTokens[tokenIndex + 1]?.text === "=" && sourceTokens[tokenIndex + 2]?.text !== "=") {
|
|
25748
26454
|
const constructed = constructionMemberSymbol(
|
|
25749
26455
|
analysis,
|
|
@@ -25753,7 +26459,6 @@ function indexedProjectSymbolAt(analysis, document, position, index) {
|
|
|
25753
26459
|
);
|
|
25754
26460
|
if (constructed) return { token, symbol: constructed };
|
|
25755
26461
|
}
|
|
25756
|
-
const source = analysis.documents.get(document.uri);
|
|
25757
26462
|
const owner = source ? declarationContaining(source, token.range.start)?.name : void 0;
|
|
25758
26463
|
if (owner) {
|
|
25759
26464
|
const owned = visibleCandidates.filter(
|
|
@@ -26272,10 +26977,11 @@ function projectFunctionsNamed(analysis, name) {
|
|
|
26272
26977
|
}
|
|
26273
26978
|
return result;
|
|
26274
26979
|
}
|
|
26275
|
-
var CONSTRUCTION_INDEX_CACHE;
|
|
26980
|
+
var PROJECT_BODY_SNAPSHOT_CACHE, CONSTRUCTION_INDEX_CACHE;
|
|
26276
26981
|
var init_project_source_language_features = __esm({
|
|
26277
26982
|
"../packages/neoscript-language/src/project-source-language-features.ts"() {
|
|
26278
26983
|
"use strict";
|
|
26984
|
+
init_analyzer();
|
|
26279
26985
|
init_lexer();
|
|
26280
26986
|
init_language_spec();
|
|
26281
26987
|
init_project_source_semantics();
|
|
@@ -26283,6 +26989,8 @@ var init_project_source_language_features = __esm({
|
|
|
26283
26989
|
init_project_source_tokens();
|
|
26284
26990
|
init_quick_fixes();
|
|
26285
26991
|
init_source_text();
|
|
26992
|
+
init_syntax();
|
|
26993
|
+
PROJECT_BODY_SNAPSHOT_CACHE = /* @__PURE__ */ new WeakMap();
|
|
26286
26994
|
CONSTRUCTION_INDEX_CACHE = /* @__PURE__ */ new WeakMap();
|
|
26287
26995
|
}
|
|
26288
26996
|
});
|
|
@@ -45984,9 +46692,9 @@ ${namedArguments(
|
|
|
45984
46692
|
`;
|
|
45985
46693
|
}
|
|
45986
46694
|
function namedArguments(entries, spaces, raw = /* @__PURE__ */ new Set()) {
|
|
45987
|
-
const
|
|
46695
|
+
const pad2 = " ".repeat(spaces);
|
|
45988
46696
|
return entries.map(
|
|
45989
|
-
([name, value]) => `${
|
|
46697
|
+
([name, value]) => `${pad2}${name}: ${raw.has(name) ? rawValue(value) : jsonValue2(value)},`
|
|
45990
46698
|
).join("\n");
|
|
45991
46699
|
}
|
|
45992
46700
|
function rawValue(value) {
|
|
@@ -50456,15 +51164,14 @@ function commentEndIndex(source, index) {
|
|
|
50456
51164
|
return null;
|
|
50457
51165
|
}
|
|
50458
51166
|
function stripInitializerComments(source) {
|
|
50459
|
-
const lines = [{
|
|
51167
|
+
const lines = [{ parts: [], removedComment: false }];
|
|
50460
51168
|
let quote6 = null;
|
|
50461
51169
|
let escaped = false;
|
|
50462
51170
|
let index = 0;
|
|
51171
|
+
let segmentStart = 0;
|
|
50463
51172
|
while (index < source.length) {
|
|
50464
51173
|
const character = source[index];
|
|
50465
|
-
const line = lines[lines.length - 1];
|
|
50466
51174
|
if (quote6 !== null) {
|
|
50467
|
-
line.text += character;
|
|
50468
51175
|
if (escaped) escaped = false;
|
|
50469
51176
|
else if (character === "\\") escaped = true;
|
|
50470
51177
|
else if (character === quote6) quote6 = null;
|
|
@@ -50473,20 +51180,34 @@ function stripInitializerComments(source) {
|
|
|
50473
51180
|
}
|
|
50474
51181
|
const afterComment = commentEndIndex(source, index);
|
|
50475
51182
|
if (afterComment !== null) {
|
|
51183
|
+
const line = lines[lines.length - 1];
|
|
51184
|
+
if (segmentStart < index) {
|
|
51185
|
+
line.parts.push(source.slice(segmentStart, index));
|
|
51186
|
+
}
|
|
50476
51187
|
line.removedComment = true;
|
|
50477
51188
|
index = afterComment;
|
|
51189
|
+
segmentStart = index;
|
|
50478
51190
|
continue;
|
|
50479
51191
|
}
|
|
50480
51192
|
if (character === "\n") {
|
|
50481
|
-
|
|
51193
|
+
if (segmentStart < index) {
|
|
51194
|
+
lines[lines.length - 1].parts.push(source.slice(segmentStart, index));
|
|
51195
|
+
}
|
|
51196
|
+
lines.push({ parts: [], removedComment: false });
|
|
50482
51197
|
index += 1;
|
|
51198
|
+
segmentStart = index;
|
|
50483
51199
|
continue;
|
|
50484
51200
|
}
|
|
50485
51201
|
if (character === '"' || character === "'") quote6 = character;
|
|
50486
|
-
line.text += character;
|
|
50487
51202
|
index += 1;
|
|
50488
51203
|
}
|
|
50489
|
-
|
|
51204
|
+
if (segmentStart < source.length) {
|
|
51205
|
+
lines[lines.length - 1].parts.push(source.slice(segmentStart));
|
|
51206
|
+
}
|
|
51207
|
+
return lines.map((line) => ({
|
|
51208
|
+
text: line.parts.join("").trimEnd(),
|
|
51209
|
+
removedComment: line.removedComment
|
|
51210
|
+
})).filter((line) => !line.removedComment || line.text.trim().length > 0).map((line) => line.text).join("\n").trim();
|
|
50490
51211
|
}
|
|
50491
51212
|
function normalizeBodySource(source) {
|
|
50492
51213
|
const trimmed = source.trim();
|
|
@@ -56658,6 +57379,19 @@ var init_NeoScriptScope = __esm({
|
|
|
56658
57379
|
setLocal(bindingId, value) {
|
|
56659
57380
|
this.#bindings.set(bindingId, value);
|
|
56660
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
|
+
}
|
|
57389
|
+
resetInvocationLocals(parameterCount) {
|
|
57390
|
+
if (this.#bindings.size > parameterCount) this.#bindings.clear();
|
|
57391
|
+
if (this.#readonlyBindingErrors.size > 0) {
|
|
57392
|
+
this.#readonlyBindingErrors.clear();
|
|
57393
|
+
}
|
|
57394
|
+
}
|
|
56661
57395
|
*keys() {
|
|
56662
57396
|
const inherited = /* @__PURE__ */ new Set();
|
|
56663
57397
|
if (this.parent !== null) {
|
|
@@ -61699,6 +62433,211 @@ function evalDeclaredListIndex(info, scope, ctx) {
|
|
|
61699
62433
|
}
|
|
61700
62434
|
return Array.isArray(hit) ? [...hit] : [];
|
|
61701
62435
|
}
|
|
62436
|
+
function prepareCollectionCallback(callback, parentScope, ctx, isList, returnContract, onPredicateMatch) {
|
|
62437
|
+
const metrics = ctx.__collectionCallbackPreparationMetrics;
|
|
62438
|
+
if (metrics !== void 0) metrics.bodyValidations += 1;
|
|
62439
|
+
const compilerRevision = callback.compilerRevision ?? 1;
|
|
62440
|
+
if (!Number.isSafeInteger(compilerRevision)) {
|
|
62441
|
+
throw new NSGetterRuntimeError(
|
|
62442
|
+
"Collection callback compiler revision must be a safe integer."
|
|
62443
|
+
);
|
|
62444
|
+
}
|
|
62445
|
+
if (compilerRevision < 1) {
|
|
62446
|
+
throw new NSGetterRuntimeError(
|
|
62447
|
+
"Collection callback compiler revision must be at least 1."
|
|
62448
|
+
);
|
|
62449
|
+
}
|
|
62450
|
+
if (compilerRevision > NEOSCRIPT_COMPILER_REVISION) {
|
|
62451
|
+
throw new NSGetterRuntimeError(
|
|
62452
|
+
`Collection callback compiler revision ${String(compilerRevision)} is newer than supported revision ${String(NEOSCRIPT_COMPILER_REVISION)}.`
|
|
62453
|
+
);
|
|
62454
|
+
}
|
|
62455
|
+
if (!isNSFunctionWithReturnType(callback)) {
|
|
62456
|
+
throw new NSGetterRuntimeError(
|
|
62457
|
+
`Collection callback body metadata is invalid for compiler revision ${String(compilerRevision)}.`
|
|
62458
|
+
);
|
|
62459
|
+
}
|
|
62460
|
+
const parameters = callback.parameters;
|
|
62461
|
+
if (parameters.length < 1) {
|
|
62462
|
+
throw new NSGetterRuntimeError(
|
|
62463
|
+
"Collection callback requires at least one parameter."
|
|
62464
|
+
);
|
|
62465
|
+
}
|
|
62466
|
+
if (parameters.length > 2) {
|
|
62467
|
+
throw new NSGetterRuntimeError(
|
|
62468
|
+
`Collection callback supports at most two parameters, but received ${String(parameters.length)}.`
|
|
62469
|
+
);
|
|
62470
|
+
}
|
|
62471
|
+
if (returnContract === "predicate") {
|
|
62472
|
+
if (callback.typeInfo.type !== 1 /* Bool */) {
|
|
62473
|
+
throw new NSGetterRuntimeError(
|
|
62474
|
+
"Collection predicate callback must declare a Bool return type."
|
|
62475
|
+
);
|
|
62476
|
+
}
|
|
62477
|
+
if (!callback.typeInfo.required) {
|
|
62478
|
+
throw new NSGetterRuntimeError(
|
|
62479
|
+
"Collection predicate callback must declare a required return type."
|
|
62480
|
+
);
|
|
62481
|
+
}
|
|
62482
|
+
}
|
|
62483
|
+
const parameterCount = parameters.length;
|
|
62484
|
+
const callbackScope = ctx.__collectionCallbackStrategy === "fresh" ? null : createChildScope(parentScope);
|
|
62485
|
+
const callbackOptions = evaluationOptions(ctx, false);
|
|
62486
|
+
const instructions = callback.instructions;
|
|
62487
|
+
const returnTypeInfo = callback.typeInfo;
|
|
62488
|
+
const requiresInvocationReset = callbackBodyMayAddInvocationLocals(
|
|
62489
|
+
instructions,
|
|
62490
|
+
new Set(parameters.map((parameter4) => parameter4.id))
|
|
62491
|
+
);
|
|
62492
|
+
let finishBody;
|
|
62493
|
+
if (returnContract === "predicate") {
|
|
62494
|
+
finishBody = (innerScope2) => {
|
|
62495
|
+
const result = evalInstructions(
|
|
62496
|
+
instructions,
|
|
62497
|
+
innerScope2,
|
|
62498
|
+
ctx,
|
|
62499
|
+
callbackOptions
|
|
62500
|
+
);
|
|
62501
|
+
rejectEscapedLoopTransfer(result, "collection callback");
|
|
62502
|
+
if (result.kind !== "return") {
|
|
62503
|
+
throw new NSGetterRuntimeError(
|
|
62504
|
+
"Collection callback ended without returning a value."
|
|
62505
|
+
);
|
|
62506
|
+
}
|
|
62507
|
+
const value = result.value;
|
|
62508
|
+
if (typeof value !== "boolean") {
|
|
62509
|
+
throw new NSGetterRuntimeError(
|
|
62510
|
+
"Collection predicate callback returned a value that does not match its required Bool contract."
|
|
62511
|
+
);
|
|
62512
|
+
}
|
|
62513
|
+
return value;
|
|
62514
|
+
};
|
|
62515
|
+
} else {
|
|
62516
|
+
finishBody = (innerScope2) => {
|
|
62517
|
+
const result = evalInstructions(
|
|
62518
|
+
instructions,
|
|
62519
|
+
innerScope2,
|
|
62520
|
+
ctx,
|
|
62521
|
+
callbackOptions
|
|
62522
|
+
);
|
|
62523
|
+
rejectEscapedLoopTransfer(result, "collection callback");
|
|
62524
|
+
if (result.kind !== "return") {
|
|
62525
|
+
throw new NSGetterRuntimeError(
|
|
62526
|
+
"Collection callback ended without returning a value."
|
|
62527
|
+
);
|
|
62528
|
+
}
|
|
62529
|
+
let value = result.value;
|
|
62530
|
+
if (returnTypeInfo.type === 20 /* Decimal */ && typeof value === "number") {
|
|
62531
|
+
value = coerceDecimalOperand(value, "collection callback return");
|
|
62532
|
+
}
|
|
62533
|
+
if (!runtimeValueMatchesType(value, returnTypeInfo, ctx)) {
|
|
62534
|
+
throw new NSGetterRuntimeError(
|
|
62535
|
+
"Collection projection callback returned a value that does not match its compiled return type."
|
|
62536
|
+
);
|
|
62537
|
+
}
|
|
62538
|
+
return value;
|
|
62539
|
+
};
|
|
62540
|
+
}
|
|
62541
|
+
if (metrics !== void 0) metrics.bindingPlanCreations += 1;
|
|
62542
|
+
if (ctx.__collectionCallbackStrategy === "fresh" || ctx.__collectionCallbackStrategy === "prepared") {
|
|
62543
|
+
return (entry, key, valueId) => {
|
|
62544
|
+
if (onPredicateMatch !== void 0) {
|
|
62545
|
+
consumeBudget(ctx, "workUnits", 1, "work unit");
|
|
62546
|
+
}
|
|
62547
|
+
const innerScope2 = callbackScope ?? createChildScope(parentScope);
|
|
62548
|
+
if (callbackScope !== null) {
|
|
62549
|
+
callbackScope.resetInvocationLocals(parameterCount);
|
|
62550
|
+
}
|
|
62551
|
+
if (parameters.length === 1) {
|
|
62552
|
+
innerScope2.setLocal(parameters[0].id, entry);
|
|
62553
|
+
} else if (parameters.length === 2) {
|
|
62554
|
+
innerScope2.setLocal(
|
|
62555
|
+
parameters[0].id,
|
|
62556
|
+
isList ? Number(key) : String(key)
|
|
62557
|
+
);
|
|
62558
|
+
innerScope2.setLocal(parameters[1].id, entry);
|
|
62559
|
+
}
|
|
62560
|
+
const value = finishBody(innerScope2);
|
|
62561
|
+
if (onPredicateMatch === void 0) return value;
|
|
62562
|
+
return value === true ? onPredicateMatch(entry, key, valueId) : 0 /* Continue */;
|
|
62563
|
+
};
|
|
62564
|
+
}
|
|
62565
|
+
const innerScope = callbackScope ?? createChildScope(parentScope);
|
|
62566
|
+
let bindValues;
|
|
62567
|
+
if (parameterCount === 1) {
|
|
62568
|
+
const entryParameterId = parameters[0].id;
|
|
62569
|
+
bindValues = (entry) => {
|
|
62570
|
+
innerScope.bindInvocationEntry(entryParameterId, entry);
|
|
62571
|
+
};
|
|
62572
|
+
} else {
|
|
62573
|
+
const keyParameterId = parameters[0].id;
|
|
62574
|
+
const entryParameterId = parameters[1].id;
|
|
62575
|
+
bindValues = (entry, key) => {
|
|
62576
|
+
innerScope.bindInvocationKeyAndEntry(
|
|
62577
|
+
keyParameterId,
|
|
62578
|
+
key,
|
|
62579
|
+
entryParameterId,
|
|
62580
|
+
entry
|
|
62581
|
+
);
|
|
62582
|
+
};
|
|
62583
|
+
}
|
|
62584
|
+
if (returnContract === "predicate") {
|
|
62585
|
+
if (onPredicateMatch === void 0) {
|
|
62586
|
+
throw new NSGetterRuntimeError(
|
|
62587
|
+
"Collection predicate preparation requires a match handler."
|
|
62588
|
+
);
|
|
62589
|
+
}
|
|
62590
|
+
if (requiresInvocationReset) {
|
|
62591
|
+
return (entry, key, valueId) => {
|
|
62592
|
+
consumeBudget(ctx, "workUnits", 1, "work unit");
|
|
62593
|
+
innerScope.resetInvocationLocals(parameterCount);
|
|
62594
|
+
bindValues(entry, key);
|
|
62595
|
+
return finishBody(innerScope) === true ? onPredicateMatch(entry, key, valueId) : 0 /* Continue */;
|
|
62596
|
+
};
|
|
62597
|
+
}
|
|
62598
|
+
return (entry, key, valueId) => {
|
|
62599
|
+
consumeBudget(ctx, "workUnits", 1, "work unit");
|
|
62600
|
+
bindValues(entry, key);
|
|
62601
|
+
return finishBody(innerScope) === true ? onPredicateMatch(entry, key, valueId) : 0 /* Continue */;
|
|
62602
|
+
};
|
|
62603
|
+
}
|
|
62604
|
+
if (requiresInvocationReset) {
|
|
62605
|
+
return (entry, key) => {
|
|
62606
|
+
innerScope.resetInvocationLocals(parameterCount);
|
|
62607
|
+
bindValues(entry, key);
|
|
62608
|
+
return finishBody(innerScope);
|
|
62609
|
+
};
|
|
62610
|
+
}
|
|
62611
|
+
return (entry, key) => {
|
|
62612
|
+
bindValues(entry, key);
|
|
62613
|
+
return finishBody(innerScope);
|
|
62614
|
+
};
|
|
62615
|
+
}
|
|
62616
|
+
function callbackBodyMayAddInvocationLocals(instructions, parameterIds) {
|
|
62617
|
+
return instructions.some((instruction) => {
|
|
62618
|
+
switch (instruction.type) {
|
|
62619
|
+
case "variable" /* variable */:
|
|
62620
|
+
return !parameterIds.has(instruction.variable.id);
|
|
62621
|
+
case "assign" /* assign */:
|
|
62622
|
+
return instruction.target.pointer.type === "variable" /* variable */ && !parameterIds.has(instruction.target.pointer.variableId);
|
|
62623
|
+
case "if" /* if */:
|
|
62624
|
+
case "for" /* for */:
|
|
62625
|
+
case "forEach" /* forEach */:
|
|
62626
|
+
case "switch" /* switch */:
|
|
62627
|
+
case "try" /* try */:
|
|
62628
|
+
return true;
|
|
62629
|
+
default:
|
|
62630
|
+
return false;
|
|
62631
|
+
}
|
|
62632
|
+
});
|
|
62633
|
+
}
|
|
62634
|
+
function isListCollection(collection) {
|
|
62635
|
+
if (Array.isArray(collection)) return true;
|
|
62636
|
+
if (typeof collection === "object" && collection !== null) return false;
|
|
62637
|
+
throw new NSGetterRuntimeError(
|
|
62638
|
+
"Collection callback receiver must be a present List or Dictionary value."
|
|
62639
|
+
);
|
|
62640
|
+
}
|
|
61702
62641
|
function evalFunction(fn, scope, ctx) {
|
|
61703
62642
|
switch (fn.type) {
|
|
61704
62643
|
case "classConstructor" /* classConstructor */:
|
|
@@ -61885,27 +62824,15 @@ function evalFunction(fn, scope, ctx) {
|
|
|
61885
62824
|
case "where" /* where */: {
|
|
61886
62825
|
const c = evalPointer(fn.info.collectionPointer, scope, ctx);
|
|
61887
62826
|
const innerFn = fn.info.function;
|
|
61888
|
-
const isList =
|
|
62827
|
+
const isList = isListCollection(c);
|
|
61889
62828
|
const out = isList ? [] : {};
|
|
61890
|
-
|
|
61891
|
-
|
|
61892
|
-
|
|
61893
|
-
|
|
61894
|
-
|
|
61895
|
-
|
|
61896
|
-
|
|
61897
|
-
// first param: index for list, key for dict
|
|
61898
|
-
entry
|
|
61899
|
-
],
|
|
61900
|
-
isList
|
|
61901
|
-
);
|
|
61902
|
-
const result = evalInstructions(
|
|
61903
|
-
innerFn.instructions,
|
|
61904
|
-
innerScope,
|
|
61905
|
-
ctx,
|
|
61906
|
-
evaluationOptions(ctx, false)
|
|
61907
|
-
);
|
|
61908
|
-
if (result.kind === "return" && result.value === true) {
|
|
62829
|
+
const callback = prepareCollectionCallback(
|
|
62830
|
+
innerFn,
|
|
62831
|
+
scope,
|
|
62832
|
+
ctx,
|
|
62833
|
+
isList,
|
|
62834
|
+
"predicate",
|
|
62835
|
+
(entry, key, valueId) => {
|
|
61909
62836
|
consumeBudget(
|
|
61910
62837
|
ctx,
|
|
61911
62838
|
"producedCollectionEntries",
|
|
@@ -61917,42 +62844,38 @@ function evalFunction(fn, scope, ctx) {
|
|
|
61917
62844
|
} else {
|
|
61918
62845
|
out[String(key)] = valueId ?? entry;
|
|
61919
62846
|
}
|
|
62847
|
+
return 0 /* Continue */;
|
|
61920
62848
|
}
|
|
61921
|
-
|
|
61922
|
-
|
|
62849
|
+
);
|
|
62850
|
+
iterateCollection(c, ctx, callback);
|
|
61923
62851
|
return out;
|
|
61924
62852
|
}
|
|
61925
62853
|
case "first" /* first */:
|
|
61926
62854
|
case "firstOrDefault" /* firstOrDefault */: {
|
|
61927
62855
|
const c = evalPointer(fn.info.collectionPointer, scope, ctx);
|
|
61928
62856
|
const innerFn = fn.info.function ?? null;
|
|
61929
|
-
const isList =
|
|
62857
|
+
const isList = isListCollection(c);
|
|
61930
62858
|
const sentinel = /* @__PURE__ */ Symbol("not-found");
|
|
61931
62859
|
let found = sentinel;
|
|
61932
|
-
|
|
61933
|
-
|
|
62860
|
+
if (innerFn === null) {
|
|
62861
|
+
iterateCollection(c, ctx, (entry) => {
|
|
61934
62862
|
found = entry;
|
|
61935
62863
|
return 1 /* Break */;
|
|
61936
|
-
}
|
|
61937
|
-
|
|
61938
|
-
const
|
|
62864
|
+
});
|
|
62865
|
+
} else {
|
|
62866
|
+
const callback = prepareCollectionCallback(
|
|
62867
|
+
innerFn,
|
|
61939
62868
|
scope,
|
|
61940
|
-
innerFn.parameters,
|
|
61941
|
-
[key, entry],
|
|
61942
|
-
isList
|
|
61943
|
-
);
|
|
61944
|
-
const result = evalInstructions(
|
|
61945
|
-
innerFn.instructions,
|
|
61946
|
-
innerScope,
|
|
61947
62869
|
ctx,
|
|
61948
|
-
|
|
62870
|
+
isList,
|
|
62871
|
+
"predicate",
|
|
62872
|
+
(entry) => {
|
|
62873
|
+
found = entry;
|
|
62874
|
+
return 1 /* Break */;
|
|
62875
|
+
}
|
|
61949
62876
|
);
|
|
61950
|
-
|
|
61951
|
-
|
|
61952
|
-
return 1 /* Break */;
|
|
61953
|
-
}
|
|
61954
|
-
return 0 /* Continue */;
|
|
61955
|
-
});
|
|
62877
|
+
iterateCollection(c, ctx, callback);
|
|
62878
|
+
}
|
|
61956
62879
|
if (found !== sentinel) return found;
|
|
61957
62880
|
if (fn.type === "first" /* first */) {
|
|
61958
62881
|
throw new NSGetterRuntimeError(
|
|
@@ -61964,31 +62887,25 @@ function evalFunction(fn, scope, ctx) {
|
|
|
61964
62887
|
case "select" /* select */: {
|
|
61965
62888
|
const c = evalPointer(fn.info.collectionPointer, scope, ctx);
|
|
61966
62889
|
const innerFn = fn.info.function;
|
|
61967
|
-
const isList =
|
|
62890
|
+
const isList = isListCollection(c);
|
|
62891
|
+
const callback = prepareCollectionCallback(
|
|
62892
|
+
innerFn,
|
|
62893
|
+
scope,
|
|
62894
|
+
ctx,
|
|
62895
|
+
isList,
|
|
62896
|
+
"projection"
|
|
62897
|
+
);
|
|
61968
62898
|
const out = [];
|
|
61969
|
-
iterateCollection(c, ctx, (entry, key) => {
|
|
62899
|
+
iterateCollection(c, ctx, (entry, key, valueId) => {
|
|
61970
62900
|
consumeBudget(ctx, "workUnits", 1, "work unit");
|
|
61971
|
-
const
|
|
61972
|
-
|
|
61973
|
-
innerFn.parameters,
|
|
61974
|
-
[key, entry],
|
|
61975
|
-
isList
|
|
61976
|
-
);
|
|
61977
|
-
const result = evalInstructions(
|
|
61978
|
-
innerFn.instructions,
|
|
61979
|
-
innerScope,
|
|
62901
|
+
const value = callback(entry, key, valueId);
|
|
62902
|
+
consumeBudget(
|
|
61980
62903
|
ctx,
|
|
61981
|
-
|
|
62904
|
+
"producedCollectionEntries",
|
|
62905
|
+
1,
|
|
62906
|
+
"produced collection entry"
|
|
61982
62907
|
);
|
|
61983
|
-
|
|
61984
|
-
consumeBudget(
|
|
61985
|
-
ctx,
|
|
61986
|
-
"producedCollectionEntries",
|
|
61987
|
-
1,
|
|
61988
|
-
"produced collection entry"
|
|
61989
|
-
);
|
|
61990
|
-
out.push(result.value);
|
|
61991
|
-
}
|
|
62908
|
+
out.push(value);
|
|
61992
62909
|
return 0 /* Continue */;
|
|
61993
62910
|
});
|
|
61994
62911
|
return out;
|
|
@@ -63324,7 +64241,7 @@ function encodeRequiredConstructorArgument(args) {
|
|
|
63324
64241
|
return adoptTracked(trackedId, "root");
|
|
63325
64242
|
}
|
|
63326
64243
|
if (args.typeInfo.type !== 6 /* List */ && args.typeInfo.type !== 5 /* Dictionary */) {
|
|
63327
|
-
return args.value;
|
|
64244
|
+
return cloneConstructorLiteralValue(args.value);
|
|
63328
64245
|
}
|
|
63329
64246
|
if (args.value === null || args.value === void 0) return null;
|
|
63330
64247
|
if (trackedId !== null) return adoptTracked(trackedId, "root");
|
|
@@ -63368,7 +64285,7 @@ function encodeRequiredConstructorArgument(args) {
|
|
|
63368
64285
|
}
|
|
63369
64286
|
return nested;
|
|
63370
64287
|
}
|
|
63371
|
-
return registerRow(value).id;
|
|
64288
|
+
return registerRow(cloneConstructorLiteralValue(value)).id;
|
|
63372
64289
|
};
|
|
63373
64290
|
if (collectionType.type === 6 /* List */) {
|
|
63374
64291
|
if (!Array.isArray(args.value)) {
|
|
@@ -63962,10 +64879,10 @@ function cloneConstructorArgumentGraph(args) {
|
|
|
63962
64879
|
return cloneRow(args.source, args.member, args.genericEnv);
|
|
63963
64880
|
}
|
|
63964
64881
|
function cloneConstructorLiteralValue(value) {
|
|
64882
|
+
if (typeof value !== "object" || value === null) return value;
|
|
63965
64883
|
if (Array.isArray(value)) {
|
|
63966
64884
|
return value.map((entry) => cloneConstructorLiteralValue(entry));
|
|
63967
64885
|
}
|
|
63968
|
-
if (typeof value !== "object" || value === null) return value;
|
|
63969
64886
|
return Object.fromEntries(
|
|
63970
64887
|
Object.entries(value).map(([key, entry]) => [
|
|
63971
64888
|
key,
|
|
@@ -64541,17 +65458,6 @@ function iterateCollection(c, ctx, callback) {
|
|
|
64541
65458
|
return callback(entry, key, valueId);
|
|
64542
65459
|
});
|
|
64543
65460
|
}
|
|
64544
|
-
function pushParams(parent, parameters, positional, isList) {
|
|
64545
|
-
const child = createChildScope(parent);
|
|
64546
|
-
if (parameters.length === 1) {
|
|
64547
|
-
child.setLocal(parameters[0].id, positional[1]);
|
|
64548
|
-
} else if (parameters.length === 2) {
|
|
64549
|
-
const first = isList ? Number(positional[0]) : String(positional[0]);
|
|
64550
|
-
child.setLocal(parameters[0].id, first);
|
|
64551
|
-
child.setLocal(parameters[1].id, positional[1]);
|
|
64552
|
-
}
|
|
64553
|
-
return child;
|
|
64554
|
-
}
|
|
64555
65461
|
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;
|
|
64556
65462
|
var init_evaluateNSGetter = __esm({
|
|
64557
65463
|
"../src/view-models/neoscript-evaluator/evaluateNSGetter.ts"() {
|
|
@@ -64565,6 +65471,7 @@ var init_evaluateNSGetter = __esm({
|
|
|
64565
65471
|
init_neoscript();
|
|
64566
65472
|
init_NSGetterRuntimeError();
|
|
64567
65473
|
init_value_row_owner_members();
|
|
65474
|
+
init_src();
|
|
64568
65475
|
init_decimal();
|
|
64569
65476
|
init_members();
|
|
64570
65477
|
init_core();
|
|
@@ -66503,6 +67410,7 @@ var init_project_document_read = __esm({
|
|
|
66503
67410
|
});
|
|
66504
67411
|
|
|
66505
67412
|
// src/workspace.ts
|
|
67413
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
66506
67414
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2 } from "node:fs";
|
|
66507
67415
|
import { dirname, join as join2, resolve } from "node:path";
|
|
66508
67416
|
function recordStateKey(recordKind, recordId) {
|
|
@@ -66735,9 +67643,12 @@ function matchUnityScalarField(content, field) {
|
|
|
66735
67643
|
function readWorkspaceState(root, options = {}) {
|
|
66736
67644
|
const statePath = join2(root, NEO_STATE_DIR, NEO_STATE_FILE);
|
|
66737
67645
|
if (!existsSync2(statePath)) {
|
|
67646
|
+
options.onSourceRead?.(null);
|
|
66738
67647
|
return { records: {} };
|
|
66739
67648
|
}
|
|
66740
|
-
const
|
|
67649
|
+
const source = readFileSync2(statePath, "utf8");
|
|
67650
|
+
options.onSourceRead?.(source);
|
|
67651
|
+
const parsed = JSON.parse(source);
|
|
66741
67652
|
if (typeof parsed !== "object" || parsed === null) {
|
|
66742
67653
|
throw new Error(`"${statePath}" must contain a JSON object.`);
|
|
66743
67654
|
}
|
|
@@ -66780,10 +67691,20 @@ function loadWorkspace(startDir, options = {}) {
|
|
|
66780
67691
|
`No "${NEO_CONFIG_FILE}" found in "${startDir}" or any parent directory. Run "neo init" first.`
|
|
66781
67692
|
);
|
|
66782
67693
|
}
|
|
67694
|
+
let stateSourceSha256;
|
|
67695
|
+
const state = readWorkspaceState(root, {
|
|
67696
|
+
discardLegacyFormat2State: options.discardLegacyFormat2State,
|
|
67697
|
+
...options.fingerprintStateSource === true ? {
|
|
67698
|
+
onSourceRead: (source) => {
|
|
67699
|
+
stateSourceSha256 = createHash2("sha256").update(source ?? "<missing>").digest("hex");
|
|
67700
|
+
}
|
|
67701
|
+
} : {}
|
|
67702
|
+
});
|
|
66783
67703
|
return {
|
|
66784
67704
|
root,
|
|
66785
67705
|
config: readWorkspaceConfig(root),
|
|
66786
|
-
state
|
|
67706
|
+
state,
|
|
67707
|
+
...stateSourceSha256 === void 0 ? {} : { stateSourceSha256 }
|
|
66787
67708
|
};
|
|
66788
67709
|
}
|
|
66789
67710
|
var NEO_CONFIG_FILE, NEO_STATE_DIR, NEO_STATE_FILE, CURRENT_FORMAT_VERSION;
|
|
@@ -72142,7 +73063,7 @@ var init_animation_clips = __esm({
|
|
|
72142
73063
|
|
|
72143
73064
|
// src/project-source/materialized-construction-cache.ts
|
|
72144
73065
|
import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
72145
|
-
import { createHash as
|
|
73066
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
72146
73067
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
72147
73068
|
function createMaterializedConstructionExpressionsV1(args) {
|
|
72148
73069
|
const warm = args.useBuildCaches ? readMaterializedConstructionBuildCacheV1(args.root, args.state) : null;
|
|
@@ -72234,7 +73155,7 @@ function writeMaterializedConstructionBuildCacheV1(root, state, expressions) {
|
|
|
72234
73155
|
renameSync(temporary, file);
|
|
72235
73156
|
}
|
|
72236
73157
|
function materializedConstructionStateFingerprint(state) {
|
|
72237
|
-
const hash =
|
|
73158
|
+
const hash = createHash3("sha256");
|
|
72238
73159
|
hash.update(String(MATERIALIZED_CONSTRUCTION_BUILD_CACHE_REVISION));
|
|
72239
73160
|
for (const [key, record3] of Object.entries(state.records).sort(
|
|
72240
73161
|
([left], [right]) => left.localeCompare(right)
|
|
@@ -73060,10 +73981,10 @@ var init_neo_script_recompile_scope = __esm({
|
|
|
73060
73981
|
});
|
|
73061
73982
|
|
|
73062
73983
|
// ../src/database/project-content-hash.ts
|
|
73063
|
-
import { createHash as
|
|
73984
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
73064
73985
|
function hashCanonicalJson(value) {
|
|
73065
73986
|
const canonicalJson = canonicalJsonStringify(value);
|
|
73066
|
-
return
|
|
73987
|
+
return createHash4("sha256").update(canonicalJson).digest("hex");
|
|
73067
73988
|
}
|
|
73068
73989
|
var init_project_content_hash = __esm({
|
|
73069
73990
|
"../src/database/project-content-hash.ts"() {
|
|
@@ -73130,7 +74051,7 @@ var init_project_fingerprint = __esm({
|
|
|
73130
74051
|
|
|
73131
74052
|
// src/project-source/neoscript-build-cache.ts
|
|
73132
74053
|
import { mkdirSync as mkdirSync4, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
73133
|
-
import { createHash as
|
|
74054
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
73134
74055
|
import { dirname as dirname3, join as join4 } from "node:path";
|
|
73135
74056
|
function loadOrBuildNeoScriptProjectV1(root, document) {
|
|
73136
74057
|
const fingerprint = neoScriptProjectFingerprint(document);
|
|
@@ -73157,7 +74078,7 @@ function loadOrBuildNeoScriptProjectV1(root, document) {
|
|
|
73157
74078
|
return project;
|
|
73158
74079
|
}
|
|
73159
74080
|
function neoScriptProjectFingerprint(document) {
|
|
73160
|
-
return
|
|
74081
|
+
return createHash5("sha256").update(
|
|
73161
74082
|
canonicalJsonStringify(neoScriptCompilationProjectContract(document))
|
|
73162
74083
|
).digest("hex");
|
|
73163
74084
|
}
|
|
@@ -92280,7 +93201,7 @@ var init_project_documents = __esm({
|
|
|
92280
93201
|
|
|
92281
93202
|
// src/project-source/project-document-cache.ts
|
|
92282
93203
|
import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, renameSync as renameSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
92283
|
-
import { createHash as
|
|
93204
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
92284
93205
|
import { dirname as dirname4, join as join5 } from "node:path";
|
|
92285
93206
|
function readProjectSourceAnalysisBuildCacheV4(root, sources) {
|
|
92286
93207
|
try {
|
|
@@ -92404,7 +93325,7 @@ function writeProjectSourceDocumentBuildCacheV1(root, sources, documents) {
|
|
|
92404
93325
|
renameSync3(temporary, file);
|
|
92405
93326
|
}
|
|
92406
93327
|
function projectSourceFileFingerprint(source) {
|
|
92407
|
-
return
|
|
93328
|
+
return createHash6("sha256").update(String(PROJECT_SOURCE_DOCUMENT_BUILD_CACHE_REVISION)).update("\0").update(String(NEOSCRIPT_COMPILER_REVISION)).update("\0").update(source.kind).update("\0").update(source.text).digest("hex");
|
|
92408
93329
|
}
|
|
92409
93330
|
function isCachedProjectSourceDocument(value, source) {
|
|
92410
93331
|
if (value === null || typeof value !== "object") return false;
|
|
@@ -92412,7 +93333,7 @@ function isCachedProjectSourceDocument(value, source) {
|
|
|
92412
93333
|
return document.kind === source.kind && document.sourceText === source.text && Array.isArray(document.declarations) && Array.isArray(document.diagnostics);
|
|
92413
93334
|
}
|
|
92414
93335
|
function projectSourceFingerprint(sources) {
|
|
92415
|
-
const hash =
|
|
93336
|
+
const hash = createHash6("sha256");
|
|
92416
93337
|
hash.update(String(PROJECT_SOURCE_BUILD_CACHE_REVISION));
|
|
92417
93338
|
hash.update("\0");
|
|
92418
93339
|
hash.update(String(NEOSCRIPT_COMPILER_REVISION));
|
|
@@ -92440,7 +93361,7 @@ var init_project_document_cache = __esm({
|
|
|
92440
93361
|
});
|
|
92441
93362
|
|
|
92442
93363
|
// src/project-source/project-files.ts
|
|
92443
|
-
import { createHash as
|
|
93364
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
92444
93365
|
import {
|
|
92445
93366
|
existsSync as existsSync3,
|
|
92446
93367
|
mkdirSync as mkdirSync6,
|
|
@@ -92687,7 +93608,7 @@ function discoverProjectBinariesV4(root, explicit, ignoredPaths = []) {
|
|
|
92687
93608
|
}).sort((left, right) => compareCodePoints(left.path, right.path));
|
|
92688
93609
|
}
|
|
92689
93610
|
function sha256Bytes(bytes) {
|
|
92690
|
-
return
|
|
93611
|
+
return createHash7("sha256").update(bytes).digest("hex");
|
|
92691
93612
|
}
|
|
92692
93613
|
function sha256File(path) {
|
|
92693
93614
|
return sha256Bytes(readFileSync6(path));
|
|
@@ -98140,7 +99061,7 @@ var init_script = __esm({
|
|
|
98140
99061
|
});
|
|
98141
99062
|
|
|
98142
99063
|
// ../src/database/project-source-identity.ts
|
|
98143
|
-
import { createHash as
|
|
99064
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
98144
99065
|
function hashProjectSourceFiles(inputFiles) {
|
|
98145
99066
|
const files = normalizeSourceFiles(inputFiles);
|
|
98146
99067
|
const bytes = Buffer.from(JSON.stringify({ version: 1, files }), "utf8");
|
|
@@ -98149,7 +99070,7 @@ function hashProjectSourceFiles(inputFiles) {
|
|
|
98149
99070
|
`Project source identity is ${bytes.byteLength} bytes; the limit is ${MAX_SOURCE_BYTES} bytes.`
|
|
98150
99071
|
);
|
|
98151
99072
|
}
|
|
98152
|
-
return
|
|
99073
|
+
return createHash8("sha256").update(bytes).digest("hex");
|
|
98153
99074
|
}
|
|
98154
99075
|
function normalizeSourceFiles(inputFiles) {
|
|
98155
99076
|
if (inputFiles.length > MAX_SOURCE_FILES) {
|
|
@@ -98241,14 +99162,14 @@ var init_project_source_identity = __esm({
|
|
|
98241
99162
|
|
|
98242
99163
|
// src/push-hook.ts
|
|
98243
99164
|
import { spawn } from "node:child_process";
|
|
98244
|
-
import { createHash as
|
|
99165
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
98245
99166
|
import { existsSync as existsSync10, readFileSync as readFileSync13, readdirSync as readdirSync4 } from "node:fs";
|
|
98246
99167
|
import { join as join13, relative as relative3, sep as sep3 } from "node:path";
|
|
98247
|
-
function fingerprintPushInputs(workspace) {
|
|
99168
|
+
function fingerprintPushInputs(workspace, options = {}) {
|
|
98248
99169
|
const paths = /* @__PURE__ */ new Set([
|
|
98249
99170
|
join13(workspace.root, "neo.json"),
|
|
98250
99171
|
...listProjectSourceFilesV4(workspace.root),
|
|
98251
|
-
...listProjectTestFilesV1(workspace.root),
|
|
99172
|
+
...options.includeTests === false ? [] : listProjectTestFilesV1(workspace.root),
|
|
98252
99173
|
...workspace.config.unityConfigPath === void 0 ? [] : [join13(workspace.root, workspace.config.unityConfigPath)]
|
|
98253
99174
|
]);
|
|
98254
99175
|
const visitManaged = (directory) => {
|
|
@@ -98262,7 +99183,7 @@ function fingerprintPushInputs(workspace) {
|
|
|
98262
99183
|
};
|
|
98263
99184
|
visitManaged(join13(workspace.root, "Files", "Images"));
|
|
98264
99185
|
visitManaged(join13(workspace.root, "Files", "AudioClips"));
|
|
98265
|
-
const hash =
|
|
99186
|
+
const hash = createHash9("sha256");
|
|
98266
99187
|
for (const path of [...paths].sort()) {
|
|
98267
99188
|
const name = relative3(workspace.root, path).split(sep3).join("/");
|
|
98268
99189
|
hash.update(name);
|
|
@@ -98919,7 +99840,7 @@ __export(push_exports, {
|
|
|
98919
99840
|
runPush: () => runPush,
|
|
98920
99841
|
stripServerDerivedNeoScript: () => stripServerDerivedNeoScript
|
|
98921
99842
|
});
|
|
98922
|
-
import { createHash as
|
|
99843
|
+
import { createHash as createHash10, randomUUID as randomUUID2 } from "node:crypto";
|
|
98923
99844
|
import {
|
|
98924
99845
|
mkdirSync as mkdirSync10,
|
|
98925
99846
|
writeFileSync as writeFileSync10,
|
|
@@ -99702,7 +100623,7 @@ async function runPush(workspace, options, preparationOverride) {
|
|
|
99702
100623
|
version: 1,
|
|
99703
100624
|
projectFingerprint: `sha256:${preparedLocal.source.sourceHash}`,
|
|
99704
100625
|
inputFingerprint: preparedInputFingerprint,
|
|
99705
|
-
documentSha256:
|
|
100626
|
+
documentSha256: createHash10("sha256").update(documentJson).digest("hex"),
|
|
99706
100627
|
document: candidate.document
|
|
99707
100628
|
})}
|
|
99708
100629
|
`,
|
|
@@ -101711,7 +102632,7 @@ var init_registry2 = __esm({
|
|
|
101711
102632
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
101712
102633
|
formatVersion: 3,
|
|
101713
102634
|
contractVersion: "3.9",
|
|
101714
|
-
cliVersion: "0.26.
|
|
102635
|
+
cliVersion: "0.26.3",
|
|
101715
102636
|
projectFileUploadBatchSize: 32,
|
|
101716
102637
|
documentRecords: {
|
|
101717
102638
|
member: {
|
|
@@ -103004,7 +103925,7 @@ __export(test_exports, {
|
|
|
103004
103925
|
maintainNeoTestBuildCache: () => maintainNeoTestBuildCache,
|
|
103005
103926
|
runTest: () => runTest
|
|
103006
103927
|
});
|
|
103007
|
-
import { createHash as
|
|
103928
|
+
import { createHash as createHash11, randomUUID as randomUUID3 } from "node:crypto";
|
|
103008
103929
|
import {
|
|
103009
103930
|
existsSync as existsSync12,
|
|
103010
103931
|
mkdirSync as mkdirSync11,
|
|
@@ -103025,6 +103946,7 @@ import {
|
|
|
103025
103946
|
resolve as resolve3,
|
|
103026
103947
|
sep as sep5
|
|
103027
103948
|
} from "node:path";
|
|
103949
|
+
import { isDeepStrictEqual } from "node:util";
|
|
103028
103950
|
function isRecord10(value) {
|
|
103029
103951
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
103030
103952
|
}
|
|
@@ -103108,9 +104030,46 @@ function stableTestValue(value) {
|
|
|
103108
104030
|
function display(value) {
|
|
103109
104031
|
return stableTestValue(value);
|
|
103110
104032
|
}
|
|
103111
|
-
function
|
|
103112
|
-
|
|
103113
|
-
|
|
104033
|
+
function matcherFailureMessage(kind, expectationValue, expected, received, details) {
|
|
104034
|
+
const actual = expectationValue.actual;
|
|
104035
|
+
const negation = expectationValue.negated ? "not " : "";
|
|
104036
|
+
switch (kind) {
|
|
104037
|
+
case "toBe":
|
|
104038
|
+
return `Expected ${display(actual)} ${negation}to be ${display(expected)}.`;
|
|
104039
|
+
case "toEqual":
|
|
104040
|
+
return `Expected ${display(actual)} ${negation}to equal ${display(expected)}.`;
|
|
104041
|
+
case "toBeNull":
|
|
104042
|
+
return `Expected ${display(actual)} ${negation}to be null.`;
|
|
104043
|
+
case "boolean":
|
|
104044
|
+
return `Expected ${display(actual)} ${negation}to be ${String(expected)}.`;
|
|
104045
|
+
case "numeric":
|
|
104046
|
+
return `Expected ${display(actual)} ${negation}to satisfy numeric comparison with ${display(expected)}.`;
|
|
104047
|
+
case "toContain":
|
|
104048
|
+
return `Expected ${display(actual)} ${negation}to contain ${display(expected)}.`;
|
|
104049
|
+
case "toHaveLength":
|
|
104050
|
+
return `Expected length ${String(expected)}, received ${String(received)}.`;
|
|
104051
|
+
case "toMatchObject":
|
|
104052
|
+
return `Expected ${display(actual)} ${negation}to match ${display(expected)}.`;
|
|
104053
|
+
case "toThrow":
|
|
104054
|
+
return `Expected callback ${negation}to throw${details === void 0 ? "" : ` a message containing ${display(details)}`}.`;
|
|
104055
|
+
case "mock":
|
|
104056
|
+
return `Expected mock ${negation}to match recorded calls ${display(details)}.`;
|
|
104057
|
+
}
|
|
104058
|
+
}
|
|
104059
|
+
function assertMatcher(condition, expectationValue, messageKind, expected, received = expectationValue.actual, details) {
|
|
104060
|
+
if (condition === expectationValue.negated) {
|
|
104061
|
+
throw new NeoTestAssertionError(
|
|
104062
|
+
matcherFailureMessage(
|
|
104063
|
+
messageKind,
|
|
104064
|
+
expectationValue,
|
|
104065
|
+
expected,
|
|
104066
|
+
received,
|
|
104067
|
+
details
|
|
104068
|
+
),
|
|
104069
|
+
expected,
|
|
104070
|
+
received
|
|
104071
|
+
);
|
|
104072
|
+
}
|
|
103114
104073
|
}
|
|
103115
104074
|
function errorMessage2(error) {
|
|
103116
104075
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -103118,10 +104077,11 @@ function errorMessage2(error) {
|
|
|
103118
104077
|
function findDelegateTargetMemberId(value) {
|
|
103119
104078
|
return isRecord10(value) && typeof value.memberId === "string" ? value.memberId : null;
|
|
103120
104079
|
}
|
|
103121
|
-
function
|
|
103122
|
-
const
|
|
103123
|
-
|
|
103124
|
-
const
|
|
104080
|
+
function sharedEvaluatorBase(rawDocument) {
|
|
104081
|
+
const cached = SHARED_EVALUATOR_BASES.get(rawDocument);
|
|
104082
|
+
if (cached !== void 0) return cached;
|
|
104083
|
+
const document = readDocumentArrays(rawDocument);
|
|
104084
|
+
const constructors = Array.isArray(rawDocument.constructors) ? rawDocument.constructors.filter(isRecord10) : [];
|
|
103125
104085
|
const vm = {
|
|
103126
104086
|
project: document.project,
|
|
103127
104087
|
members: document.members,
|
|
@@ -103146,10 +104106,19 @@ function makeEvaluatorContext(rawDocument, interceptor, documentAlreadyIsolated
|
|
|
103146
104106
|
}
|
|
103147
104107
|
)
|
|
103148
104108
|
};
|
|
103149
|
-
|
|
104109
|
+
const created = {
|
|
103150
104110
|
vm,
|
|
104111
|
+
rootValue: buildRootValue(document)
|
|
104112
|
+
};
|
|
104113
|
+
SHARED_EVALUATOR_BASES.set(rawDocument, created);
|
|
104114
|
+
return created;
|
|
104115
|
+
}
|
|
104116
|
+
function makeEvaluatorContext(rawDocument, interceptor) {
|
|
104117
|
+
const base = sharedEvaluatorBase(rawDocument);
|
|
104118
|
+
return createNeoScriptEvaluationRuntime({
|
|
104119
|
+
vm: base.vm,
|
|
103151
104120
|
thisValue: null,
|
|
103152
|
-
rootValue:
|
|
104121
|
+
rootValue: base.rootValue,
|
|
103153
104122
|
dialogueContext: null,
|
|
103154
104123
|
callInterceptor: interceptor,
|
|
103155
104124
|
nativeFunctionErrorCheckBehavior: "strict"
|
|
@@ -103216,14 +104185,15 @@ function preparedHookCandidate(workspace) {
|
|
|
103216
104185
|
);
|
|
103217
104186
|
}
|
|
103218
104187
|
const documentJson = JSON.stringify(parsed.document);
|
|
103219
|
-
if (
|
|
104188
|
+
if (createHash11("sha256").update(documentJson).digest("hex") !== parsed.documentSha256) {
|
|
103220
104189
|
throw new NeoTestPreparedCandidateError(
|
|
103221
104190
|
"Configured push hook candidate project document failed checksum verification."
|
|
103222
104191
|
);
|
|
103223
104192
|
}
|
|
103224
104193
|
return {
|
|
103225
104194
|
document: parsed.document,
|
|
103226
|
-
sourceHash: configuredFingerprint.replace(/^sha256:/u, "")
|
|
104195
|
+
sourceHash: configuredFingerprint.replace(/^sha256:/u, ""),
|
|
104196
|
+
documentSha256: parsed.documentSha256
|
|
103227
104197
|
};
|
|
103228
104198
|
} catch (error) {
|
|
103229
104199
|
if (error instanceof NeoTestPreparedCandidateError) throw error;
|
|
@@ -103232,11 +104202,79 @@ function preparedHookCandidate(workspace) {
|
|
|
103232
104202
|
);
|
|
103233
104203
|
}
|
|
103234
104204
|
}
|
|
104205
|
+
function fingerprintTestCandidateInputs(workspace) {
|
|
104206
|
+
return createHash11("sha256").update("neo-test-candidate\0").update(String(TEST_CANDIDATE_CACHE_REVISION)).update("\0").update(PROJECT_SCHEMA_CONTRACT.cliVersion).update("\0").update(String(NEOSCRIPT_COMPILER_REVISION)).update("\0").update(fingerprintPushInputs(workspace, { includeTests: false })).update("\0").update(
|
|
104207
|
+
workspace.stateSourceSha256 === void 0 ? `object\0${JSON.stringify(workspace.state)}` : `source\0${workspace.stateSourceSha256}`
|
|
104208
|
+
).digest("hex");
|
|
104209
|
+
}
|
|
104210
|
+
function testCandidateCachePath(workspace, inputFingerprint) {
|
|
104211
|
+
const cacheKey = createHash11("sha256").update(inputFingerprint).digest("hex");
|
|
104212
|
+
return join16(
|
|
104213
|
+
workspace.root,
|
|
104214
|
+
".neo",
|
|
104215
|
+
"test-build",
|
|
104216
|
+
"v1",
|
|
104217
|
+
"project",
|
|
104218
|
+
cacheKey,
|
|
104219
|
+
"candidate.json"
|
|
104220
|
+
);
|
|
104221
|
+
}
|
|
104222
|
+
function cachedTestCandidate(workspace, inputFingerprint) {
|
|
104223
|
+
try {
|
|
104224
|
+
const candidatePath = testCandidateCachePath(workspace, inputFingerprint);
|
|
104225
|
+
const parsed = JSON.parse(readFileSync16(candidatePath, "utf8"));
|
|
104226
|
+
if (!isRecord10(parsed)) return null;
|
|
104227
|
+
if (parsed.version !== 1) return null;
|
|
104228
|
+
if (parsed.candidateRevision !== TEST_CANDIDATE_CACHE_REVISION) return null;
|
|
104229
|
+
if (parsed.cliVersion !== PROJECT_SCHEMA_CONTRACT.cliVersion) return null;
|
|
104230
|
+
if (parsed.compilerRevision !== NEOSCRIPT_COMPILER_REVISION) return null;
|
|
104231
|
+
if (parsed.inputFingerprint !== inputFingerprint) return null;
|
|
104232
|
+
if (typeof parsed.sourceHash !== "string" || parsed.sourceHash.length === 0) {
|
|
104233
|
+
return null;
|
|
104234
|
+
}
|
|
104235
|
+
if (typeof parsed.documentSha256 !== "string") return null;
|
|
104236
|
+
const documentJson = readFileSync16(
|
|
104237
|
+
join16(dirname9(candidatePath), "document.json"),
|
|
104238
|
+
"utf8"
|
|
104239
|
+
);
|
|
104240
|
+
if (createHash11("sha256").update(documentJson).digest("hex") !== parsed.documentSha256) {
|
|
104241
|
+
return null;
|
|
104242
|
+
}
|
|
104243
|
+
const document = JSON.parse(documentJson);
|
|
104244
|
+
if (!isRecord10(document)) return null;
|
|
104245
|
+
return {
|
|
104246
|
+
document,
|
|
104247
|
+
sourceHash: parsed.sourceHash,
|
|
104248
|
+
documentSha256: parsed.documentSha256
|
|
104249
|
+
};
|
|
104250
|
+
} catch {
|
|
104251
|
+
return null;
|
|
104252
|
+
}
|
|
104253
|
+
}
|
|
104254
|
+
function cacheTestCandidate(workspace, inputFingerprint, candidate) {
|
|
104255
|
+
const documentJson = JSON.stringify(candidate.document);
|
|
104256
|
+
const documentSha256 = createHash11("sha256").update(documentJson).digest("hex");
|
|
104257
|
+
const candidatePath = testCandidateCachePath(workspace, inputFingerprint);
|
|
104258
|
+
atomicWrite(join16(dirname9(candidatePath), "document.json"), documentJson);
|
|
104259
|
+
atomicWrite(
|
|
104260
|
+
candidatePath,
|
|
104261
|
+
JSON.stringify({
|
|
104262
|
+
version: 1,
|
|
104263
|
+
candidateRevision: TEST_CANDIDATE_CACHE_REVISION,
|
|
104264
|
+
cliVersion: PROJECT_SCHEMA_CONTRACT.cliVersion,
|
|
104265
|
+
compilerRevision: NEOSCRIPT_COMPILER_REVISION,
|
|
104266
|
+
inputFingerprint,
|
|
104267
|
+
sourceHash: candidate.sourceHash,
|
|
104268
|
+
documentSha256
|
|
104269
|
+
}) + "\n"
|
|
104270
|
+
);
|
|
104271
|
+
return { ...candidate, documentSha256 };
|
|
104272
|
+
}
|
|
103235
104273
|
function compileSpec(workspace, document, absolutePath, projectCompilationHash2) {
|
|
103236
104274
|
const scriptDocument = readDocumentArrays(document);
|
|
103237
104275
|
const path = relative5(workspace.root, absolutePath).split(sep5).join("/");
|
|
103238
104276
|
const source = readFileSync16(absolutePath, "utf8");
|
|
103239
|
-
const sourceHash =
|
|
104277
|
+
const sourceHash = createHash11("sha256").update(source).digest("hex");
|
|
103240
104278
|
const artifactPath = join16(
|
|
103241
104279
|
workspace.root,
|
|
103242
104280
|
".neo",
|
|
@@ -103247,7 +104285,7 @@ function compileSpec(workspace, document, absolutePath, projectCompilationHash2)
|
|
|
103247
104285
|
);
|
|
103248
104286
|
try {
|
|
103249
104287
|
const cached = JSON.parse(readFileSync16(artifactPath, "utf8"));
|
|
103250
|
-
if (isRecord10(cached) && cached.version === 1 && cached.compilerRevision === NEOSCRIPT_COMPILER_REVISION && cached.projectCompilationHash === projectCompilationHash2 && cached.sourceHash === sourceHash && isRecord10(cached.action) && typeof cached.artifactSha256 === "string" &&
|
|
104288
|
+
if (isRecord10(cached) && cached.version === 1 && cached.compilerRevision === NEOSCRIPT_COMPILER_REVISION && cached.projectCompilationHash === projectCompilationHash2 && cached.sourceHash === sourceHash && isRecord10(cached.action) && typeof cached.artifactSha256 === "string" && createHash11("sha256").update(JSON.stringify(cached.action)).digest("hex") === cached.artifactSha256 && cached.action.compilerRevision === NEOSCRIPT_COMPILER_REVISION && Array.isArray(cached.action.parameters) && Array.isArray(cached.action.instructions) && isRecord10(cached.action.typeInfo)) {
|
|
103251
104289
|
return {
|
|
103252
104290
|
path,
|
|
103253
104291
|
source,
|
|
@@ -103279,15 +104317,16 @@ function compileSpec(workspace, document, absolutePath, projectCompilationHash2)
|
|
|
103279
104317
|
compilerRevision: NEOSCRIPT_COMPILER_REVISION,
|
|
103280
104318
|
projectCompilationHash: projectCompilationHash2,
|
|
103281
104319
|
sourceHash,
|
|
103282
|
-
artifactSha256:
|
|
104320
|
+
artifactSha256: createHash11("sha256").update(JSON.stringify(compiled.action)).digest("hex"),
|
|
103283
104321
|
action: compiled.action
|
|
103284
104322
|
})}
|
|
103285
104323
|
`
|
|
103286
104324
|
);
|
|
103287
104325
|
return compiled;
|
|
103288
104326
|
}
|
|
103289
|
-
function projectCompilationHash(projectSourceHash, document) {
|
|
103290
|
-
|
|
104327
|
+
function projectCompilationHash(projectSourceHash, document, knownDocumentSha256) {
|
|
104328
|
+
const documentSha256 = knownDocumentSha256 ?? createHash11("sha256").update(JSON.stringify(document)).digest("hex");
|
|
104329
|
+
return createHash11("sha256").update(projectSourceHash).update("\0").update(documentSha256).digest("hex");
|
|
103291
104330
|
}
|
|
103292
104331
|
function selectedSpecPaths(workspace, selectors) {
|
|
103293
104332
|
const all = listProjectTestFilesV1(workspace.root);
|
|
@@ -103520,7 +104559,7 @@ function registerSpec(spec, document) {
|
|
|
103520
104559
|
}
|
|
103521
104560
|
names.add(fullName);
|
|
103522
104561
|
const test = {
|
|
103523
|
-
id: `sha256:${
|
|
104562
|
+
id: `sha256:${createHash11("sha256").update(`${spec.path}\0${namePath}`).digest("hex")}`,
|
|
103524
104563
|
name: namePath,
|
|
103525
104564
|
fullName,
|
|
103526
104565
|
body: portableDelegate(call.args[1]),
|
|
@@ -103579,8 +104618,7 @@ function mockResponse(environment, mock, selected2, call) {
|
|
|
103579
104618
|
};
|
|
103580
104619
|
}
|
|
103581
104620
|
function partialObjectMatch(actual, expected) {
|
|
103582
|
-
if (!isRecord10(expected))
|
|
103583
|
-
return stableTestValue(actual) === stableTestValue(expected);
|
|
104621
|
+
if (!isRecord10(expected)) return isDeepStrictEqual(actual, expected);
|
|
103584
104622
|
if (!isRecord10(actual)) return false;
|
|
103585
104623
|
return Object.entries(expected).every(
|
|
103586
104624
|
([key, value]) => partialObjectMatch(actual[key], value)
|
|
@@ -103737,56 +104775,28 @@ function interceptTestCallCore(environment, call) {
|
|
|
103737
104775
|
}
|
|
103738
104776
|
return { handled: true, value: null };
|
|
103739
104777
|
}
|
|
103740
|
-
|
|
103741
|
-
NEO_TEST_IDS.toBe,
|
|
103742
|
-
NEO_TEST_IDS.toEqual,
|
|
103743
|
-
NEO_TEST_IDS.toBeNull,
|
|
103744
|
-
NEO_TEST_IDS.toBeTrue,
|
|
103745
|
-
NEO_TEST_IDS.toBeFalse,
|
|
103746
|
-
NEO_TEST_IDS.toBeGreaterThan,
|
|
103747
|
-
NEO_TEST_IDS.toBeGreaterThanOrEqual,
|
|
103748
|
-
NEO_TEST_IDS.toBeLessThan,
|
|
103749
|
-
NEO_TEST_IDS.toBeLessThanOrEqual,
|
|
103750
|
-
NEO_TEST_IDS.toContain,
|
|
103751
|
-
NEO_TEST_IDS.toHaveLength,
|
|
103752
|
-
NEO_TEST_IDS.toMatchObject,
|
|
103753
|
-
NEO_TEST_IDS.toThrow,
|
|
103754
|
-
NEO_TEST_IDS.toHaveBeenCalled,
|
|
103755
|
-
NEO_TEST_IDS.toHaveBeenCalledTimes,
|
|
103756
|
-
NEO_TEST_IDS.toHaveBeenCalledWith
|
|
103757
|
-
]);
|
|
103758
|
-
if (!matcherIds.has(call.memberId)) return { handled: false };
|
|
104778
|
+
if (!MATCHER_IDS.has(call.memberId)) return { handled: false };
|
|
103759
104779
|
const expectationValue = readExpectation(call.receiver);
|
|
103760
104780
|
const actual = expectationValue.actual;
|
|
103761
104781
|
if (call.memberId === NEO_TEST_IDS.toBe) {
|
|
103762
104782
|
assertMatcher(
|
|
103763
104783
|
Object.is(actual, call.args[0]),
|
|
103764
104784
|
expectationValue,
|
|
103765
|
-
|
|
104785
|
+
"toBe",
|
|
103766
104786
|
call.args[0]
|
|
103767
104787
|
);
|
|
103768
104788
|
} else if (call.memberId === NEO_TEST_IDS.toEqual) {
|
|
103769
104789
|
assertMatcher(
|
|
103770
|
-
|
|
104790
|
+
isDeepStrictEqual(actual, call.args[0]),
|
|
103771
104791
|
expectationValue,
|
|
103772
|
-
|
|
104792
|
+
"toEqual",
|
|
103773
104793
|
call.args[0]
|
|
103774
104794
|
);
|
|
103775
104795
|
} else if (call.memberId === NEO_TEST_IDS.toBeNull) {
|
|
103776
|
-
assertMatcher(
|
|
103777
|
-
actual === null,
|
|
103778
|
-
expectationValue,
|
|
103779
|
-
`Expected ${display(actual)} ${expectationValue.negated ? "not " : ""}to be null.`,
|
|
103780
|
-
null
|
|
103781
|
-
);
|
|
104796
|
+
assertMatcher(actual === null, expectationValue, "toBeNull", null);
|
|
103782
104797
|
} else if (call.memberId === NEO_TEST_IDS.toBeTrue || call.memberId === NEO_TEST_IDS.toBeFalse) {
|
|
103783
104798
|
const expected = call.memberId === NEO_TEST_IDS.toBeTrue;
|
|
103784
|
-
assertMatcher(
|
|
103785
|
-
actual === expected,
|
|
103786
|
-
expectationValue,
|
|
103787
|
-
`Expected ${display(actual)} ${expectationValue.negated ? "not " : ""}to be ${String(expected)}.`,
|
|
103788
|
-
expected
|
|
103789
|
-
);
|
|
104799
|
+
assertMatcher(actual === expected, expectationValue, "boolean", expected);
|
|
103790
104800
|
} 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) {
|
|
103791
104801
|
const left = Number(actual);
|
|
103792
104802
|
const right = Number(call.args[0]);
|
|
@@ -103794,25 +104804,18 @@ function interceptTestCallCore(environment, call) {
|
|
|
103794
104804
|
assertMatcher(
|
|
103795
104805
|
Number.isFinite(left) && Number.isFinite(right) && matches,
|
|
103796
104806
|
expectationValue,
|
|
103797
|
-
|
|
104807
|
+
"numeric",
|
|
103798
104808
|
call.args[0]
|
|
103799
104809
|
);
|
|
103800
104810
|
} else if (call.memberId === NEO_TEST_IDS.toContain) {
|
|
103801
|
-
const contains2 = typeof actual === "string" ? actual.includes(String(call.args[0])) : Array.isArray(actual) && actual.some(
|
|
103802
|
-
|
|
103803
|
-
);
|
|
103804
|
-
assertMatcher(
|
|
103805
|
-
contains2,
|
|
103806
|
-
expectationValue,
|
|
103807
|
-
`Expected ${display(actual)} ${expectationValue.negated ? "not " : ""}to contain ${display(call.args[0])}.`,
|
|
103808
|
-
call.args[0]
|
|
103809
|
-
);
|
|
104811
|
+
const contains2 = typeof actual === "string" ? actual.includes(String(call.args[0])) : Array.isArray(actual) && actual.some((entry) => isDeepStrictEqual(entry, call.args[0]));
|
|
104812
|
+
assertMatcher(contains2, expectationValue, "toContain", call.args[0]);
|
|
103810
104813
|
} else if (call.memberId === NEO_TEST_IDS.toHaveLength) {
|
|
103811
104814
|
const length = typeof actual === "string" || Array.isArray(actual) ? actual.length : isRecord10(actual) ? Object.keys(actual).length : -1;
|
|
103812
104815
|
assertMatcher(
|
|
103813
104816
|
length === call.args[0],
|
|
103814
104817
|
expectationValue,
|
|
103815
|
-
|
|
104818
|
+
"toHaveLength",
|
|
103816
104819
|
call.args[0],
|
|
103817
104820
|
length
|
|
103818
104821
|
);
|
|
@@ -103820,7 +104823,7 @@ function interceptTestCallCore(environment, call) {
|
|
|
103820
104823
|
assertMatcher(
|
|
103821
104824
|
partialObjectMatch(actual, call.args[0]),
|
|
103822
104825
|
expectationValue,
|
|
103823
|
-
|
|
104826
|
+
"toMatchObject",
|
|
103824
104827
|
call.args[0]
|
|
103825
104828
|
);
|
|
103826
104829
|
} else if (call.memberId === NEO_TEST_IDS.toThrow) {
|
|
@@ -103836,9 +104839,10 @@ function interceptTestCallCore(environment, call) {
|
|
|
103836
104839
|
assertMatcher(
|
|
103837
104840
|
matches,
|
|
103838
104841
|
expectationValue,
|
|
103839
|
-
|
|
104842
|
+
"toThrow",
|
|
103840
104843
|
pattern ?? "a catchable NeoScript error",
|
|
103841
|
-
thrown === void 0 ? "no throw" : errorMessage2(thrown)
|
|
104844
|
+
thrown === void 0 ? "no throw" : errorMessage2(thrown),
|
|
104845
|
+
pattern
|
|
103842
104846
|
);
|
|
103843
104847
|
} else {
|
|
103844
104848
|
const handle = readMockHandle(actual);
|
|
@@ -103848,15 +104852,14 @@ function interceptTestCallCore(environment, call) {
|
|
|
103848
104852
|
"Expected value is not an active mock handle."
|
|
103849
104853
|
);
|
|
103850
104854
|
}
|
|
103851
|
-
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(
|
|
103852
|
-
(args) => stableTestValue(args) === stableTestValue(call.args)
|
|
103853
|
-
);
|
|
104855
|
+
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));
|
|
103854
104856
|
assertMatcher(
|
|
103855
104857
|
matches,
|
|
103856
104858
|
expectationValue,
|
|
103857
|
-
|
|
104859
|
+
"mock",
|
|
103858
104860
|
call.memberId === NEO_TEST_IDS.toHaveBeenCalled ? "at least one call" : call.memberId === NEO_TEST_IDS.toHaveBeenCalledTimes ? call.args[0] : call.args,
|
|
103859
|
-
call.memberId === NEO_TEST_IDS.toHaveBeenCalledTimes ? mock.calls.length : mock.calls
|
|
104861
|
+
call.memberId === NEO_TEST_IDS.toHaveBeenCalledTimes ? mock.calls.length : mock.calls,
|
|
104862
|
+
mock.calls
|
|
103860
104863
|
);
|
|
103861
104864
|
}
|
|
103862
104865
|
return { handled: true, value: null };
|
|
@@ -103871,24 +104874,32 @@ function interceptTestCall(environment, call) {
|
|
|
103871
104874
|
throw error;
|
|
103872
104875
|
}
|
|
103873
104876
|
}
|
|
103874
|
-
function createTestEnvironment(document
|
|
104877
|
+
function createTestEnvironment(document) {
|
|
103875
104878
|
const environment = {
|
|
103876
104879
|
baseDocument: document,
|
|
103877
104880
|
context: void 0,
|
|
103878
104881
|
mocks: /* @__PURE__ */ new Map(),
|
|
103879
104882
|
mocksByMember: /* @__PURE__ */ new Map(),
|
|
103880
|
-
nextMockId: 1
|
|
104883
|
+
nextMockId: 1,
|
|
104884
|
+
hasStateChanges: false
|
|
103881
104885
|
};
|
|
103882
104886
|
environment.context = makeEvaluatorContext(
|
|
103883
104887
|
document,
|
|
103884
|
-
(call) => interceptTestCall(environment, call)
|
|
103885
|
-
documentAlreadyIsolated
|
|
104888
|
+
(call) => interceptTestCall(environment, call)
|
|
103886
104889
|
);
|
|
103887
104890
|
return environment;
|
|
103888
104891
|
}
|
|
103889
104892
|
function snapshotEnvironmentDocument(environment) {
|
|
103890
|
-
const
|
|
103891
|
-
const
|
|
104893
|
+
const overlay = environment.context.__valueOverlay;
|
|
104894
|
+
const runtime = environment.context.__runtimeSessionValues;
|
|
104895
|
+
const bindings = new Map([
|
|
104896
|
+
...environment.context.__saveStaticBindings ?? [],
|
|
104897
|
+
...environment.context.__sessionStaticBindings ?? []
|
|
104898
|
+
]);
|
|
104899
|
+
if (!environment.hasStateChanges) return environment.baseDocument;
|
|
104900
|
+
const snapshot = { ...environment.baseDocument };
|
|
104901
|
+
const baseValues = Array.isArray(snapshot.values) ? snapshot.values : [];
|
|
104902
|
+
const values = [...baseValues];
|
|
103892
104903
|
const byId = /* @__PURE__ */ new Map();
|
|
103893
104904
|
values.forEach((value, index) => {
|
|
103894
104905
|
if (isRecord10(value) && typeof value.id === "string")
|
|
@@ -103905,20 +104916,17 @@ function snapshotEnvironmentDocument(environment) {
|
|
|
103905
104916
|
values[index] = cloned;
|
|
103906
104917
|
}
|
|
103907
104918
|
};
|
|
103908
|
-
for (const row of
|
|
103909
|
-
|
|
103910
|
-
for (const row of environment.context.__runtimeSessionValues?.values() ?? [])
|
|
103911
|
-
mergeRow(row);
|
|
104919
|
+
for (const row of overlay?.values() ?? []) mergeRow(row);
|
|
104920
|
+
for (const row of runtime?.values() ?? []) mergeRow(row);
|
|
103912
104921
|
snapshot.values = values;
|
|
103913
|
-
|
|
103914
|
-
|
|
103915
|
-
|
|
103916
|
-
|
|
103917
|
-
|
|
103918
|
-
|
|
103919
|
-
|
|
103920
|
-
|
|
103921
|
-
member.valueId = bindings.get(member.id) ?? null;
|
|
104922
|
+
if (bindings.size > 0) {
|
|
104923
|
+
const baseMembers = Array.isArray(snapshot.members) ? snapshot.members : [];
|
|
104924
|
+
snapshot.members = baseMembers.map((member) => {
|
|
104925
|
+
if (!isRecord10(member) || typeof member.id !== "string" || !bindings.has(member.id)) {
|
|
104926
|
+
return member;
|
|
104927
|
+
}
|
|
104928
|
+
return { ...member, valueId: bindings.get(member.id) ?? null };
|
|
104929
|
+
});
|
|
103922
104930
|
}
|
|
103923
104931
|
return snapshot;
|
|
103924
104932
|
}
|
|
@@ -103939,10 +104947,7 @@ function copyMocks(source, target) {
|
|
|
103939
104947
|
}
|
|
103940
104948
|
}
|
|
103941
104949
|
function cloneTestEnvironment(source) {
|
|
103942
|
-
const cloned = createTestEnvironment(
|
|
103943
|
-
snapshotEnvironmentDocument(source),
|
|
103944
|
-
true
|
|
103945
|
-
);
|
|
104950
|
+
const cloned = createTestEnvironment(snapshotEnvironmentDocument(source));
|
|
103946
104951
|
copyMocks(source, cloned);
|
|
103947
104952
|
return cloned;
|
|
103948
104953
|
}
|
|
@@ -103953,10 +104958,14 @@ function runCallback(environment, delegate, deadlineMs) {
|
|
|
103953
104958
|
__indexes: void 0,
|
|
103954
104959
|
wallClockDeadlineMs: deadlineMs
|
|
103955
104960
|
});
|
|
103956
|
-
|
|
103957
|
-
|
|
103958
|
-
|
|
103959
|
-
|
|
104961
|
+
try {
|
|
104962
|
+
evaluateNSDelegate(
|
|
104963
|
+
bindNeoScriptDelegateToContext(delegate, environment.context),
|
|
104964
|
+
environment.context
|
|
104965
|
+
);
|
|
104966
|
+
} finally {
|
|
104967
|
+
environment.hasStateChanges ||= (environment.context.__executionState?.writes.length ?? 0) > 0 || (environment.context.__runtimeSessionValues?.size ?? 0) > 0 || (environment.context.__saveStaticBindings?.size ?? 0) > 0 || (environment.context.__sessionStaticBindings?.size ?? 0) > 0;
|
|
104968
|
+
}
|
|
103960
104969
|
}
|
|
103961
104970
|
function failureFor(error, file, position, member = null) {
|
|
103962
104971
|
const timeout = error instanceof NeoScriptWallClockTimeoutError;
|
|
@@ -103982,18 +104991,22 @@ function suiteHasSelectedTests(suite, selected2) {
|
|
|
103982
104991
|
async function executeRegisteredSpec(registered, document, selected2, timeoutMs, interrupted) {
|
|
103983
104992
|
const results = [];
|
|
103984
104993
|
const fileFailures = [];
|
|
104994
|
+
let testDurationMs = 0;
|
|
103985
104995
|
const executeSuite = async (suite, parentEnvironment, inheritedFailures) => {
|
|
103986
104996
|
if (!suiteHasSelectedTests(suite, selected2)) return;
|
|
103987
104997
|
const fixture = cloneTestEnvironment(parentEnvironment);
|
|
103988
104998
|
const suiteFailures = [...inheritedFailures];
|
|
103989
104999
|
const suiteDeadline = Date.now() + timeoutMs;
|
|
103990
105000
|
for (const hook of suite.beforeAll) {
|
|
105001
|
+
const hookStarted = performance.now();
|
|
103991
105002
|
try {
|
|
103992
105003
|
runCallback(fixture, hook, suiteDeadline);
|
|
103993
105004
|
} catch (error) {
|
|
103994
105005
|
suiteFailures.push(
|
|
103995
105006
|
failureFor(error, registered.spec.path, suite, "beforeAll")
|
|
103996
105007
|
);
|
|
105008
|
+
} finally {
|
|
105009
|
+
testDurationMs += performance.now() - hookStarted;
|
|
103997
105010
|
}
|
|
103998
105011
|
}
|
|
103999
105012
|
for (const test of suite.tests) {
|
|
@@ -104001,6 +105014,8 @@ async function executeRegisteredSpec(registered, document, selected2, timeoutMs,
|
|
|
104001
105014
|
const started = performance.now();
|
|
104002
105015
|
const deadline = Date.now() + timeoutMs;
|
|
104003
105016
|
const environment = cloneTestEnvironment(fixture);
|
|
105017
|
+
const startupBeforeTestMs = performance.now() - started;
|
|
105018
|
+
const testStarted = performance.now();
|
|
104004
105019
|
const failures = [...suiteFailures];
|
|
104005
105020
|
let setupFailed = failures.length > 0;
|
|
104006
105021
|
if (!setupFailed) {
|
|
@@ -104037,19 +105052,24 @@ async function executeRegisteredSpec(registered, document, selected2, timeoutMs,
|
|
|
104037
105052
|
}
|
|
104038
105053
|
}
|
|
104039
105054
|
}
|
|
104040
|
-
const
|
|
105055
|
+
const currentTestDurationMs = performance.now() - testStarted;
|
|
105056
|
+
const schedulerStarted = performance.now();
|
|
105057
|
+
await new Promise((resolvePromise) => {
|
|
105058
|
+
setImmediate(resolvePromise);
|
|
105059
|
+
});
|
|
105060
|
+
const startupDurationMs = startupBeforeTestMs + performance.now() - schedulerStarted;
|
|
105061
|
+
testDurationMs += currentTestDurationMs;
|
|
104041
105062
|
results.push({
|
|
104042
105063
|
id: test.id,
|
|
104043
105064
|
file: registered.spec.path,
|
|
104044
105065
|
name: test.name,
|
|
104045
105066
|
fullName: test.fullName,
|
|
104046
105067
|
status: failures.length === 0 ? "passed" : "failed",
|
|
104047
|
-
durationMs,
|
|
105068
|
+
durationMs: startupDurationMs + currentTestDurationMs,
|
|
105069
|
+
startupDurationMs,
|
|
105070
|
+
testDurationMs: currentTestDurationMs,
|
|
104048
105071
|
failures
|
|
104049
105072
|
});
|
|
104050
|
-
await new Promise((resolvePromise) => {
|
|
104051
|
-
setImmediate(resolvePromise);
|
|
104052
|
-
});
|
|
104053
105073
|
if (interrupted()) break;
|
|
104054
105074
|
}
|
|
104055
105075
|
for (const child of suite.suites) {
|
|
@@ -104057,12 +105077,15 @@ async function executeRegisteredSpec(registered, document, selected2, timeoutMs,
|
|
|
104057
105077
|
await executeSuite(child, fixture, suiteFailures);
|
|
104058
105078
|
}
|
|
104059
105079
|
for (const hook of suite.afterAll) {
|
|
105080
|
+
const hookStarted = performance.now();
|
|
104060
105081
|
try {
|
|
104061
105082
|
runCallback(fixture, hook, Date.now() + timeoutMs);
|
|
104062
105083
|
} catch (error) {
|
|
104063
105084
|
fileFailures.push(
|
|
104064
105085
|
failureFor(error, registered.spec.path, suite, "afterAll")
|
|
104065
105086
|
);
|
|
105087
|
+
} finally {
|
|
105088
|
+
testDurationMs += performance.now() - hookStarted;
|
|
104066
105089
|
}
|
|
104067
105090
|
}
|
|
104068
105091
|
};
|
|
@@ -104073,7 +105096,7 @@ async function executeRegisteredSpec(registered, document, selected2, timeoutMs,
|
|
|
104073
105096
|
results.sort(
|
|
104074
105097
|
(left, right) => (registrationOrder.get(left.id) ?? Number.MAX_SAFE_INTEGER) - (registrationOrder.get(right.id) ?? Number.MAX_SAFE_INTEGER)
|
|
104075
105098
|
);
|
|
104076
|
-
return { tests: results, failures: fileFailures };
|
|
105099
|
+
return { tests: results, failures: fileFailures, testDurationMs };
|
|
104077
105100
|
}
|
|
104078
105101
|
function atomicWrite(path, content) {
|
|
104079
105102
|
mkdirSync11(dirname9(path), { recursive: true });
|
|
@@ -104126,8 +105149,28 @@ function maintainNeoTestBuildCache(root, maxBytes = TEST_BUILD_CACHE_LIMIT_BYTES
|
|
|
104126
105149
|
total -= file.size;
|
|
104127
105150
|
}
|
|
104128
105151
|
}
|
|
105152
|
+
function formatTestDuration(durationMs) {
|
|
105153
|
+
if (durationMs >= 1e3) {
|
|
105154
|
+
const seconds = durationMs / 1e3;
|
|
105155
|
+
return `${seconds < 10 ? seconds.toFixed(2) : seconds.toFixed(1)}s`;
|
|
105156
|
+
}
|
|
105157
|
+
return `${durationMs < 10 ? durationMs.toFixed(2) : durationMs.toFixed(1)}ms`;
|
|
105158
|
+
}
|
|
105159
|
+
function paintTestDuration(durationMs) {
|
|
105160
|
+
const formatted = formatTestDuration(durationMs);
|
|
105161
|
+
return durationMs >= 300 ? color.yellow(formatted) : color.dim(formatted);
|
|
105162
|
+
}
|
|
105163
|
+
function formatStatusCounts(passed, failed, total, skipped = 0) {
|
|
105164
|
+
const parts = [
|
|
105165
|
+
failed > 0 ? color.red(`${failed} failed`) : null,
|
|
105166
|
+
passed > 0 ? color.green(`${passed} passed`) : null,
|
|
105167
|
+
skipped > 0 ? color.yellow(`${skipped} skipped`) : null
|
|
105168
|
+
].filter((part) => part !== null);
|
|
105169
|
+
return `${parts.join(color.dim(" | "))} ${color.dim(`(${total})`)}`;
|
|
105170
|
+
}
|
|
104129
105171
|
async function runTest(workspace, options, dependencies = {}) {
|
|
104130
105172
|
const started = Date.now();
|
|
105173
|
+
const performanceStarted = performance.now();
|
|
104131
105174
|
const testBuildRoot = join16(workspace.root, ".neo", "test-build");
|
|
104132
105175
|
maintainNeoTestBuildCache(testBuildRoot);
|
|
104133
105176
|
const startedAt = new Date(started).toISOString();
|
|
@@ -104140,6 +105183,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104140
105183
|
const selectedTestCountByFile = /* @__PURE__ */ new Map();
|
|
104141
105184
|
const fileFailuresByPath = /* @__PURE__ */ new Map();
|
|
104142
105185
|
const diagnostics = [];
|
|
105186
|
+
let testDurationMs = 0;
|
|
104143
105187
|
let exitCode = 0;
|
|
104144
105188
|
let interrupted = false;
|
|
104145
105189
|
const handleSigint = () => {
|
|
@@ -104153,22 +105197,77 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104153
105197
|
}
|
|
104154
105198
|
};
|
|
104155
105199
|
process.on("SIGINT", handleSigint);
|
|
105200
|
+
const phaseDurations = {
|
|
105201
|
+
prepare: 0,
|
|
105202
|
+
select: 0,
|
|
105203
|
+
compile: 0,
|
|
105204
|
+
register: 0,
|
|
105205
|
+
execute: 0,
|
|
105206
|
+
finalize: 0
|
|
105207
|
+
};
|
|
104156
105208
|
let phase = "prepare";
|
|
105209
|
+
let phaseStarted = performanceStarted;
|
|
105210
|
+
const enterPhase = (next, label) => {
|
|
105211
|
+
const finished = performance.now();
|
|
105212
|
+
phaseDurations[phase] += finished - phaseStarted;
|
|
105213
|
+
phase = next;
|
|
105214
|
+
phaseStarted = finished;
|
|
105215
|
+
dependencies.progress?.update(label);
|
|
105216
|
+
};
|
|
105217
|
+
const finishPhase = () => {
|
|
105218
|
+
const finished = performance.now();
|
|
105219
|
+
phaseDurations[phase] += finished - phaseStarted;
|
|
105220
|
+
phaseStarted = finished;
|
|
105221
|
+
};
|
|
105222
|
+
dependencies.progress?.update("Preparing test project\u2026");
|
|
104157
105223
|
try {
|
|
104158
|
-
|
|
105224
|
+
let candidate = dependencies.prepareLocalCandidate === void 0 ? preparedHookCandidate(workspace) : null;
|
|
105225
|
+
let candidateInputFingerprint = null;
|
|
105226
|
+
let shouldCacheCandidate = false;
|
|
105227
|
+
if (candidate === null) {
|
|
105228
|
+
const canUseCandidateCache = dependencies.prepareLocalCandidate === void 0 || dependencies.fingerprintCandidateInputs !== void 0;
|
|
105229
|
+
if (canUseCandidateCache) {
|
|
105230
|
+
candidateInputFingerprint = dependencies.fingerprintCandidateInputs?.(workspace) ?? fingerprintTestCandidateInputs(workspace);
|
|
105231
|
+
candidate = cachedTestCandidate(workspace, candidateInputFingerprint);
|
|
105232
|
+
}
|
|
105233
|
+
if (candidate === null) {
|
|
105234
|
+
const prepared = dependencies.prepareLocalCandidate === void 0 ? await prepareLocalCandidateV4(workspace, {
|
|
105235
|
+
onPhase: (label) => {
|
|
105236
|
+
dependencies.progress?.update(label);
|
|
105237
|
+
}
|
|
105238
|
+
}) : await dependencies.prepareLocalCandidate(workspace);
|
|
105239
|
+
if (prepared.document === null) {
|
|
105240
|
+
throw new NeoTestReportWriteError(
|
|
105241
|
+
"Local test preparation did not produce a project document."
|
|
105242
|
+
);
|
|
105243
|
+
}
|
|
105244
|
+
candidate = {
|
|
105245
|
+
document: prepared.document,
|
|
105246
|
+
sourceHash: prepared.sourceHash
|
|
105247
|
+
};
|
|
105248
|
+
shouldCacheCandidate = canUseCandidateCache;
|
|
105249
|
+
}
|
|
105250
|
+
}
|
|
104159
105251
|
assertNotInterrupted();
|
|
104160
|
-
if (candidate
|
|
105252
|
+
if (candidate === null) {
|
|
104161
105253
|
throw new NeoTestReportWriteError(
|
|
104162
|
-
"Local test preparation
|
|
105254
|
+
"Local test preparation produced no reusable candidate."
|
|
104163
105255
|
);
|
|
104164
105256
|
}
|
|
105257
|
+
if (shouldCacheCandidate && candidateInputFingerprint !== null) {
|
|
105258
|
+
candidate = cacheTestCandidate(workspace, candidateInputFingerprint, {
|
|
105259
|
+
document: candidate.document,
|
|
105260
|
+
sourceHash: candidate.sourceHash
|
|
105261
|
+
});
|
|
105262
|
+
}
|
|
104165
105263
|
projectFingerprint = `sha256:${candidate.sourceHash}`;
|
|
104166
105264
|
const rawDocument = documentRecord(candidate.document);
|
|
104167
105265
|
const compilationHash = projectCompilationHash(
|
|
104168
105266
|
candidate.sourceHash,
|
|
104169
|
-
rawDocument
|
|
105267
|
+
rawDocument,
|
|
105268
|
+
candidate.documentSha256
|
|
104170
105269
|
);
|
|
104171
|
-
|
|
105270
|
+
enterPhase("select", "Selecting test files\u2026");
|
|
104172
105271
|
let selectedPaths;
|
|
104173
105272
|
try {
|
|
104174
105273
|
selectedPaths = selectedSpecPaths(workspace, options.selectors);
|
|
@@ -104183,7 +105282,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104183
105282
|
"No .spec.neo files matched. Pass --passWithNoTests to treat this as success."
|
|
104184
105283
|
);
|
|
104185
105284
|
}
|
|
104186
|
-
|
|
105285
|
+
enterPhase("compile", "Compiling test files\u2026");
|
|
104187
105286
|
specs = selectedPaths.map(
|
|
104188
105287
|
(path) => compileSpec(workspace, rawDocument, path, compilationHash)
|
|
104189
105288
|
);
|
|
@@ -104197,7 +105296,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104197
105296
|
);
|
|
104198
105297
|
}
|
|
104199
105298
|
}
|
|
104200
|
-
|
|
105299
|
+
enterPhase("register", "Registering tests\u2026");
|
|
104201
105300
|
const registered = specs.map((spec) => registerSpec(spec, rawDocument));
|
|
104202
105301
|
const selectedTests = registered.flatMap((entry) => entry.tests).filter((test) => pattern === null || pattern.test(test.fullName));
|
|
104203
105302
|
for (const entry of registered) {
|
|
@@ -104214,7 +105313,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104214
105313
|
);
|
|
104215
105314
|
}
|
|
104216
105315
|
const selectedIds = new Set(selectedTests.map((test) => test.id));
|
|
104217
|
-
|
|
105316
|
+
enterPhase("execute", "Running tests\u2026");
|
|
104218
105317
|
const timeoutMs = options.timeoutMs ?? workspace.config.test?.timeoutMs ?? 5e3;
|
|
104219
105318
|
for (const entry of registered) {
|
|
104220
105319
|
const executed = await executeRegisteredSpec(
|
|
@@ -104225,12 +105324,14 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104225
105324
|
() => interrupted
|
|
104226
105325
|
);
|
|
104227
105326
|
results.push(...executed.tests);
|
|
105327
|
+
testDurationMs += executed.testDurationMs;
|
|
104228
105328
|
fileFailuresByPath.set(entry.spec.path, executed.failures);
|
|
104229
105329
|
assertNotInterrupted();
|
|
104230
105330
|
}
|
|
104231
105331
|
if (results.some((result) => result.status === "failed") || [...fileFailuresByPath.values()].some((failures) => failures.length > 0)) {
|
|
104232
105332
|
exitCode = 1;
|
|
104233
105333
|
}
|
|
105334
|
+
enterPhase("finalize", "Finalizing test report\u2026");
|
|
104234
105335
|
const buildManifest = {
|
|
104235
105336
|
version: 1,
|
|
104236
105337
|
cliVersion: PROJECT_SCHEMA_CONTRACT.cliVersion,
|
|
@@ -104238,14 +105339,14 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104238
105339
|
compilerRevision: NEOSCRIPT_COMPILER_REVISION,
|
|
104239
105340
|
evaluatorRevision: 4,
|
|
104240
105341
|
projectFingerprint,
|
|
104241
|
-
configurationSha256:
|
|
105342
|
+
configurationSha256: createHash11("sha256").update(JSON.stringify(workspace.config.test ?? {})).digest("hex"),
|
|
104242
105343
|
dependencyGraph: Object.fromEntries(
|
|
104243
105344
|
specs.map((spec) => [spec.path, [projectFingerprint]])
|
|
104244
105345
|
),
|
|
104245
105346
|
artifacts: specs.map((spec) => ({
|
|
104246
105347
|
path: spec.path,
|
|
104247
|
-
sourceSha256:
|
|
104248
|
-
artifactSha256:
|
|
105348
|
+
sourceSha256: createHash11("sha256").update(spec.source).digest("hex"),
|
|
105349
|
+
artifactSha256: createHash11("sha256").update(JSON.stringify(spec.action)).digest("hex")
|
|
104249
105350
|
}))
|
|
104250
105351
|
};
|
|
104251
105352
|
atomicWrite(
|
|
@@ -104266,6 +105367,8 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104266
105367
|
related: []
|
|
104267
105368
|
});
|
|
104268
105369
|
}
|
|
105370
|
+
finishPhase();
|
|
105371
|
+
dependencies.progress?.stop();
|
|
104269
105372
|
process.off("SIGINT", handleSigint);
|
|
104270
105373
|
const failed = results.filter((result) => result.status === "failed").length;
|
|
104271
105374
|
const selectedTestTotal = [...selectedTestCountByFile.values()].reduce(
|
|
@@ -104273,7 +105376,16 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104273
105376
|
0
|
|
104274
105377
|
);
|
|
104275
105378
|
const skipped = Math.max(0, selectedTestTotal - results.length);
|
|
104276
|
-
const durationMs =
|
|
105379
|
+
const durationMs = performance.now() - performanceStarted;
|
|
105380
|
+
const startupDurationMs = Math.max(0, durationMs - testDurationMs);
|
|
105381
|
+
const perTestStartupDurationMs = results.reduce(
|
|
105382
|
+
(sum, result) => sum + result.startupDurationMs,
|
|
105383
|
+
0
|
|
105384
|
+
);
|
|
105385
|
+
const sharedStartupDurationMs = Math.max(
|
|
105386
|
+
0,
|
|
105387
|
+
startupDurationMs - perTestStartupDurationMs
|
|
105388
|
+
);
|
|
104277
105389
|
const testFiles = specs.map((spec) => {
|
|
104278
105390
|
const tests = results.filter((result) => result.file === spec.path);
|
|
104279
105391
|
const failures = fileFailuresByPath.get(spec.path) ?? [];
|
|
@@ -104290,7 +105402,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104290
105402
|
success: exitCode === 0,
|
|
104291
105403
|
projectFingerprint,
|
|
104292
105404
|
seed: Number.parseInt(
|
|
104293
|
-
|
|
105405
|
+
createHash11("sha256").update(projectFingerprint ?? "neo-test:no-project").digest("hex").slice(0, 8),
|
|
104294
105406
|
16
|
|
104295
105407
|
),
|
|
104296
105408
|
selection: {
|
|
@@ -104305,7 +105417,18 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104305
105417
|
failed,
|
|
104306
105418
|
skipped,
|
|
104307
105419
|
todo: 0,
|
|
104308
|
-
durationMs
|
|
105420
|
+
durationMs,
|
|
105421
|
+
startupDurationMs,
|
|
105422
|
+
sharedStartupDurationMs,
|
|
105423
|
+
testDurationMs
|
|
105424
|
+
},
|
|
105425
|
+
timings: {
|
|
105426
|
+
prepareMs: phaseDurations.prepare,
|
|
105427
|
+
selectMs: phaseDurations.select,
|
|
105428
|
+
compileMs: phaseDurations.compile,
|
|
105429
|
+
registerMs: phaseDurations.register,
|
|
105430
|
+
executeMs: phaseDurations.execute,
|
|
105431
|
+
finalizeMs: phaseDurations.finalize
|
|
104309
105432
|
},
|
|
104310
105433
|
testFiles,
|
|
104311
105434
|
diagnostics,
|
|
@@ -104330,30 +105453,63 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104330
105453
|
if (options.reporter === "json") {
|
|
104331
105454
|
if (options.outputFile === null) process.stdout.write(serialized);
|
|
104332
105455
|
} else {
|
|
104333
|
-
|
|
105456
|
+
console.log("");
|
|
105457
|
+
console.log(
|
|
105458
|
+
` ${color.bold("RUN")} ${color.dim(`neo ${PROJECT_SCHEMA_CONTRACT.cliVersion} ${workspace.root}`)}`
|
|
105459
|
+
);
|
|
105460
|
+
console.log("");
|
|
105461
|
+
console.log(
|
|
105462
|
+
` ${color.cyan("\u21BB")} ${color.dim("shared startup")} ${paintTestDuration(report.summary.sharedStartupDurationMs)}`
|
|
105463
|
+
);
|
|
105464
|
+
for (const file of testFiles) {
|
|
105465
|
+
const fileDurationMs = file.tests.reduce(
|
|
105466
|
+
(sum, test) => sum + test.durationMs,
|
|
105467
|
+
0
|
|
105468
|
+
);
|
|
105469
|
+
const fileSymbol = file.status === "passed" ? color.green("\u2713") : file.status === "failed" ? color.red("\xD7") : color.yellow("!");
|
|
105470
|
+
const testLabel = `${file.tests.length} ${file.tests.length === 1 ? "test" : "tests"}`;
|
|
104334
105471
|
console.log(
|
|
104335
|
-
|
|
105472
|
+
` ${fileSymbol} ${color.bold(file.path)} ${color.dim(`(${testLabel})`)} ${paintTestDuration(fileDurationMs)}`
|
|
104336
105473
|
);
|
|
104337
|
-
for (const
|
|
104338
|
-
|
|
104339
|
-
|
|
104340
|
-
|
|
105474
|
+
for (const result of file.tests) {
|
|
105475
|
+
const resultSymbol = result.status === "passed" ? color.green("\u2713") : color.red("\xD7");
|
|
105476
|
+
console.log(
|
|
105477
|
+
` ${resultSymbol} ${result.name} ${color.dim("total")} ${paintTestDuration(result.durationMs)} ${color.dim(`(test ${formatTestDuration(result.testDurationMs)}, startup ${formatTestDuration(result.startupDurationMs)})`)}`
|
|
105478
|
+
);
|
|
105479
|
+
for (const failure of result.failures) {
|
|
105480
|
+
console.log(` ${color.red(failure.message)}`);
|
|
105481
|
+
}
|
|
105482
|
+
}
|
|
104341
105483
|
if (file.status === "interrupted") {
|
|
104342
105484
|
console.log(
|
|
104343
|
-
|
|
105485
|
+
` ${color.yellow("!")} interrupted before all selected tests ran`
|
|
104344
105486
|
);
|
|
104345
105487
|
}
|
|
104346
105488
|
for (const failure of file.failures) {
|
|
104347
105489
|
console.log(
|
|
104348
|
-
|
|
105490
|
+
` ${color.red("\xD7")} ${failure.frames[0]?.member ?? "suite hook"}`
|
|
104349
105491
|
);
|
|
104350
|
-
console.log(`
|
|
105492
|
+
console.log(` ${color.red(failure.message)}`);
|
|
104351
105493
|
}
|
|
104352
105494
|
}
|
|
104353
|
-
for (const diagnostic of diagnostics)
|
|
104354
|
-
console.log(
|
|
105495
|
+
for (const diagnostic of diagnostics) {
|
|
105496
|
+
console.log(` ${color.red("\xD7")} ${diagnostic.message}`);
|
|
105497
|
+
}
|
|
105498
|
+
console.log("");
|
|
105499
|
+
const passedFiles = testFiles.filter(
|
|
105500
|
+
(file) => file.status === "passed"
|
|
105501
|
+
).length;
|
|
105502
|
+
const failedFiles = testFiles.filter(
|
|
105503
|
+
(file) => file.status === "failed"
|
|
105504
|
+
).length;
|
|
105505
|
+
console.log(
|
|
105506
|
+
` ${color.bold(pad("Test Files", 11))} ${formatStatusCounts(passedFiles, failedFiles, report.summary.files)}`
|
|
105507
|
+
);
|
|
104355
105508
|
console.log(
|
|
104356
|
-
|
|
105509
|
+
` ${color.bold(pad("Tests", 11))} ${formatStatusCounts(report.summary.passed, report.summary.failed, report.summary.tests, report.summary.skipped)}`
|
|
105510
|
+
);
|
|
105511
|
+
console.log(
|
|
105512
|
+
` ${color.bold(pad("Duration", 11))} ${color.bold(`total ${formatTestDuration(report.summary.durationMs)}`)} ${color.dim(`(test ${formatTestDuration(report.summary.testDurationMs)}, startup ${formatTestDuration(report.summary.startupDurationMs)})`)}`
|
|
104357
105513
|
);
|
|
104358
105514
|
}
|
|
104359
105515
|
if (!report.success) process.exitCode = exitCode;
|
|
@@ -104400,7 +105556,7 @@ async function inspectNeoTestCompilation(workspace, dependencies = {}) {
|
|
|
104400
105556
|
errors
|
|
104401
105557
|
};
|
|
104402
105558
|
}
|
|
104403
|
-
var TEST_BUILD_CACHE_LIMIT_BYTES, ABANDONED_TEMP_MAX_AGE_MS, NeoTestUsageError, NeoTestNoTestsError, NeoTestRegistrationError, NeoTestReportWriteError, NeoTestPreparedCandidateError, NeoTestInterruptedError, NeoTestAssertionError, ERROR_SOURCE_POSITIONS, REGISTRATION_IDS;
|
|
105559
|
+
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;
|
|
104404
105560
|
var init_test = __esm({
|
|
104405
105561
|
"src/commands/test.ts"() {
|
|
104406
105562
|
"use strict";
|
|
@@ -104413,8 +105569,10 @@ var init_test = __esm({
|
|
|
104413
105569
|
init_push();
|
|
104414
105570
|
init_registry2();
|
|
104415
105571
|
init_push_hook();
|
|
105572
|
+
init_ui();
|
|
104416
105573
|
TEST_BUILD_CACHE_LIMIT_BYTES = 512 * 1024 * 1024;
|
|
104417
105574
|
ABANDONED_TEMP_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
105575
|
+
TEST_CANDIDATE_CACHE_REVISION = 1;
|
|
104418
105576
|
NeoTestUsageError = class extends Error {
|
|
104419
105577
|
name = "NeoTestUsageError";
|
|
104420
105578
|
};
|
|
@@ -104446,6 +105604,7 @@ var init_test = __esm({
|
|
|
104446
105604
|
received;
|
|
104447
105605
|
};
|
|
104448
105606
|
ERROR_SOURCE_POSITIONS = /* @__PURE__ */ new WeakMap();
|
|
105607
|
+
SHARED_EVALUATOR_BASES = /* @__PURE__ */ new WeakMap();
|
|
104449
105608
|
REGISTRATION_IDS = /* @__PURE__ */ new Set([
|
|
104450
105609
|
NEO_TEST_IDS.describe,
|
|
104451
105610
|
NEO_TEST_IDS.test,
|
|
@@ -104455,6 +105614,24 @@ var init_test = __esm({
|
|
|
104455
105614
|
NEO_TEST_IDS.beforeEach,
|
|
104456
105615
|
NEO_TEST_IDS.afterEach
|
|
104457
105616
|
]);
|
|
105617
|
+
MATCHER_IDS = /* @__PURE__ */ new Set([
|
|
105618
|
+
NEO_TEST_IDS.toBe,
|
|
105619
|
+
NEO_TEST_IDS.toEqual,
|
|
105620
|
+
NEO_TEST_IDS.toBeNull,
|
|
105621
|
+
NEO_TEST_IDS.toBeTrue,
|
|
105622
|
+
NEO_TEST_IDS.toBeFalse,
|
|
105623
|
+
NEO_TEST_IDS.toBeGreaterThan,
|
|
105624
|
+
NEO_TEST_IDS.toBeGreaterThanOrEqual,
|
|
105625
|
+
NEO_TEST_IDS.toBeLessThan,
|
|
105626
|
+
NEO_TEST_IDS.toBeLessThanOrEqual,
|
|
105627
|
+
NEO_TEST_IDS.toContain,
|
|
105628
|
+
NEO_TEST_IDS.toHaveLength,
|
|
105629
|
+
NEO_TEST_IDS.toMatchObject,
|
|
105630
|
+
NEO_TEST_IDS.toThrow,
|
|
105631
|
+
NEO_TEST_IDS.toHaveBeenCalled,
|
|
105632
|
+
NEO_TEST_IDS.toHaveBeenCalledTimes,
|
|
105633
|
+
NEO_TEST_IDS.toHaveBeenCalledWith
|
|
105634
|
+
]);
|
|
104458
105635
|
}
|
|
104459
105636
|
});
|
|
104460
105637
|
|
|
@@ -107841,7 +109018,8 @@ function loadWorkspaceForCommand(args) {
|
|
|
107841
109018
|
// A reset reconstructs the working copy from the server and may therefore
|
|
107842
109019
|
// discard an unsupported pre-cutover cache. No other command gets this
|
|
107843
109020
|
// exception, so format 2 never becomes an active compatibility read path.
|
|
107844
|
-
discardLegacyFormat2State: args.command === "pull" && boolFlag(args, "reset")
|
|
109021
|
+
discardLegacyFormat2State: args.command === "pull" && boolFlag(args, "reset"),
|
|
109022
|
+
fingerprintStateSource: args.command === "test"
|
|
107845
109023
|
});
|
|
107846
109024
|
const apiOverride = stringFlag(args, "api");
|
|
107847
109025
|
if (apiOverride !== null) {
|
|
@@ -108019,7 +109197,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
108019
109197
|
async function main() {
|
|
108020
109198
|
const args = parseArgs(process.argv.slice(2));
|
|
108021
109199
|
if (args.command === "--version") {
|
|
108022
|
-
console.log("0.26.
|
|
109200
|
+
console.log("0.26.3");
|
|
108023
109201
|
return;
|
|
108024
109202
|
}
|
|
108025
109203
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
|
@@ -108303,15 +109481,25 @@ async function main() {
|
|
|
108303
109481
|
"--testTimeout must be a positive number of milliseconds."
|
|
108304
109482
|
);
|
|
108305
109483
|
}
|
|
108306
|
-
const
|
|
108307
|
-
|
|
108308
|
-
|
|
108309
|
-
|
|
108310
|
-
|
|
108311
|
-
|
|
108312
|
-
|
|
108313
|
-
|
|
108314
|
-
|
|
109484
|
+
const progress = reporterValue === "default" && process.stdout.isTTY === true ? spinner("Preparing test project\u2026") : null;
|
|
109485
|
+
try {
|
|
109486
|
+
const { runTest: runTest2 } = await Promise.resolve().then(() => (init_test(), test_exports));
|
|
109487
|
+
await runTest2(
|
|
109488
|
+
workspace,
|
|
109489
|
+
{
|
|
109490
|
+
selectors: args.positional,
|
|
109491
|
+
testNamePattern: stringFlag(args, "testNamePattern"),
|
|
109492
|
+
reporter: reporterValue,
|
|
109493
|
+
outputFile: stringFlag(args, "outputFile") ?? stringFlag(args, "output-file"),
|
|
109494
|
+
passWithNoTests: boolFlag(args, "passWithNoTests"),
|
|
109495
|
+
...timeoutMs === void 0 ? {} : { timeoutMs }
|
|
109496
|
+
},
|
|
109497
|
+
progress === null ? {} : { progress }
|
|
109498
|
+
);
|
|
109499
|
+
} catch (error) {
|
|
109500
|
+
progress?.fail("Test run failed.");
|
|
109501
|
+
throw error;
|
|
109502
|
+
}
|
|
108315
109503
|
return;
|
|
108316
109504
|
}
|
|
108317
109505
|
case "dev": {
|