@neocompose/cli 0.26.0 → 0.26.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +12 -4
- package/dist/neo.mjs +1255 -236
- 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
|
@@ -2143,16 +2143,28 @@ function complete(snapshot, position) {
|
|
|
2143
2143
|
candidates = switchCaseCandidates;
|
|
2144
2144
|
} else if (tail && (tail.kind === "punctuation" && tail.text === "." || tail.kind === "operator" && tail.text === "?.")) {
|
|
2145
2145
|
const receiverTokens = expressionTokensBefore(tokens, tokens.length - 1);
|
|
2146
|
-
|
|
2147
|
-
|
|
2146
|
+
if (receiverTokens.length === 0 || isContextualCompletionDot(snapshot.source.text, word.start)) {
|
|
2147
|
+
candidates = contextualEnumCompletionItems(
|
|
2148
|
+
snapshot,
|
|
2149
|
+
expectedTypeAt(snapshot, word.start),
|
|
2150
|
+
word
|
|
2151
|
+
);
|
|
2152
|
+
} else {
|
|
2153
|
+
const resolved = resolveChain(snapshot, receiverTokens, offset);
|
|
2154
|
+
candidates = completionItemsForResolution(snapshot, resolved, word);
|
|
2155
|
+
}
|
|
2148
2156
|
} else if (tail?.kind === "identifier" && tail.text === NEOSCRIPT_CONSTRUCTOR_KEYWORD) {
|
|
2149
|
-
candidates = constructorCompletionItems(
|
|
2157
|
+
candidates = constructorCompletionItems(
|
|
2158
|
+
snapshot,
|
|
2159
|
+
word,
|
|
2160
|
+
expectedTypeAt(snapshot, word.start)
|
|
2161
|
+
);
|
|
2150
2162
|
} else if (isTypePosition(tokens)) {
|
|
2151
2163
|
candidates = typeCompletionItems(snapshot, word);
|
|
2152
2164
|
} else if (isLambdaParameterPosition(tokens)) {
|
|
2153
2165
|
candidates = [];
|
|
2154
2166
|
} else {
|
|
2155
|
-
candidates =
|
|
2167
|
+
candidates = contextualCompletionItems(snapshot, offset, word);
|
|
2156
2168
|
}
|
|
2157
2169
|
return {
|
|
2158
2170
|
isIncomplete: hasUnclosedConstruct(snapshot.lexed.tokens, offset),
|
|
@@ -2230,12 +2242,33 @@ function signatureHelp(snapshot, position) {
|
|
|
2230
2242
|
if (call.kind === "constructor") {
|
|
2231
2243
|
const type = resolution?.staticType;
|
|
2232
2244
|
const constructor2 = type?.constructorSignature;
|
|
2233
|
-
|
|
2245
|
+
const declared = type?.declaredConstructors ?? [];
|
|
2246
|
+
if (!type) return null;
|
|
2234
2247
|
const activeParameter2 = countTopLevelCommas(
|
|
2235
2248
|
snapshot.source.text,
|
|
2236
2249
|
call.openParenOffset + 1,
|
|
2237
2250
|
offset
|
|
2238
2251
|
);
|
|
2252
|
+
if (declared.length > 0) {
|
|
2253
|
+
return {
|
|
2254
|
+
signatures: declared.map((candidate) => ({
|
|
2255
|
+
label: `${type.name}(${candidate.parameters.map(
|
|
2256
|
+
(parameter4) => `${formatType(parameter4.type, snapshot.project)} ${parameter4.name}`
|
|
2257
|
+
).join(", ")})`,
|
|
2258
|
+
...candidate.documentation ? { documentation: candidate.documentation } : {},
|
|
2259
|
+
parameters: candidate.parameters.map((parameter4) => ({
|
|
2260
|
+
label: `${formatType(parameter4.type, snapshot.project)} ${parameter4.name}`,
|
|
2261
|
+
...parameter4.documentation ? { documentation: parameter4.documentation } : {}
|
|
2262
|
+
}))
|
|
2263
|
+
})),
|
|
2264
|
+
activeSignature: 0,
|
|
2265
|
+
activeParameter: Math.min(
|
|
2266
|
+
activeParameter2,
|
|
2267
|
+
Math.max(0, (declared[0]?.parameters.length ?? 1) - 1)
|
|
2268
|
+
)
|
|
2269
|
+
};
|
|
2270
|
+
}
|
|
2271
|
+
if (!constructor2) return null;
|
|
2239
2272
|
return {
|
|
2240
2273
|
signatures: [
|
|
2241
2274
|
{
|
|
@@ -2283,19 +2316,18 @@ function inlayHints(snapshot, range2) {
|
|
|
2283
2316
|
const hints = [];
|
|
2284
2317
|
for (const call of snapshot.parsed.calls) {
|
|
2285
2318
|
if (call.kind !== "constructor") continue;
|
|
2286
|
-
const
|
|
2287
|
-
|
|
2288
|
-
)
|
|
2289
|
-
if (!constructor2) continue;
|
|
2319
|
+
const type = snapshot.project.typeByName.get(call.name);
|
|
2320
|
+
const parameterNames = constructorParameterNames(type);
|
|
2321
|
+
if (!parameterNames) continue;
|
|
2290
2322
|
for (let index = 0; index < call.argumentRanges.length; index++) {
|
|
2291
2323
|
const argumentRange = call.argumentRanges[index];
|
|
2292
|
-
const
|
|
2293
|
-
if (!argumentRange || !
|
|
2324
|
+
const parameterName = parameterNames[index];
|
|
2325
|
+
if (!argumentRange || !parameterName) continue;
|
|
2294
2326
|
const position = firstNonWhitespacePosition(snapshot, argumentRange);
|
|
2295
2327
|
if (range2 && !positionInRange(position, range2)) continue;
|
|
2296
2328
|
hints.push({
|
|
2297
2329
|
position,
|
|
2298
|
-
label: `${
|
|
2330
|
+
label: `${parameterName}:`,
|
|
2299
2331
|
kind: "parameter",
|
|
2300
2332
|
paddingRight: true
|
|
2301
2333
|
});
|
|
@@ -2303,6 +2335,22 @@ function inlayHints(snapshot, range2) {
|
|
|
2303
2335
|
}
|
|
2304
2336
|
return hints;
|
|
2305
2337
|
}
|
|
2338
|
+
function constructorParameterNames(type) {
|
|
2339
|
+
const declared = type?.declaredConstructors ?? [];
|
|
2340
|
+
if (declared.length > 0) {
|
|
2341
|
+
const arity = Math.max(
|
|
2342
|
+
...declared.map((constructor2) => constructor2.parameters.length)
|
|
2343
|
+
);
|
|
2344
|
+
return Array.from({ length: arity }, (_, index) => {
|
|
2345
|
+
const names = new Set(
|
|
2346
|
+
declared.map((constructor2) => constructor2.parameters[index]?.name)
|
|
2347
|
+
);
|
|
2348
|
+
const [name] = names;
|
|
2349
|
+
return names.size === 1 && name ? name : null;
|
|
2350
|
+
});
|
|
2351
|
+
}
|
|
2352
|
+
return type?.constructorSignature?.parameters.map((parameter4) => parameter4.name) ?? null;
|
|
2353
|
+
}
|
|
2306
2354
|
function documentSymbols(snapshot) {
|
|
2307
2355
|
const unitSymbols = snapshot.parsed.units.map((unit) => ({
|
|
2308
2356
|
name: unit.kind,
|
|
@@ -2439,8 +2487,9 @@ function isValidNeoIdentifier(name) {
|
|
|
2439
2487
|
function isValidRenameIdentifier(name) {
|
|
2440
2488
|
return isValidNeoIdentifier(name);
|
|
2441
2489
|
}
|
|
2442
|
-
function
|
|
2490
|
+
function contextualCompletionItems(snapshot, offset, word) {
|
|
2443
2491
|
const items = [];
|
|
2492
|
+
const expectedType = expectedTypeAt(snapshot, word.start);
|
|
2444
2493
|
if (insideCatchBody(snapshot, offset)) {
|
|
2445
2494
|
items.push(
|
|
2446
2495
|
completion(
|
|
@@ -2454,7 +2503,12 @@ function topLevelCompletionItems(snapshot, offset, word) {
|
|
|
2454
2503
|
)
|
|
2455
2504
|
);
|
|
2456
2505
|
}
|
|
2506
|
+
const statementStart = isStatementStart(snapshot.lexed.tokens, word.start);
|
|
2457
2507
|
for (const keyword of NEOSCRIPT_KEYWORDS) {
|
|
2508
|
+
if (!statementStart && statementOnlyKeyword(keyword)) continue;
|
|
2509
|
+
if (!statementStart && expectedType !== null && !literalKeywordMatchesExpectedType(keyword, expectedType)) {
|
|
2510
|
+
continue;
|
|
2511
|
+
}
|
|
2458
2512
|
items.push(
|
|
2459
2513
|
completion(
|
|
2460
2514
|
keyword,
|
|
@@ -2467,6 +2521,7 @@ function topLevelCompletionItems(snapshot, offset, word) {
|
|
|
2467
2521
|
);
|
|
2468
2522
|
}
|
|
2469
2523
|
for (const snippet of NEOSCRIPT_STATEMENT_SNIPPETS) {
|
|
2524
|
+
if (!statementStart) continue;
|
|
2470
2525
|
items.push(
|
|
2471
2526
|
completion(
|
|
2472
2527
|
snippet.label,
|
|
@@ -2479,60 +2534,282 @@ function topLevelCompletionItems(snapshot, offset, word) {
|
|
|
2479
2534
|
)
|
|
2480
2535
|
);
|
|
2481
2536
|
}
|
|
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) {
|
|
2537
|
+
if (statementStart) {
|
|
2505
2538
|
items.push(
|
|
2506
2539
|
completion(
|
|
2507
|
-
|
|
2508
|
-
"
|
|
2509
|
-
|
|
2510
|
-
"
|
|
2540
|
+
NEOSCRIPT_INFERRED_LOCAL_KEYWORD,
|
|
2541
|
+
"snippet",
|
|
2542
|
+
"var ${1:name} = ${0:value};",
|
|
2543
|
+
"Inferred local declaration",
|
|
2511
2544
|
word,
|
|
2512
|
-
snapshot
|
|
2545
|
+
snapshot,
|
|
2546
|
+
"snippet"
|
|
2547
|
+
)
|
|
2548
|
+
);
|
|
2549
|
+
}
|
|
2550
|
+
const expectedNamed = expectedType?.kind === "named" ? snapshot.project.typeById.get(expectedType.typeId) : void 0;
|
|
2551
|
+
if (expectedType === null || expectedNamed?.kind === "class" || expectedNamed?.kind === "interface") {
|
|
2552
|
+
items.push(
|
|
2553
|
+
completion(
|
|
2554
|
+
NEOSCRIPT_CONSTRUCTOR_KEYWORD,
|
|
2555
|
+
"snippet",
|
|
2556
|
+
"new ${1:ClassName}(${0})",
|
|
2557
|
+
"Construct a Class value",
|
|
2558
|
+
word,
|
|
2559
|
+
snapshot,
|
|
2560
|
+
"snippet"
|
|
2561
|
+
)
|
|
2562
|
+
);
|
|
2563
|
+
}
|
|
2564
|
+
if (statementStart && expectedType === null) {
|
|
2565
|
+
for (const primitive3 of NEOSCRIPT_PRIMITIVE_TYPES) {
|
|
2566
|
+
items.push(
|
|
2567
|
+
completion(
|
|
2568
|
+
primitive3,
|
|
2569
|
+
"keyword",
|
|
2570
|
+
primitive3,
|
|
2571
|
+
"Primitive type",
|
|
2572
|
+
word,
|
|
2573
|
+
snapshot
|
|
2574
|
+
)
|
|
2575
|
+
);
|
|
2576
|
+
}
|
|
2577
|
+
items.push(
|
|
2578
|
+
completion(
|
|
2579
|
+
"Dictionary",
|
|
2580
|
+
"snippet",
|
|
2581
|
+
"Dictionary<string, ${1:T}>",
|
|
2582
|
+
"Dictionary type",
|
|
2583
|
+
word,
|
|
2584
|
+
snapshot,
|
|
2585
|
+
"snippet"
|
|
2513
2586
|
)
|
|
2514
2587
|
);
|
|
2515
2588
|
}
|
|
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
2589
|
for (const symbol of scopeAt(snapshot, offset)) {
|
|
2590
|
+
if (expectedType !== null && !isNeoScriptTypeAssignable(
|
|
2591
|
+
symbol.returnType ?? symbol.type,
|
|
2592
|
+
expectedType,
|
|
2593
|
+
snapshot.project
|
|
2594
|
+
)) {
|
|
2595
|
+
continue;
|
|
2596
|
+
}
|
|
2528
2597
|
items.push(symbolCompletion(symbol, word, snapshot));
|
|
2529
2598
|
}
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2599
|
+
if (statementStart && expectedType === null) {
|
|
2600
|
+
for (const type of snapshot.project.typeByName.values()) {
|
|
2601
|
+
if (type.kind === "builtin" && type.name.startsWith("__")) continue;
|
|
2602
|
+
items.push(typeCompletion(type, word, snapshot));
|
|
2603
|
+
}
|
|
2533
2604
|
}
|
|
2534
2605
|
return items;
|
|
2535
2606
|
}
|
|
2607
|
+
function contextualEnumCompletionItems(snapshot, expected, word) {
|
|
2608
|
+
if (expected?.kind !== "named") return [];
|
|
2609
|
+
const type = snapshot.project.typeById.get(expected.typeId);
|
|
2610
|
+
if (type?.kind !== "enum") return [];
|
|
2611
|
+
return type.members.filter((member) => member.kind === "enumMember").map((member) => {
|
|
2612
|
+
const item = symbolCompletion(member, word, snapshot);
|
|
2613
|
+
return {
|
|
2614
|
+
...item,
|
|
2615
|
+
label: `.${member.name}`,
|
|
2616
|
+
insertText: member.name,
|
|
2617
|
+
textEdit: {
|
|
2618
|
+
range: snapshot.source.range(word.start, word.end),
|
|
2619
|
+
newText: member.name
|
|
2620
|
+
}
|
|
2621
|
+
};
|
|
2622
|
+
});
|
|
2623
|
+
}
|
|
2624
|
+
function isContextualCompletionDot(text, wordStart) {
|
|
2625
|
+
if (text[wordStart - 1] !== ".") return false;
|
|
2626
|
+
let cursor = wordStart - 2;
|
|
2627
|
+
while (cursor >= 0 && /\s/.test(text[cursor] ?? "")) cursor--;
|
|
2628
|
+
const beforeDot = text[cursor];
|
|
2629
|
+
if (beforeDot !== void 0 && /[A-Za-z0-9_]/.test(beforeDot)) {
|
|
2630
|
+
const precedingWord = /[A-Za-z_][A-Za-z0-9_]*$/.exec(
|
|
2631
|
+
text.slice(0, cursor + 1)
|
|
2632
|
+
)?.[0];
|
|
2633
|
+
return precedingWord === "return" || precedingWord === "case";
|
|
2634
|
+
}
|
|
2635
|
+
return beforeDot === void 0 || !/[A-Za-z0-9_\])}]/.test(beforeDot);
|
|
2636
|
+
}
|
|
2637
|
+
function expectedTypeAt(snapshot, offset) {
|
|
2638
|
+
const call = [...snapshot.parsed.calls].filter(
|
|
2639
|
+
(candidate) => candidate.openParenOffset < offset && (candidate.closeParenOffset === void 0 || candidate.closeParenOffset >= offset)
|
|
2640
|
+
).sort((left, right) => right.openParenOffset - left.openParenOffset)[0];
|
|
2641
|
+
if (call) {
|
|
2642
|
+
const reference2 = snapshot.parsed.references.find(
|
|
2643
|
+
(candidate) => candidate.range.start.line === call.nameRange.start.line && candidate.range.start.character === call.nameRange.start.character
|
|
2644
|
+
);
|
|
2645
|
+
const resolution = reference2 ? resolveReference(snapshot, reference2) : null;
|
|
2646
|
+
const index = countTopLevelCommas(
|
|
2647
|
+
snapshot.source.text,
|
|
2648
|
+
call.openParenOffset + 1,
|
|
2649
|
+
offset
|
|
2650
|
+
);
|
|
2651
|
+
const parameterType = call.kind === "constructor" ? constructorParameterTypeAt(resolution?.staticType, index, snapshot) : resolution?.symbol?.parameters?.[index]?.type;
|
|
2652
|
+
if (parameterType) {
|
|
2653
|
+
return expectedCollectionElementType(
|
|
2654
|
+
parameterType,
|
|
2655
|
+
snapshot.lexed.tokens,
|
|
2656
|
+
call.openParenOffset + 1,
|
|
2657
|
+
offset
|
|
2658
|
+
);
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
const local = snapshot.parsed.locals.filter((candidate) => {
|
|
2662
|
+
const first = candidate.initializerTokens?.[0];
|
|
2663
|
+
return !candidate.inferred && first !== void 0 && first.start <= offset && offset <= snapshot.source.offsetAt(candidate.declarationRange.end);
|
|
2664
|
+
}).sort((left, right) => right.scopeStart - left.scopeStart)[0];
|
|
2665
|
+
if (local) {
|
|
2666
|
+
const first = local.initializerTokens?.[0];
|
|
2667
|
+
return expectedCollectionElementType(
|
|
2668
|
+
resolveDeclaredType(local, snapshot),
|
|
2669
|
+
snapshot.lexed.tokens,
|
|
2670
|
+
first?.start ?? offset,
|
|
2671
|
+
offset
|
|
2672
|
+
);
|
|
2673
|
+
}
|
|
2674
|
+
const tokens = significantTokensBefore(snapshot.lexed.tokens, offset);
|
|
2675
|
+
const boundary = lastStatementBoundary(tokens);
|
|
2676
|
+
for (let index = tokens.length - 1; index > boundary; index--) {
|
|
2677
|
+
const token = tokens[index];
|
|
2678
|
+
if (token?.kind !== "operator" || token.text !== "=") continue;
|
|
2679
|
+
const left = expressionTokensBefore(tokens, index);
|
|
2680
|
+
const resolution = resolveChain(snapshot, left, offset);
|
|
2681
|
+
if (resolution) {
|
|
2682
|
+
return expectedCollectionElementType(
|
|
2683
|
+
resolution.type,
|
|
2684
|
+
tokens,
|
|
2685
|
+
token.end,
|
|
2686
|
+
offset
|
|
2687
|
+
);
|
|
2688
|
+
}
|
|
2689
|
+
break;
|
|
2690
|
+
}
|
|
2691
|
+
for (let index = tokens.length - 1; index > boundary; index--) {
|
|
2692
|
+
const token = tokens[index];
|
|
2693
|
+
if (token?.kind !== "operator" || token.text !== "==" && token.text !== "!=") {
|
|
2694
|
+
continue;
|
|
2695
|
+
}
|
|
2696
|
+
const left = expressionTokensBefore(tokens, index);
|
|
2697
|
+
const type = resolveChain(snapshot, left, offset)?.type ?? inferExpressionType(left, snapshot, left[0]?.start ?? offset);
|
|
2698
|
+
if (!isUnknownExpectedType(type)) return type;
|
|
2699
|
+
}
|
|
2700
|
+
const futureComparison = expectedTypeFromComparisonRight(snapshot, offset);
|
|
2701
|
+
if (futureComparison) return futureComparison;
|
|
2702
|
+
const tail = tokens.at(-1);
|
|
2703
|
+
if (tail?.kind === "operator" && ["!", "&&", "||"].includes(tail.text) || tail?.kind === "punctuation" && tail.text === "(" && tokens.at(-2)?.kind === "keyword" && ["if", "while"].includes(tokens.at(-2)?.text ?? "")) {
|
|
2704
|
+
return { kind: "primitive", name: "bool" };
|
|
2705
|
+
}
|
|
2706
|
+
const throwToken = tokens.slice(boundary + 1).find((token) => token.kind === "keyword" && token.text === "throw");
|
|
2707
|
+
if (throwToken) return { kind: "primitive", name: "string" };
|
|
2708
|
+
const returnToken = tokens.slice(boundary + 1).find((token) => token.kind === "keyword" && token.text === "return");
|
|
2709
|
+
if (returnToken && snapshot.context.returnType) {
|
|
2710
|
+
return expectedCollectionElementType(
|
|
2711
|
+
snapshot.context.returnType,
|
|
2712
|
+
tokens,
|
|
2713
|
+
returnToken.end,
|
|
2714
|
+
offset
|
|
2715
|
+
);
|
|
2716
|
+
}
|
|
2717
|
+
return null;
|
|
2718
|
+
}
|
|
2719
|
+
function expectedTypeFromComparisonRight(snapshot, offset) {
|
|
2720
|
+
const tokens = snapshot.lexed.tokens.filter(
|
|
2721
|
+
(token) => token.kind !== "comment" && token.kind !== "eof"
|
|
2722
|
+
);
|
|
2723
|
+
let operatorIndex = -1;
|
|
2724
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
2725
|
+
const token = tokens[index];
|
|
2726
|
+
if (!token || token.start < offset) continue;
|
|
2727
|
+
if (token.kind === "punctuation" && [";", "{", "}"].includes(token.text)) {
|
|
2728
|
+
break;
|
|
2729
|
+
}
|
|
2730
|
+
if (token.kind === "operator" && (token.text === "==" || token.text === "!=")) {
|
|
2731
|
+
operatorIndex = index;
|
|
2732
|
+
break;
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2735
|
+
if (operatorIndex < 0) return null;
|
|
2736
|
+
const right = [];
|
|
2737
|
+
let depth = 0;
|
|
2738
|
+
for (let index = operatorIndex + 1; index < tokens.length; index++) {
|
|
2739
|
+
const token = tokens[index];
|
|
2740
|
+
if (!token) continue;
|
|
2741
|
+
if (token.kind === "punctuation" && ["(", "["].includes(token.text)) {
|
|
2742
|
+
depth++;
|
|
2743
|
+
} else if (token.kind === "punctuation" && [")", "]"].includes(token.text)) {
|
|
2744
|
+
if (depth === 0) break;
|
|
2745
|
+
depth--;
|
|
2746
|
+
}
|
|
2747
|
+
if (depth === 0 && token.kind === "punctuation" && [";", ",", "{"].includes(token.text)) {
|
|
2748
|
+
break;
|
|
2749
|
+
}
|
|
2750
|
+
right.push(token);
|
|
2751
|
+
}
|
|
2752
|
+
const type = inferExpressionType(right, snapshot, right[0]?.start ?? offset);
|
|
2753
|
+
return isUnknownExpectedType(type) ? null : type;
|
|
2754
|
+
}
|
|
2755
|
+
function isUnknownExpectedType(type) {
|
|
2756
|
+
return type.kind === "primitive" && type.name === "unknown";
|
|
2757
|
+
}
|
|
2758
|
+
function constructorParameterTypeAt(type, index, snapshot) {
|
|
2759
|
+
const declared = (type?.declaredConstructors ?? []).map((constructor2) => constructor2.parameters[index]?.type).filter(
|
|
2760
|
+
(candidate) => candidate !== void 0
|
|
2761
|
+
);
|
|
2762
|
+
if ((type?.declaredConstructors?.length ?? 0) === 0) {
|
|
2763
|
+
return type?.constructorSignature?.parameters[index]?.parameterType;
|
|
2764
|
+
}
|
|
2765
|
+
if (declared.length === 0) return void 0;
|
|
2766
|
+
const first = declared[0];
|
|
2767
|
+
return declared.every(
|
|
2768
|
+
(candidate) => isNeoScriptTypeAssignable(candidate, first, snapshot.project) && isNeoScriptTypeAssignable(first, candidate, snapshot.project)
|
|
2769
|
+
) ? first : void 0;
|
|
2770
|
+
}
|
|
2771
|
+
function expectedCollectionElementType(initial, tokens, start, end) {
|
|
2772
|
+
let expected = initial;
|
|
2773
|
+
const stack = [];
|
|
2774
|
+
for (const token of tokens) {
|
|
2775
|
+
if (token.start < start || token.end > end || token.kind !== "punctuation") {
|
|
2776
|
+
continue;
|
|
2777
|
+
}
|
|
2778
|
+
if (token.text === "[") {
|
|
2779
|
+
stack.push(expected);
|
|
2780
|
+
if (expected.kind === "list" || expected.kind === "set") {
|
|
2781
|
+
expected = expected.elementType;
|
|
2782
|
+
}
|
|
2783
|
+
} else if (token.text === "]") {
|
|
2784
|
+
expected = stack.pop() ?? expected;
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
return expected;
|
|
2788
|
+
}
|
|
2789
|
+
function lastStatementBoundary(tokens) {
|
|
2790
|
+
for (let index = tokens.length - 1; index >= 0; index--) {
|
|
2791
|
+
const token = tokens[index];
|
|
2792
|
+
if (token?.kind === "punctuation" && (token.text === ";" || token.text === "{" || token.text === "}")) {
|
|
2793
|
+
return index;
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2796
|
+
return -1;
|
|
2797
|
+
}
|
|
2798
|
+
function isStatementStart(tokens, offset) {
|
|
2799
|
+
const significant = significantTokensBefore(tokens, offset);
|
|
2800
|
+
const tail = significant.at(-1);
|
|
2801
|
+
return tail === void 0 || tail.kind === "punctuation" && (tail.text === ";" || tail.text === "{" || tail.text === "}") || tail.kind === "punctuation" && tail.text === ":";
|
|
2802
|
+
}
|
|
2803
|
+
function statementOnlyKeyword(keyword) {
|
|
2804
|
+
return !["true", "false", "null", "is"].includes(keyword);
|
|
2805
|
+
}
|
|
2806
|
+
function literalKeywordMatchesExpectedType(keyword, expected) {
|
|
2807
|
+
if (keyword === "true" || keyword === "false") {
|
|
2808
|
+
return expected.kind === "primitive" && expected.name === "bool";
|
|
2809
|
+
}
|
|
2810
|
+
if (keyword === "null") return expected.nullable === true;
|
|
2811
|
+
return false;
|
|
2812
|
+
}
|
|
2536
2813
|
function catchFilterCompletionItems(snapshot, offset, word) {
|
|
2537
2814
|
const prefix = snapshot.source.text.slice(0, offset);
|
|
2538
2815
|
if (!/\bcatch\s*\(\s*string\s+[A-Za-z_][A-Za-z0-9_]*\s*\)\s*$/.test(prefix)) {
|
|
@@ -2682,16 +2959,24 @@ function typeCompletionItems(snapshot, word) {
|
|
|
2682
2959
|
}
|
|
2683
2960
|
return items;
|
|
2684
2961
|
}
|
|
2685
|
-
function constructorCompletionItems(snapshot, word) {
|
|
2962
|
+
function constructorCompletionItems(snapshot, word, expected = null) {
|
|
2686
2963
|
return [...snapshot.project.typeByName.values()].flatMap((type) => {
|
|
2687
2964
|
const signature = type.constructorSignature;
|
|
2688
|
-
|
|
2965
|
+
const declared = type.declaredConstructors ?? [];
|
|
2966
|
+
if (!signature && declared.length === 0) return [];
|
|
2967
|
+
if (expected !== null && !isNeoScriptTypeAssignable(
|
|
2968
|
+
{ kind: "named", typeId: type.id },
|
|
2969
|
+
expected,
|
|
2970
|
+
snapshot.project
|
|
2971
|
+
)) {
|
|
2972
|
+
return [];
|
|
2973
|
+
}
|
|
2689
2974
|
const insertText = `${type.name}(`;
|
|
2690
2975
|
return [
|
|
2691
2976
|
{
|
|
2692
2977
|
label: type.name,
|
|
2693
2978
|
kind: "class",
|
|
2694
|
-
detail: formatConstructorSignature(type.name, signature, snapshot),
|
|
2979
|
+
detail: declared.length > 0 ? `${type.name} \u2014 ${declared.length} declared constructor${declared.length === 1 ? "" : "s"}` : signature ? formatConstructorSignature(type.name, signature, snapshot) : type.name,
|
|
2695
2980
|
...type.documentation ? { documentation: type.documentation } : {},
|
|
2696
2981
|
insertText,
|
|
2697
2982
|
textEdit: {
|
|
@@ -2764,6 +3049,22 @@ function membersForType(snapshot, type) {
|
|
|
2764
3049
|
return [];
|
|
2765
3050
|
}
|
|
2766
3051
|
function resolveReference(snapshot, reference2) {
|
|
3052
|
+
if (!reference2.member && (isTypeAnnotationReference(snapshot, reference2) || isConstructorTypeReference(snapshot, reference2))) {
|
|
3053
|
+
const type = snapshot.project.typeByName.get(reference2.name);
|
|
3054
|
+
if (type) {
|
|
3055
|
+
return {
|
|
3056
|
+
type: { kind: "named", typeId: type.id },
|
|
3057
|
+
staticType: type
|
|
3058
|
+
};
|
|
3059
|
+
}
|
|
3060
|
+
}
|
|
3061
|
+
if (reference2.member && isContextualCompletionDot(snapshot.source.text, reference2.start)) {
|
|
3062
|
+
const contextual = resolveContextualExpectedEnumReference(
|
|
3063
|
+
snapshot,
|
|
3064
|
+
reference2
|
|
3065
|
+
);
|
|
3066
|
+
if (contextual) return contextual;
|
|
3067
|
+
}
|
|
2767
3068
|
const tokens = snapshot.lexed.tokens.filter(
|
|
2768
3069
|
(token) => token.kind !== "comment" && token.kind !== "eof" && token.end <= reference2.end
|
|
2769
3070
|
);
|
|
@@ -2814,6 +3115,16 @@ function resolveContextualSwitchEnumReference(snapshot, reference2) {
|
|
|
2814
3115
|
);
|
|
2815
3116
|
return symbol ? { type: symbol.type, symbol } : null;
|
|
2816
3117
|
}
|
|
3118
|
+
function resolveContextualExpectedEnumReference(snapshot, reference2) {
|
|
3119
|
+
const expected = expectedTypeAt(snapshot, reference2.start);
|
|
3120
|
+
if (expected?.kind !== "named") return null;
|
|
3121
|
+
const type = snapshot.project.typeById.get(expected.typeId);
|
|
3122
|
+
if (type?.kind !== "enum") return null;
|
|
3123
|
+
const symbol = type.members.find(
|
|
3124
|
+
(member) => member.kind === "enumMember" && member.name === reference2.name
|
|
3125
|
+
);
|
|
3126
|
+
return symbol ? { type: symbol.type, symbol } : null;
|
|
3127
|
+
}
|
|
2817
3128
|
function switchCaseEnumContext(snapshot, offset) {
|
|
2818
3129
|
for (const statement of snapshot.parsed.switches) {
|
|
2819
3130
|
for (const section of statement.sections) {
|
|
@@ -3067,6 +3378,19 @@ function scopeAt(snapshot, offset) {
|
|
|
3067
3378
|
)
|
|
3068
3379
|
);
|
|
3069
3380
|
}
|
|
3381
|
+
const declaringType = snapshot.context.declaringType;
|
|
3382
|
+
if (snapshot.context.implicitMemberAccess === true && declaringType?.kind === "named") {
|
|
3383
|
+
const owner = snapshot.project.typeById.get(declaringType.typeId);
|
|
3384
|
+
if (owner) {
|
|
3385
|
+
for (const member of owner.members) {
|
|
3386
|
+
if (snapshot.context.staticMember === true && member.static !== true) {
|
|
3387
|
+
continue;
|
|
3388
|
+
}
|
|
3389
|
+
if (!isMemberCompletionAccessible(snapshot, owner, member)) continue;
|
|
3390
|
+
result.push(withScope(member, 0, snapshot.source.text.length));
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
}
|
|
3070
3394
|
if (effectiveDocumentKind(snapshot, offset) === "setter" && snapshot.context.returnType) {
|
|
3071
3395
|
result.push(
|
|
3072
3396
|
withScope(
|
|
@@ -3903,6 +4227,11 @@ function isTypeAnnotationReference(snapshot, reference2) {
|
|
|
3903
4227
|
(local) => local.typeTokens.some((token) => token.start === reference2.start)
|
|
3904
4228
|
);
|
|
3905
4229
|
}
|
|
4230
|
+
function isConstructorTypeReference(snapshot, reference2) {
|
|
4231
|
+
return snapshot.parsed.calls.some(
|
|
4232
|
+
(call) => call.kind === "constructor" && call.nameRange.start.line === reference2.range.start.line && call.nameRange.start.character === reference2.range.start.character
|
|
4233
|
+
);
|
|
4234
|
+
}
|
|
3906
4235
|
var IDENTIFIER_PATTERN, RESERVED_NAMES;
|
|
3907
4236
|
var init_analyzer = __esm({
|
|
3908
4237
|
"../packages/neoscript-language/src/analyzer.ts"() {
|
|
@@ -10150,7 +10479,9 @@ var init_strict_resolver = __esm({
|
|
|
10150
10479
|
pointer: operand.pointer
|
|
10151
10480
|
},
|
|
10152
10481
|
type: isNullable(operand.type) ? { ...operand.type, nullable: false } : operand.type,
|
|
10153
|
-
...operand.writability ? { writability: operand.writability } : {}
|
|
10482
|
+
...operand.writability ? { writability: operand.writability } : {},
|
|
10483
|
+
...operand.entryWritability ? { entryWritability: operand.entryWritability } : {},
|
|
10484
|
+
...operand.writeRoot ? { writeRoot: operand.writeRoot } : {}
|
|
10154
10485
|
};
|
|
10155
10486
|
}
|
|
10156
10487
|
case "coalesce": {
|
|
@@ -10999,7 +11330,7 @@ var init_strict_resolver = __esm({
|
|
|
10999
11330
|
};
|
|
11000
11331
|
}
|
|
11001
11332
|
const writability = this.memberWritability(member, receiver);
|
|
11002
|
-
const entryWritability = member.lookup
|
|
11333
|
+
const entryWritability = member.lookup ? this.lookupEntryWritability(member, receiver) : void 0;
|
|
11003
11334
|
const lookupWire = member.lookup?.multiselect === true && memberType2.kind === "set" ? {
|
|
11004
11335
|
type: 9 /* Lookup */,
|
|
11005
11336
|
required: !isNullable(memberType2),
|
|
@@ -11094,12 +11425,9 @@ var init_strict_resolver = __esm({
|
|
|
11094
11425
|
}
|
|
11095
11426
|
if (!member.writable) return void 0;
|
|
11096
11427
|
if (!member.lookup) {
|
|
11097
|
-
return member.writability ? toWritability(member.writability) : receiver.writability ?? "save" /* Save */;
|
|
11428
|
+
return member.writability ? toWritability(member.writability) : receiver.entryWritability ?? receiver.writability ?? "save" /* Save */;
|
|
11098
11429
|
}
|
|
11099
|
-
|
|
11100
|
-
return member.writability ? toWritability(member.writability) : receiver.writability ?? "save" /* Save */;
|
|
11101
|
-
}
|
|
11102
|
-
return this.lookupEntryWritability(member, receiver);
|
|
11430
|
+
return member.writability ? toWritability(member.writability) : receiver.writability ?? "save" /* Save */;
|
|
11103
11431
|
}
|
|
11104
11432
|
lookupEntryWritability(member, receiver) {
|
|
11105
11433
|
if (!member.lookup) return "readOnly" /* ReadOnly */;
|
|
@@ -21593,6 +21921,7 @@ function compileProjectSourceBodies(documents) {
|
|
|
21593
21921
|
const graph = buildProjectGraph(documents);
|
|
21594
21922
|
const projectIndex = createProjectIndex(graph.project);
|
|
21595
21923
|
const bodies = [];
|
|
21924
|
+
const contexts = [];
|
|
21596
21925
|
const diagnostics = [];
|
|
21597
21926
|
for (const [uri, document] of documents) {
|
|
21598
21927
|
if (document.kind !== "definition") continue;
|
|
@@ -21637,6 +21966,7 @@ function compileProjectSourceBodies(documents) {
|
|
|
21637
21966
|
},
|
|
21638
21967
|
projectIndex,
|
|
21639
21968
|
bodies,
|
|
21969
|
+
contexts,
|
|
21640
21970
|
diagnostics
|
|
21641
21971
|
});
|
|
21642
21972
|
}
|
|
@@ -21672,6 +22002,7 @@ function compileProjectSourceBodies(documents) {
|
|
|
21672
22002
|
},
|
|
21673
22003
|
projectIndex,
|
|
21674
22004
|
bodies,
|
|
22005
|
+
contexts,
|
|
21675
22006
|
diagnostics
|
|
21676
22007
|
});
|
|
21677
22008
|
}
|
|
@@ -21712,6 +22043,7 @@ function compileProjectSourceBodies(documents) {
|
|
|
21712
22043
|
},
|
|
21713
22044
|
projectIndex,
|
|
21714
22045
|
bodies,
|
|
22046
|
+
contexts,
|
|
21715
22047
|
diagnostics
|
|
21716
22048
|
});
|
|
21717
22049
|
continue;
|
|
@@ -21736,15 +22068,24 @@ function compileProjectSourceBodies(documents) {
|
|
|
21736
22068
|
context: { ...baseContext2, kind: unit },
|
|
21737
22069
|
projectIndex,
|
|
21738
22070
|
bodies,
|
|
22071
|
+
contexts,
|
|
21739
22072
|
diagnostics
|
|
21740
22073
|
});
|
|
21741
22074
|
}
|
|
21742
22075
|
}
|
|
21743
22076
|
}
|
|
21744
22077
|
}
|
|
21745
|
-
return { project: graph.project, bodies, diagnostics };
|
|
22078
|
+
return { project: graph.project, bodies, contexts, diagnostics };
|
|
21746
22079
|
}
|
|
21747
22080
|
function compileBody(args) {
|
|
22081
|
+
args.contexts.push({
|
|
22082
|
+
uri: args.uri,
|
|
22083
|
+
ownerName: args.owner.declaration.name,
|
|
22084
|
+
memberName: args.memberName,
|
|
22085
|
+
unit: args.unit,
|
|
22086
|
+
range: args.range,
|
|
22087
|
+
context: args.context
|
|
22088
|
+
});
|
|
21748
22089
|
const source = new SourceText(args.document.sourceText);
|
|
21749
22090
|
const start = source.offsetAt(args.range.start);
|
|
21750
22091
|
const end = source.offsetAt(args.range.end);
|
|
@@ -24064,6 +24405,7 @@ function analyzeNeoProjectSources(inputs, parsedDocuments = /* @__PURE__ */ new
|
|
|
24064
24405
|
symbols,
|
|
24065
24406
|
project: bodyCompilation.project,
|
|
24066
24407
|
compiledBodies: bodyCompilation.bodies,
|
|
24408
|
+
bodyContexts: bodyCompilation.contexts,
|
|
24067
24409
|
diagnostics
|
|
24068
24410
|
};
|
|
24069
24411
|
}
|
|
@@ -24891,9 +25233,25 @@ var init_quick_fixes = __esm({
|
|
|
24891
25233
|
|
|
24892
25234
|
// ../packages/neoscript-language/src/project-source-language-features.ts
|
|
24893
25235
|
function projectDiagnostics(analysis, uri) {
|
|
24894
|
-
return analysis.diagnostics.filter((diagnostic) => diagnostic.uri === uri).map((
|
|
25236
|
+
return analysis.diagnostics.filter((diagnostic) => diagnostic.uri === uri).map((diagnostic) => ({
|
|
25237
|
+
range: diagnostic.range,
|
|
25238
|
+
severity: diagnostic.severity,
|
|
25239
|
+
message: diagnostic.message,
|
|
25240
|
+
...diagnostic.code === void 0 ? {} : { code: diagnostic.code },
|
|
25241
|
+
...diagnostic.source === void 0 ? {} : { source: diagnostic.source },
|
|
25242
|
+
...diagnostic.relatedInformation === void 0 ? {} : { relatedInformation: diagnostic.relatedInformation },
|
|
25243
|
+
...diagnostic.suggestions === void 0 ? {} : { suggestions: diagnostic.suggestions }
|
|
25244
|
+
}));
|
|
24895
25245
|
}
|
|
24896
25246
|
function projectCompletions(analysis, document, position) {
|
|
25247
|
+
const body = projectBodySnapshotAt(analysis, document, position);
|
|
25248
|
+
if (body) return complete(body, position);
|
|
25249
|
+
const annotations = projectAnnotationCompletions(
|
|
25250
|
+
analysis,
|
|
25251
|
+
document,
|
|
25252
|
+
position
|
|
25253
|
+
);
|
|
25254
|
+
if (annotations) return { isIncomplete: false, items: annotations };
|
|
24897
25255
|
const members = projectMemberCompletions(analysis, document, position);
|
|
24898
25256
|
if (members) {
|
|
24899
25257
|
return {
|
|
@@ -24978,13 +25336,126 @@ function projectCompletions(analysis, document, position) {
|
|
|
24978
25336
|
if (initializerMembers) {
|
|
24979
25337
|
return { isIncomplete: false, items: initializerMembers };
|
|
24980
25338
|
}
|
|
25339
|
+
const contextualEnum = projectContextualEnumCompletions(
|
|
25340
|
+
analysis,
|
|
25341
|
+
document,
|
|
25342
|
+
position
|
|
25343
|
+
);
|
|
25344
|
+
if (contextualEnum) {
|
|
25345
|
+
return { isIncomplete: false, items: contextualEnum };
|
|
25346
|
+
}
|
|
25347
|
+
return projectFallbackCompletions(analysis, document, position);
|
|
25348
|
+
}
|
|
25349
|
+
function projectAnnotationCompletions(analysis, document, position) {
|
|
25350
|
+
const source = new SourceText(document.text);
|
|
25351
|
+
const offset = source.offsetAt(position);
|
|
25352
|
+
const word = projectWordRange(document.text, offset);
|
|
25353
|
+
if (document.text[word.start - 1] !== "@") return null;
|
|
25354
|
+
if (initializerRootAt(analysis, document, position)) return [];
|
|
25355
|
+
const names = projectAnnotationNamesAt(analysis, document, position);
|
|
25356
|
+
return names.map((name) => ({
|
|
25357
|
+
label: `@${name}`,
|
|
25358
|
+
kind: "snippet",
|
|
25359
|
+
insertText: name,
|
|
25360
|
+
textEdit: {
|
|
25361
|
+
range: source.range(word.start, word.end),
|
|
25362
|
+
newText: name
|
|
25363
|
+
}
|
|
25364
|
+
}));
|
|
25365
|
+
}
|
|
25366
|
+
function projectAnnotationNamesAt(analysis, document, position) {
|
|
25367
|
+
const source = analysis.documents.get(document.uri);
|
|
25368
|
+
if (!source) return [];
|
|
25369
|
+
if (document.languageId === "neoflow") {
|
|
25370
|
+
return ["id", "primary", "incomplete"];
|
|
25371
|
+
}
|
|
25372
|
+
const offset = new SourceText(document.text).offsetAt(position);
|
|
25373
|
+
const followingDeclaration = /^\s*(class|interface|enum)\b([^{}]*)/.exec(
|
|
25374
|
+
document.text.slice(offset)
|
|
25375
|
+
);
|
|
25376
|
+
if (followingDeclaration?.[1] === "class") {
|
|
25377
|
+
return [
|
|
25378
|
+
"id",
|
|
25379
|
+
"hidden",
|
|
25380
|
+
"settings",
|
|
25381
|
+
"storage",
|
|
25382
|
+
"relations",
|
|
25383
|
+
.../\bDialogue\b/.test(followingDeclaration[2] ?? "") ? ["incomplete"] : []
|
|
25384
|
+
];
|
|
25385
|
+
}
|
|
25386
|
+
if (followingDeclaration) return ["id"];
|
|
25387
|
+
const containing = declarationContaining(source, position);
|
|
25388
|
+
if (containing?.kind === "enum") return ["id"];
|
|
25389
|
+
if (containing?.kind === "class" || containing?.kind === "interface") {
|
|
25390
|
+
if (positionCompare(position, containing.nameRange.start) < 0) {
|
|
25391
|
+
return projectDeclarationAnnotationNames(containing);
|
|
25392
|
+
}
|
|
25393
|
+
const member = containing.members.find(
|
|
25394
|
+
(candidate) => rangeContains(candidate.range, position) || positionCompare(position, candidate.range.start) <= 0
|
|
25395
|
+
);
|
|
25396
|
+
return projectMemberAnnotationNames(member);
|
|
25397
|
+
}
|
|
25398
|
+
const following = source.declarations.find(
|
|
25399
|
+
(declaration) => positionCompare(position, declaration.range.start) <= 0
|
|
25400
|
+
);
|
|
25401
|
+
if (following) return projectDeclarationAnnotationNames(following);
|
|
25402
|
+
return ["id"];
|
|
25403
|
+
}
|
|
25404
|
+
function projectDeclarationAnnotationNames(declaration) {
|
|
25405
|
+
if (declaration.kind !== "class") return ["id"];
|
|
25406
|
+
return [
|
|
25407
|
+
"id",
|
|
25408
|
+
"hidden",
|
|
25409
|
+
"settings",
|
|
25410
|
+
"storage",
|
|
25411
|
+
"relations",
|
|
25412
|
+
...declaration.baseTypes.some((type) => type.name === "Dialogue") ? ["incomplete"] : []
|
|
25413
|
+
];
|
|
25414
|
+
}
|
|
25415
|
+
function projectMemberAnnotationNames(member) {
|
|
25416
|
+
const names = ["id", "settings", "storage", "locked"];
|
|
25417
|
+
if (member?.type.name === "List") names.push("index", "column");
|
|
25418
|
+
return names;
|
|
25419
|
+
}
|
|
25420
|
+
function projectContextualEnumCompletions(analysis, document, position) {
|
|
25421
|
+
const source = new SourceText(document.text);
|
|
25422
|
+
const offset = source.offsetAt(position);
|
|
25423
|
+
const word = projectWordRange(document.text, offset);
|
|
25424
|
+
if (!isContextualDot(document.text, word.start)) return null;
|
|
25425
|
+
const typeName = constructionSiteAt(
|
|
25426
|
+
analysis,
|
|
25427
|
+
document,
|
|
25428
|
+
position
|
|
25429
|
+
)?.expectedTypeName;
|
|
25430
|
+
if (!typeName) return null;
|
|
25431
|
+
const type = analysis.project.types.find(
|
|
25432
|
+
(candidate) => candidate.kind === "enum" && candidate.name === typeName
|
|
25433
|
+
);
|
|
25434
|
+
if (!type) return null;
|
|
25435
|
+
return type.members.filter((member) => member.kind === "enumMember").map((member) => ({
|
|
25436
|
+
label: `.${member.name}`,
|
|
25437
|
+
kind: "enumMember",
|
|
25438
|
+
detail: type.name,
|
|
25439
|
+
insertText: member.name,
|
|
25440
|
+
textEdit: {
|
|
25441
|
+
range: source.range(word.start, word.end),
|
|
25442
|
+
newText: member.name
|
|
25443
|
+
},
|
|
25444
|
+
symbolId: member.id
|
|
25445
|
+
}));
|
|
25446
|
+
}
|
|
25447
|
+
function projectFallbackCompletions(analysis, document, position) {
|
|
24981
25448
|
const items = /* @__PURE__ */ new Map();
|
|
24982
|
-
|
|
24983
|
-
|
|
24984
|
-
|
|
24985
|
-
|
|
24986
|
-
|
|
24987
|
-
|
|
25449
|
+
const construction = constructionSiteAt(analysis, document, position);
|
|
25450
|
+
const recoveredInitializerType = projectInitializerExpectedTypeNameAt(
|
|
25451
|
+
document,
|
|
25452
|
+
position
|
|
25453
|
+
);
|
|
25454
|
+
const expression = construction !== null || recoveredInitializerType !== null;
|
|
25455
|
+
const expectedTypeName = construction?.expectedTypeName ?? recoveredInitializerType;
|
|
25456
|
+
const afterNew = expression && projectAfterNewAt(document, position);
|
|
25457
|
+
const typePosition = projectTypePositionAt(analysis, document, position);
|
|
25458
|
+
const keywords = expression ? afterNew ? [] : ["new"] : typePosition ? [] : [
|
|
24988
25459
|
"class",
|
|
24989
25460
|
"interface",
|
|
24990
25461
|
"enum",
|
|
@@ -24994,16 +25465,20 @@ function projectCompletions(analysis, document, position) {
|
|
|
24994
25465
|
"override",
|
|
24995
25466
|
"readonly",
|
|
24996
25467
|
"virtual",
|
|
24997
|
-
"static"
|
|
24998
|
-
|
|
24999
|
-
|
|
25468
|
+
"static"
|
|
25469
|
+
];
|
|
25470
|
+
for (const keyword of keywords) {
|
|
25000
25471
|
items.set(keyword, {
|
|
25001
25472
|
label: keyword,
|
|
25002
|
-
kind:
|
|
25473
|
+
kind: "keyword",
|
|
25003
25474
|
insertText: keyword
|
|
25004
25475
|
});
|
|
25005
25476
|
}
|
|
25006
|
-
for (const typeName of
|
|
25477
|
+
for (const typeName of [
|
|
25478
|
+
...NEOSCRIPT_PRIMITIVE_TYPES,
|
|
25479
|
+
...NEOSCRIPT_BUILTIN_TYPES
|
|
25480
|
+
]) {
|
|
25481
|
+
if (expression) continue;
|
|
25007
25482
|
items.set(typeName, {
|
|
25008
25483
|
label: typeName,
|
|
25009
25484
|
kind: "class",
|
|
@@ -25011,10 +25486,31 @@ function projectCompletions(analysis, document, position) {
|
|
|
25011
25486
|
insertText: typeName
|
|
25012
25487
|
});
|
|
25013
25488
|
}
|
|
25489
|
+
const source = analysis.documents.get(document.uri);
|
|
25490
|
+
const owner = source ? declarationContaining(source, position)?.name : void 0;
|
|
25014
25491
|
for (const symbol of analysis.symbols) {
|
|
25015
25492
|
if (symbol.scopeRange && (symbol.location.uri !== document.uri || !rangeContains(symbol.scopeRange, position))) {
|
|
25016
25493
|
continue;
|
|
25017
25494
|
}
|
|
25495
|
+
const isType = symbol.kind === "class" || symbol.kind === "interface" || symbol.kind === "enum" || symbol.kind === "genericParameter";
|
|
25496
|
+
if (typePosition && !isType) continue;
|
|
25497
|
+
if (expression) {
|
|
25498
|
+
if (afterNew) {
|
|
25499
|
+
if (!isType || symbol.kind !== "class" || expectedTypeName !== null && !projectTypeNameAssignable(analysis, symbol.name, expectedTypeName)) {
|
|
25500
|
+
continue;
|
|
25501
|
+
}
|
|
25502
|
+
} else {
|
|
25503
|
+
const isValue = symbol.kind === "parameter" || symbol.kind === "flowBinding" || symbol.kind === "graphChild" || symbol.kind === "global" || symbol.kind === "member" && symbol.ownerName === owner;
|
|
25504
|
+
if (!isValue) continue;
|
|
25505
|
+
if (expectedTypeName !== null && (symbol.detail === void 0 || !projectTypeNameAssignable(
|
|
25506
|
+
analysis,
|
|
25507
|
+
symbol.detail,
|
|
25508
|
+
expectedTypeName
|
|
25509
|
+
))) {
|
|
25510
|
+
continue;
|
|
25511
|
+
}
|
|
25512
|
+
}
|
|
25513
|
+
}
|
|
25018
25514
|
const kind = projectCompletionKind(symbol);
|
|
25019
25515
|
items.set(symbol.name, {
|
|
25020
25516
|
label: symbol.name,
|
|
@@ -25026,6 +25522,168 @@ function projectCompletions(analysis, document, position) {
|
|
|
25026
25522
|
}
|
|
25027
25523
|
return { isIncomplete: false, items: [...items.values()] };
|
|
25028
25524
|
}
|
|
25525
|
+
function projectInitializerExpectedTypeNameAt(document, position) {
|
|
25526
|
+
const prefix = documentPrefix(document.text, position);
|
|
25527
|
+
const line = prefix.slice(prefix.lastIndexOf("\n") + 1);
|
|
25528
|
+
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(
|
|
25529
|
+
line
|
|
25530
|
+
)?.[1] ?? null;
|
|
25531
|
+
}
|
|
25532
|
+
function projectAfterNewAt(document, position) {
|
|
25533
|
+
const tokens = tokensBeforePosition(document.text, position);
|
|
25534
|
+
let cursor = tokens.length - 1;
|
|
25535
|
+
const current = tokens[cursor];
|
|
25536
|
+
const offset = new SourceText(document.text).offsetAt(position);
|
|
25537
|
+
if (current?.kind === "identifier" && current.text !== "new" && /[A-Za-z0-9_]$/.test(document.text.slice(0, offset))) {
|
|
25538
|
+
cursor--;
|
|
25539
|
+
}
|
|
25540
|
+
return tokens[cursor]?.text === "new";
|
|
25541
|
+
}
|
|
25542
|
+
function projectTypeNameAssignable(analysis, sourceName, targetName) {
|
|
25543
|
+
if (sourceName === targetName) return true;
|
|
25544
|
+
if (sourceName === "int" && (targetName === "float" || targetName === "decimal")) {
|
|
25545
|
+
return true;
|
|
25546
|
+
}
|
|
25547
|
+
const source = analysis.project.types.find(
|
|
25548
|
+
(type) => type.name === sourceName
|
|
25549
|
+
);
|
|
25550
|
+
const target = analysis.project.types.find(
|
|
25551
|
+
(type) => type.name === targetName
|
|
25552
|
+
);
|
|
25553
|
+
if (!source || !target) return false;
|
|
25554
|
+
const visited = /* @__PURE__ */ new Set();
|
|
25555
|
+
const derivesFrom = (typeId) => {
|
|
25556
|
+
if (typeId === target.id) return true;
|
|
25557
|
+
if (visited.has(typeId)) return false;
|
|
25558
|
+
visited.add(typeId);
|
|
25559
|
+
const type = analysis.project.types.find(
|
|
25560
|
+
(candidate) => candidate.id === typeId
|
|
25561
|
+
);
|
|
25562
|
+
return [
|
|
25563
|
+
...type?.baseTypeIds ?? [],
|
|
25564
|
+
...type?.interfaceTypeIds ?? []
|
|
25565
|
+
].some(derivesFrom);
|
|
25566
|
+
};
|
|
25567
|
+
return derivesFrom(source.id);
|
|
25568
|
+
}
|
|
25569
|
+
function projectBodySnapshotAt(analysis, document, position) {
|
|
25570
|
+
const body = analysis.bodyContexts.find(
|
|
25571
|
+
(candidate) => candidate.uri === document.uri && rangeContains(candidate.range, position)
|
|
25572
|
+
);
|
|
25573
|
+
return body ? projectBodySnapshot(analysis, document, body) : null;
|
|
25574
|
+
}
|
|
25575
|
+
function projectBodySnapshot(analysis, document, body) {
|
|
25576
|
+
let snapshots = PROJECT_BODY_SNAPSHOT_CACHE.get(analysis);
|
|
25577
|
+
if (!snapshots) {
|
|
25578
|
+
snapshots = /* @__PURE__ */ new Map();
|
|
25579
|
+
PROJECT_BODY_SNAPSHOT_CACHE.set(analysis, snapshots);
|
|
25580
|
+
}
|
|
25581
|
+
const cached = snapshots.get(body);
|
|
25582
|
+
if (cached) return cached;
|
|
25583
|
+
const source = new SourceText(document.text);
|
|
25584
|
+
const start = source.offsetAt(body.range.start);
|
|
25585
|
+
const end = source.offsetAt(body.range.end);
|
|
25586
|
+
const text = maskOutsideProjectBody(document.text, start, end);
|
|
25587
|
+
const syntax = analyzeNeoScriptSyntax(text, body.context.kind);
|
|
25588
|
+
const context = { ...body.context, project: analysis.project };
|
|
25589
|
+
const snapshot = {
|
|
25590
|
+
uri: document.uri,
|
|
25591
|
+
source: syntax.lexed.source,
|
|
25592
|
+
lexed: syntax.lexed,
|
|
25593
|
+
parsed: syntax.parsed,
|
|
25594
|
+
context,
|
|
25595
|
+
project: buildProjectIndexWithBuiltins(context)
|
|
25596
|
+
};
|
|
25597
|
+
snapshots.set(body, snapshot);
|
|
25598
|
+
return snapshot;
|
|
25599
|
+
}
|
|
25600
|
+
function maskOutsideProjectBody(text, start, end) {
|
|
25601
|
+
let masked = "";
|
|
25602
|
+
for (let index = 0; index < text.length; index++) {
|
|
25603
|
+
const character = text[index] ?? "";
|
|
25604
|
+
masked += index >= start && index < end || character === "\n" || character === "\r" ? character : " ";
|
|
25605
|
+
}
|
|
25606
|
+
return masked;
|
|
25607
|
+
}
|
|
25608
|
+
function projectWordRange(text, offset) {
|
|
25609
|
+
let start = offset;
|
|
25610
|
+
let end = offset;
|
|
25611
|
+
while (start > 0 && /[A-Za-z0-9_]/.test(text[start - 1] ?? "")) start--;
|
|
25612
|
+
while (end < text.length && /[A-Za-z0-9_]/.test(text[end] ?? "")) end++;
|
|
25613
|
+
return { start, end };
|
|
25614
|
+
}
|
|
25615
|
+
function isContextualDot(text, wordStart) {
|
|
25616
|
+
if (text[wordStart - 1] !== ".") return false;
|
|
25617
|
+
let cursor = wordStart - 2;
|
|
25618
|
+
while (cursor >= 0 && /\s/.test(text[cursor] ?? "")) cursor--;
|
|
25619
|
+
const beforeDot = text[cursor];
|
|
25620
|
+
if (beforeDot !== void 0 && /[A-Za-z0-9_]/.test(beforeDot)) {
|
|
25621
|
+
const precedingWord = /[A-Za-z_][A-Za-z0-9_]*$/.exec(
|
|
25622
|
+
text.slice(0, cursor + 1)
|
|
25623
|
+
)?.[0];
|
|
25624
|
+
return precedingWord === "return" || precedingWord === "case";
|
|
25625
|
+
}
|
|
25626
|
+
return beforeDot === void 0 || !/[A-Za-z0-9_\])}]/.test(beforeDot);
|
|
25627
|
+
}
|
|
25628
|
+
function projectTypePositionAt(analysis, document, position) {
|
|
25629
|
+
const source = analysis.documents.get(document.uri);
|
|
25630
|
+
if (source && sourceTypeAt(source, position)) return true;
|
|
25631
|
+
const prefix = documentPrefix(document.text, position);
|
|
25632
|
+
const line = prefix.slice(prefix.lastIndexOf("\n") + 1);
|
|
25633
|
+
return /(?:^|[{:;,])\s*(?:(?:public|protected|private|abstract|async|native|override|readonly|sealed|static|virtual)\s+)*[A-Za-z_][A-Za-z0-9_]*(?:\s*<[^;={}()]*)?$/.test(
|
|
25634
|
+
line
|
|
25635
|
+
);
|
|
25636
|
+
}
|
|
25637
|
+
function sourceTypeAt(document, position) {
|
|
25638
|
+
const contains2 = (type) => {
|
|
25639
|
+
for (const argument2 of type.typeArguments) {
|
|
25640
|
+
const nested = contains2(argument2);
|
|
25641
|
+
if (nested) return nested;
|
|
25642
|
+
}
|
|
25643
|
+
return rangeContains(type.range, position) ? type : null;
|
|
25644
|
+
};
|
|
25645
|
+
const parameterType = (parameters) => {
|
|
25646
|
+
for (const parameter4 of parameters ?? []) {
|
|
25647
|
+
const match = contains2(parameter4.type);
|
|
25648
|
+
if (match) return match;
|
|
25649
|
+
}
|
|
25650
|
+
return null;
|
|
25651
|
+
};
|
|
25652
|
+
for (const declaration of document.declarations) {
|
|
25653
|
+
if (declaration.kind === "global") {
|
|
25654
|
+
const match = contains2(declaration.type);
|
|
25655
|
+
if (match) return match;
|
|
25656
|
+
continue;
|
|
25657
|
+
}
|
|
25658
|
+
if (declaration.kind === "enum") continue;
|
|
25659
|
+
for (const base of declaration.baseTypes) {
|
|
25660
|
+
const match = contains2(base);
|
|
25661
|
+
if (match) return match;
|
|
25662
|
+
}
|
|
25663
|
+
if (declaration.kind === "class") {
|
|
25664
|
+
const header = parameterType(declaration.headerParameters);
|
|
25665
|
+
if (header) return header;
|
|
25666
|
+
for (const generic of declaration.genericParameters) {
|
|
25667
|
+
if (!generic.constraint) continue;
|
|
25668
|
+
const match = contains2(generic.constraint);
|
|
25669
|
+
if (match) return match;
|
|
25670
|
+
}
|
|
25671
|
+
for (const constructor2 of declaration.constructors) {
|
|
25672
|
+
const match = parameterType(constructor2.parameters);
|
|
25673
|
+
if (match) return match;
|
|
25674
|
+
}
|
|
25675
|
+
}
|
|
25676
|
+
for (const member of declaration.members) {
|
|
25677
|
+
const memberType2 = contains2(member.type);
|
|
25678
|
+
if (memberType2) return memberType2;
|
|
25679
|
+
if (member.kind === "function") {
|
|
25680
|
+
const match = parameterType(member.parameters);
|
|
25681
|
+
if (match) return match;
|
|
25682
|
+
}
|
|
25683
|
+
}
|
|
25684
|
+
}
|
|
25685
|
+
return null;
|
|
25686
|
+
}
|
|
25029
25687
|
function projectMemberCompletions(analysis, document, position) {
|
|
25030
25688
|
const tokens = projectTokens(document).filter(
|
|
25031
25689
|
(token) => token.kind !== "eof" && token.kind !== "comment" && positionCompare(token.range.start, position) <= 0
|
|
@@ -25263,6 +25921,8 @@ function activeNamedArgument(text, position) {
|
|
|
25263
25921
|
return /([A-Za-z_][A-Za-z0-9_]*)\s*:\s*\.[A-Za-z0-9_]*$/.exec(prefix)?.[1] ?? null;
|
|
25264
25922
|
}
|
|
25265
25923
|
function projectHover(analysis, document, position) {
|
|
25924
|
+
const body = projectBodySnapshotAt(analysis, document, position);
|
|
25925
|
+
if (body) return hover(body, position);
|
|
25266
25926
|
const resolved = projectSymbolAt(analysis, document, position);
|
|
25267
25927
|
if (!resolved) return null;
|
|
25268
25928
|
const owner = resolved.symbol.ownerName ? ` on \`${resolved.symbol.ownerName}\`` : "";
|
|
@@ -25310,6 +25970,8 @@ Construct with \`new(${parameters})\` \u2014 this class declares a required cons
|
|
|
25310
25970
|
${lines.join("\n\n")}`;
|
|
25311
25971
|
}
|
|
25312
25972
|
function projectDefinition(analysis, document, position) {
|
|
25973
|
+
const body = projectBodySnapshotAt(analysis, document, position);
|
|
25974
|
+
if (body) return definition(body, position);
|
|
25313
25975
|
const resolved = projectSymbolAt(analysis, document, position);
|
|
25314
25976
|
return resolved ? [resolved.symbol.location] : [];
|
|
25315
25977
|
}
|
|
@@ -25376,6 +26038,8 @@ function requiredDestinationEdit(document, initializer, destination) {
|
|
|
25376
26038
|
return open && close ? trailingBlockReturnEdit(document.text, open, close, destination) : null;
|
|
25377
26039
|
}
|
|
25378
26040
|
function projectSignatureHelp(analysis, document, position) {
|
|
26041
|
+
const body = projectBodySnapshotAt(analysis, document, position);
|
|
26042
|
+
if (body) return signatureHelp(body, position);
|
|
25379
26043
|
const tokens = tokensBeforePosition(document.text, position);
|
|
25380
26044
|
const openIndex = activeCallOpenIndex(tokens, position);
|
|
25381
26045
|
if (openIndex < 0) return null;
|
|
@@ -25437,6 +26101,9 @@ function projectSignatureHelp(analysis, document, position) {
|
|
|
25437
26101
|
};
|
|
25438
26102
|
}
|
|
25439
26103
|
function projectInlayHints(analysis, document, range2) {
|
|
26104
|
+
const bodyContexts = analysis.bodyContexts.filter(
|
|
26105
|
+
(body) => body.uri === document.uri
|
|
26106
|
+
);
|
|
25440
26107
|
const tokens = lex(document.text).tokens.filter(
|
|
25441
26108
|
(token) => token.kind !== "comment" && token.kind !== "eof"
|
|
25442
26109
|
);
|
|
@@ -25451,6 +26118,9 @@ function projectInlayHints(analysis, document, range2) {
|
|
|
25451
26118
|
if (!callee || callee.kind !== "identifier" && callee.kind !== "type") {
|
|
25452
26119
|
continue;
|
|
25453
26120
|
}
|
|
26121
|
+
if (bodyContexts.some((body) => rangeContains(body.range, callee.range.start))) {
|
|
26122
|
+
continue;
|
|
26123
|
+
}
|
|
25454
26124
|
if (!open || open.text !== "(") continue;
|
|
25455
26125
|
const beforeCallee = tokens[index - 1];
|
|
25456
26126
|
if (beforeCallee?.text === "@") continue;
|
|
@@ -25477,6 +26147,14 @@ function projectInlayHints(analysis, document, range2) {
|
|
|
25477
26147
|
});
|
|
25478
26148
|
}
|
|
25479
26149
|
}
|
|
26150
|
+
for (const body of bodyContexts) {
|
|
26151
|
+
const snapshot = projectBodySnapshot(analysis, document, body);
|
|
26152
|
+
hints.push(
|
|
26153
|
+
...inlayHints(snapshot, range2).filter(
|
|
26154
|
+
(hint) => rangeContains(body.range, hint.position)
|
|
26155
|
+
)
|
|
26156
|
+
);
|
|
26157
|
+
}
|
|
25480
26158
|
return hints;
|
|
25481
26159
|
}
|
|
25482
26160
|
function projectCallParameterNames(analysis, document, callee, beforeCallee) {
|
|
@@ -25678,8 +26356,14 @@ function symbolsDeclaredAt(index, uri, range2) {
|
|
|
25678
26356
|
function projectSemanticTokens(document, analysis) {
|
|
25679
26357
|
const index = buildProjectSymbolIndex(analysis.symbols);
|
|
25680
26358
|
const tokens = projectTokens(document);
|
|
25681
|
-
|
|
26359
|
+
const bodyContexts = analysis.bodyContexts.filter(
|
|
26360
|
+
(body) => body.uri === document.uri
|
|
26361
|
+
);
|
|
26362
|
+
const result = tokens.flatMap((token, tokenIndex) => {
|
|
25682
26363
|
if (token.kind === "eof" || token.kind === "error") return [];
|
|
26364
|
+
if (bodyContexts.some((body) => rangeContains(body.range, token.range.start))) {
|
|
26365
|
+
return [];
|
|
26366
|
+
}
|
|
25683
26367
|
const declaration = symbolsDeclaredAt(index, document.uri, token.range)[0];
|
|
25684
26368
|
const resolved = token.kind === "identifier" ? indexedProjectSymbolAt(analysis, document, token.range.start, index)?.symbol : void 0;
|
|
25685
26369
|
let type;
|
|
@@ -25706,6 +26390,17 @@ function projectSemanticTokens(document, analysis) {
|
|
|
25706
26390
|
}
|
|
25707
26391
|
];
|
|
25708
26392
|
});
|
|
26393
|
+
for (const body of bodyContexts) {
|
|
26394
|
+
const snapshot = projectBodySnapshot(analysis, document, body);
|
|
26395
|
+
result.push(
|
|
26396
|
+
...semanticTokens(snapshot).filter(
|
|
26397
|
+
(token) => rangeContains(body.range, token.range.start)
|
|
26398
|
+
)
|
|
26399
|
+
);
|
|
26400
|
+
}
|
|
26401
|
+
return result.sort(
|
|
26402
|
+
(left, right) => positionCompare(left.range.start, right.range.start)
|
|
26403
|
+
);
|
|
25709
26404
|
}
|
|
25710
26405
|
function isProjectContextualKeyword(tokens, tokenIndex) {
|
|
25711
26406
|
const token = tokens[tokenIndex];
|
|
@@ -25730,6 +26425,17 @@ function indexedProjectSymbolAt(analysis, document, position, index) {
|
|
|
25730
26425
|
if (exact.length === 1) return { token, symbol: exact[0] };
|
|
25731
26426
|
const candidates = index.byName.get(token.text) ?? [];
|
|
25732
26427
|
if (candidates.length === 0) return null;
|
|
26428
|
+
const sourceTokens = projectTokens(document);
|
|
26429
|
+
const tokenIndex = sourceTokens.findIndex(
|
|
26430
|
+
(candidate) => candidate.start === token.start && candidate.end === token.end
|
|
26431
|
+
);
|
|
26432
|
+
const source = analysis.documents.get(document.uri);
|
|
26433
|
+
if (source && sourceTypeAt(source, token.range.start) || sourceTokens[tokenIndex - 1]?.text === "new") {
|
|
26434
|
+
const types = candidates.filter(
|
|
26435
|
+
(symbol) => symbol.kind === "class" || symbol.kind === "interface" || symbol.kind === "enum" || symbol.kind === "genericParameter"
|
|
26436
|
+
);
|
|
26437
|
+
if (types.length === 1) return { token, symbol: types[0] };
|
|
26438
|
+
}
|
|
25733
26439
|
const scoped = candidates.filter(
|
|
25734
26440
|
(symbol) => symbol.scopeRange && symbol.location.uri === document.uri && rangeContains(symbol.scopeRange, token.range.start)
|
|
25735
26441
|
).sort(
|
|
@@ -25741,10 +26447,6 @@ function indexedProjectSymbolAt(analysis, document, position, index) {
|
|
|
25741
26447
|
return { token, symbol: visibleCandidates[0] };
|
|
25742
26448
|
}
|
|
25743
26449
|
if (visibleCandidates.length === 0) return null;
|
|
25744
|
-
const sourceTokens = projectTokens(document);
|
|
25745
|
-
const tokenIndex = sourceTokens.findIndex(
|
|
25746
|
-
(candidate) => candidate.start === token.start && candidate.end === token.end
|
|
25747
|
-
);
|
|
25748
26450
|
if (sourceTokens[tokenIndex + 1]?.text === "=" && sourceTokens[tokenIndex + 2]?.text !== "=") {
|
|
25749
26451
|
const constructed = constructionMemberSymbol(
|
|
25750
26452
|
analysis,
|
|
@@ -25754,7 +26456,6 @@ function indexedProjectSymbolAt(analysis, document, position, index) {
|
|
|
25754
26456
|
);
|
|
25755
26457
|
if (constructed) return { token, symbol: constructed };
|
|
25756
26458
|
}
|
|
25757
|
-
const source = analysis.documents.get(document.uri);
|
|
25758
26459
|
const owner = source ? declarationContaining(source, token.range.start)?.name : void 0;
|
|
25759
26460
|
if (owner) {
|
|
25760
26461
|
const owned = visibleCandidates.filter(
|
|
@@ -26273,10 +26974,11 @@ function projectFunctionsNamed(analysis, name) {
|
|
|
26273
26974
|
}
|
|
26274
26975
|
return result;
|
|
26275
26976
|
}
|
|
26276
|
-
var CONSTRUCTION_INDEX_CACHE;
|
|
26977
|
+
var PROJECT_BODY_SNAPSHOT_CACHE, CONSTRUCTION_INDEX_CACHE;
|
|
26277
26978
|
var init_project_source_language_features = __esm({
|
|
26278
26979
|
"../packages/neoscript-language/src/project-source-language-features.ts"() {
|
|
26279
26980
|
"use strict";
|
|
26981
|
+
init_analyzer();
|
|
26280
26982
|
init_lexer();
|
|
26281
26983
|
init_language_spec();
|
|
26282
26984
|
init_project_source_semantics();
|
|
@@ -26284,6 +26986,8 @@ var init_project_source_language_features = __esm({
|
|
|
26284
26986
|
init_project_source_tokens();
|
|
26285
26987
|
init_quick_fixes();
|
|
26286
26988
|
init_source_text();
|
|
26989
|
+
init_syntax();
|
|
26990
|
+
PROJECT_BODY_SNAPSHOT_CACHE = /* @__PURE__ */ new WeakMap();
|
|
26287
26991
|
CONSTRUCTION_INDEX_CACHE = /* @__PURE__ */ new WeakMap();
|
|
26288
26992
|
}
|
|
26289
26993
|
});
|
|
@@ -42908,6 +43612,7 @@ function evaluateLiteralContainer(args) {
|
|
|
42908
43612
|
}
|
|
42909
43613
|
return {
|
|
42910
43614
|
literal: literal2,
|
|
43615
|
+
...evaluated.genericBindings === void 0 ? {} : { genericBindings: evaluated.genericBindings },
|
|
42911
43616
|
...evaluated.provisionalRootId === void 0 ? {} : { provisionalRootId: evaluated.provisionalRootId },
|
|
42912
43617
|
...evaluated.existingValueRow === void 0 ? {} : { existingValueRow: evaluated.existingValueRow }
|
|
42913
43618
|
};
|
|
@@ -42930,6 +43635,9 @@ function buildDefaultMemberValue(args) {
|
|
|
42930
43635
|
return evaluated.existingValueRow;
|
|
42931
43636
|
}
|
|
42932
43637
|
const value2 = buildNewValue(args.projectId, evaluated.literal);
|
|
43638
|
+
if (evaluated.genericBindings !== void 0) {
|
|
43639
|
+
value2.genericBindings = { ...evaluated.genericBindings };
|
|
43640
|
+
}
|
|
42933
43641
|
if (evaluated.provisionalRootId !== void 0) {
|
|
42934
43642
|
retargetDelegateReceiverValueIds(
|
|
42935
43643
|
[value2, ...args.createdValues],
|
|
@@ -43316,6 +44024,9 @@ function cloneDefaultValueForMember(args) {
|
|
|
43316
44024
|
return evaluated.existingValueRow;
|
|
43317
44025
|
}
|
|
43318
44026
|
const evaluatedRow = buildNewValue(args.projectId, evaluated.literal);
|
|
44027
|
+
if (evaluated.genericBindings !== void 0) {
|
|
44028
|
+
evaluatedRow.genericBindings = { ...evaluated.genericBindings };
|
|
44029
|
+
}
|
|
43319
44030
|
if (evaluated.provisionalRootId !== void 0) {
|
|
43320
44031
|
retargetDelegateReceiverValueIds(
|
|
43321
44032
|
[evaluatedRow, ...args.createdValues],
|
|
@@ -50450,15 +51161,14 @@ function commentEndIndex(source, index) {
|
|
|
50450
51161
|
return null;
|
|
50451
51162
|
}
|
|
50452
51163
|
function stripInitializerComments(source) {
|
|
50453
|
-
const lines = [{
|
|
51164
|
+
const lines = [{ parts: [], removedComment: false }];
|
|
50454
51165
|
let quote6 = null;
|
|
50455
51166
|
let escaped = false;
|
|
50456
51167
|
let index = 0;
|
|
51168
|
+
let segmentStart = 0;
|
|
50457
51169
|
while (index < source.length) {
|
|
50458
51170
|
const character = source[index];
|
|
50459
|
-
const line = lines[lines.length - 1];
|
|
50460
51171
|
if (quote6 !== null) {
|
|
50461
|
-
line.text += character;
|
|
50462
51172
|
if (escaped) escaped = false;
|
|
50463
51173
|
else if (character === "\\") escaped = true;
|
|
50464
51174
|
else if (character === quote6) quote6 = null;
|
|
@@ -50467,20 +51177,34 @@ function stripInitializerComments(source) {
|
|
|
50467
51177
|
}
|
|
50468
51178
|
const afterComment = commentEndIndex(source, index);
|
|
50469
51179
|
if (afterComment !== null) {
|
|
51180
|
+
const line = lines[lines.length - 1];
|
|
51181
|
+
if (segmentStart < index) {
|
|
51182
|
+
line.parts.push(source.slice(segmentStart, index));
|
|
51183
|
+
}
|
|
50470
51184
|
line.removedComment = true;
|
|
50471
51185
|
index = afterComment;
|
|
51186
|
+
segmentStart = index;
|
|
50472
51187
|
continue;
|
|
50473
51188
|
}
|
|
50474
51189
|
if (character === "\n") {
|
|
50475
|
-
|
|
51190
|
+
if (segmentStart < index) {
|
|
51191
|
+
lines[lines.length - 1].parts.push(source.slice(segmentStart, index));
|
|
51192
|
+
}
|
|
51193
|
+
lines.push({ parts: [], removedComment: false });
|
|
50476
51194
|
index += 1;
|
|
51195
|
+
segmentStart = index;
|
|
50477
51196
|
continue;
|
|
50478
51197
|
}
|
|
50479
51198
|
if (character === '"' || character === "'") quote6 = character;
|
|
50480
|
-
line.text += character;
|
|
50481
51199
|
index += 1;
|
|
50482
51200
|
}
|
|
50483
|
-
|
|
51201
|
+
if (segmentStart < source.length) {
|
|
51202
|
+
lines[lines.length - 1].parts.push(source.slice(segmentStart));
|
|
51203
|
+
}
|
|
51204
|
+
return lines.map((line) => ({
|
|
51205
|
+
text: line.parts.join("").trimEnd(),
|
|
51206
|
+
removedComment: line.removedComment
|
|
51207
|
+
})).filter((line) => !line.removedComment || line.text.trim().length > 0).map((line) => line.text).join("\n").trim();
|
|
50484
51208
|
}
|
|
50485
51209
|
function normalizeBodySource(source) {
|
|
50486
51210
|
const trimmed = source.trim();
|
|
@@ -56652,6 +57376,12 @@ var init_NeoScriptScope = __esm({
|
|
|
56652
57376
|
setLocal(bindingId, value) {
|
|
56653
57377
|
this.#bindings.set(bindingId, value);
|
|
56654
57378
|
}
|
|
57379
|
+
resetInvocationLocals(parameterCount) {
|
|
57380
|
+
if (this.#bindings.size > parameterCount) this.#bindings.clear();
|
|
57381
|
+
if (this.#readonlyBindingErrors.size > 0) {
|
|
57382
|
+
this.#readonlyBindingErrors.clear();
|
|
57383
|
+
}
|
|
57384
|
+
}
|
|
56655
57385
|
*keys() {
|
|
56656
57386
|
const inherited = /* @__PURE__ */ new Set();
|
|
56657
57387
|
if (this.parent !== null) {
|
|
@@ -61881,23 +62611,30 @@ function evalFunction(fn, scope, ctx) {
|
|
|
61881
62611
|
const innerFn = fn.info.function;
|
|
61882
62612
|
const isList = Array.isArray(c);
|
|
61883
62613
|
const out = isList ? [] : {};
|
|
62614
|
+
const useFreshCallbackScope = ctx.__collectionCallbackStrategy === "fresh";
|
|
62615
|
+
const callbackScope = useFreshCallbackScope ? null : createChildScope(scope);
|
|
62616
|
+
const callbackOptions = useFreshCallbackScope ? null : evaluationOptions(ctx, false);
|
|
62617
|
+
const callbackParameterCount = innerFn.parameters.length === 1 || innerFn.parameters.length === 2 ? innerFn.parameters.length : 0;
|
|
61884
62618
|
iterateCollection(c, ctx, (entry, key, valueId) => {
|
|
61885
62619
|
consumeBudget(ctx, "workUnits", 1, "work unit");
|
|
61886
|
-
const innerScope = pushParams(
|
|
61887
|
-
|
|
61888
|
-
|
|
61889
|
-
|
|
61890
|
-
|
|
61891
|
-
|
|
61892
|
-
|
|
61893
|
-
|
|
61894
|
-
|
|
61895
|
-
|
|
62620
|
+
const innerScope = callbackScope ?? pushParams(scope, innerFn.parameters, [key, entry], isList);
|
|
62621
|
+
if (callbackScope !== null) {
|
|
62622
|
+
callbackScope.resetInvocationLocals(callbackParameterCount);
|
|
62623
|
+
if (callbackParameterCount === 1) {
|
|
62624
|
+
callbackScope.setLocal(innerFn.parameters[0].id, entry);
|
|
62625
|
+
} else if (callbackParameterCount === 2) {
|
|
62626
|
+
callbackScope.setLocal(
|
|
62627
|
+
innerFn.parameters[0].id,
|
|
62628
|
+
isList ? Number(key) : String(key)
|
|
62629
|
+
);
|
|
62630
|
+
callbackScope.setLocal(innerFn.parameters[1].id, entry);
|
|
62631
|
+
}
|
|
62632
|
+
}
|
|
61896
62633
|
const result = evalInstructions(
|
|
61897
62634
|
innerFn.instructions,
|
|
61898
62635
|
innerScope,
|
|
61899
62636
|
ctx,
|
|
61900
|
-
evaluationOptions(ctx, false)
|
|
62637
|
+
callbackOptions ?? evaluationOptions(ctx, false)
|
|
61901
62638
|
);
|
|
61902
62639
|
if (result.kind === "return" && result.value === true) {
|
|
61903
62640
|
consumeBudget(
|
|
@@ -61922,24 +62659,35 @@ function evalFunction(fn, scope, ctx) {
|
|
|
61922
62659
|
const innerFn = fn.info.function ?? null;
|
|
61923
62660
|
const isList = Array.isArray(c);
|
|
61924
62661
|
const sentinel = /* @__PURE__ */ Symbol("not-found");
|
|
62662
|
+
const useFreshCallbackScope = ctx.__collectionCallbackStrategy === "fresh";
|
|
62663
|
+
const callbackScope = innerFn === null || useFreshCallbackScope ? null : createChildScope(scope);
|
|
62664
|
+
const callbackOptions = innerFn === null || useFreshCallbackScope ? null : evaluationOptions(ctx, false);
|
|
62665
|
+
const callbackParameterCount = innerFn !== null && (innerFn.parameters.length === 1 || innerFn.parameters.length === 2) ? innerFn.parameters.length : 0;
|
|
61925
62666
|
let found = sentinel;
|
|
61926
62667
|
iterateCollection(c, ctx, (entry, key) => {
|
|
61927
|
-
if (
|
|
62668
|
+
if (innerFn === null) {
|
|
61928
62669
|
found = entry;
|
|
61929
62670
|
return 1 /* Break */;
|
|
61930
62671
|
}
|
|
61931
62672
|
consumeBudget(ctx, "workUnits", 1, "work unit");
|
|
61932
|
-
const innerScope = pushParams(
|
|
61933
|
-
|
|
61934
|
-
|
|
61935
|
-
|
|
61936
|
-
|
|
61937
|
-
|
|
62673
|
+
const innerScope = callbackScope ?? pushParams(scope, innerFn.parameters, [key, entry], isList);
|
|
62674
|
+
if (callbackScope !== null) {
|
|
62675
|
+
callbackScope.resetInvocationLocals(callbackParameterCount);
|
|
62676
|
+
if (callbackParameterCount === 1) {
|
|
62677
|
+
callbackScope.setLocal(innerFn.parameters[0].id, entry);
|
|
62678
|
+
} else if (callbackParameterCount === 2) {
|
|
62679
|
+
callbackScope.setLocal(
|
|
62680
|
+
innerFn.parameters[0].id,
|
|
62681
|
+
isList ? Number(key) : String(key)
|
|
62682
|
+
);
|
|
62683
|
+
callbackScope.setLocal(innerFn.parameters[1].id, entry);
|
|
62684
|
+
}
|
|
62685
|
+
}
|
|
61938
62686
|
const result = evalInstructions(
|
|
61939
62687
|
innerFn.instructions,
|
|
61940
62688
|
innerScope,
|
|
61941
62689
|
ctx,
|
|
61942
|
-
evaluationOptions(ctx, false)
|
|
62690
|
+
callbackOptions ?? evaluationOptions(ctx, false)
|
|
61943
62691
|
);
|
|
61944
62692
|
if (result.kind === "return" && result.value === true) {
|
|
61945
62693
|
found = entry;
|
|
@@ -61957,22 +62705,33 @@ function evalFunction(fn, scope, ctx) {
|
|
|
61957
62705
|
}
|
|
61958
62706
|
case "select" /* select */: {
|
|
61959
62707
|
const c = evalPointer(fn.info.collectionPointer, scope, ctx);
|
|
62708
|
+
const useFreshCallbackScope = ctx.__collectionCallbackStrategy === "fresh";
|
|
62709
|
+
const callbackScope = useFreshCallbackScope ? null : createChildScope(scope);
|
|
62710
|
+
const callbackOptions = useFreshCallbackScope ? null : evaluationOptions(ctx, false);
|
|
61960
62711
|
const innerFn = fn.info.function;
|
|
62712
|
+
const callbackParameterCount = innerFn.parameters.length === 1 || innerFn.parameters.length === 2 ? innerFn.parameters.length : 0;
|
|
61961
62713
|
const isList = Array.isArray(c);
|
|
61962
62714
|
const out = [];
|
|
61963
62715
|
iterateCollection(c, ctx, (entry, key) => {
|
|
61964
62716
|
consumeBudget(ctx, "workUnits", 1, "work unit");
|
|
61965
|
-
const innerScope = pushParams(
|
|
61966
|
-
|
|
61967
|
-
|
|
61968
|
-
|
|
61969
|
-
|
|
61970
|
-
|
|
62717
|
+
const innerScope = callbackScope ?? pushParams(scope, innerFn.parameters, [key, entry], isList);
|
|
62718
|
+
if (callbackScope !== null) {
|
|
62719
|
+
callbackScope.resetInvocationLocals(callbackParameterCount);
|
|
62720
|
+
if (callbackParameterCount === 1) {
|
|
62721
|
+
callbackScope.setLocal(innerFn.parameters[0].id, entry);
|
|
62722
|
+
} else if (callbackParameterCount === 2) {
|
|
62723
|
+
callbackScope.setLocal(
|
|
62724
|
+
innerFn.parameters[0].id,
|
|
62725
|
+
isList ? Number(key) : String(key)
|
|
62726
|
+
);
|
|
62727
|
+
callbackScope.setLocal(innerFn.parameters[1].id, entry);
|
|
62728
|
+
}
|
|
62729
|
+
}
|
|
61971
62730
|
const result = evalInstructions(
|
|
61972
62731
|
innerFn.instructions,
|
|
61973
62732
|
innerScope,
|
|
61974
62733
|
ctx,
|
|
61975
|
-
evaluationOptions(ctx, false)
|
|
62734
|
+
callbackOptions ?? evaluationOptions(ctx, false)
|
|
61976
62735
|
);
|
|
61977
62736
|
if (result.kind === "return") {
|
|
61978
62737
|
consumeBudget(
|
|
@@ -62168,6 +62927,43 @@ function validateConstructorFieldSlot(args) {
|
|
|
62168
62927
|
requiredWithoutDefault: member.required && member.defaultValue == null
|
|
62169
62928
|
};
|
|
62170
62929
|
}
|
|
62930
|
+
function constructionGenericSlotsForMember(rawMember, ctx, instanceEnv, visitedMemberIds = /* @__PURE__ */ new Set()) {
|
|
62931
|
+
const member = substituteMember(
|
|
62932
|
+
rawMember,
|
|
62933
|
+
instanceEnv,
|
|
62934
|
+
ctx.vm.members
|
|
62935
|
+
);
|
|
62936
|
+
const memberId = Reflect.get(member, "id");
|
|
62937
|
+
if (typeof memberId === "string" && visitedMemberIds.has(memberId)) {
|
|
62938
|
+
return [];
|
|
62939
|
+
}
|
|
62940
|
+
const nextVisited = new Set(visitedMemberIds);
|
|
62941
|
+
if (typeof memberId === "string") nextVisited.add(memberId);
|
|
62942
|
+
if (isMemberClassBase(member)) {
|
|
62943
|
+
const classArguments2 = member.classArguments ?? {};
|
|
62944
|
+
return Object.keys(classArguments2).length === 0 ? [] : [{ classId: member.classId, classArguments: classArguments2 }];
|
|
62945
|
+
}
|
|
62946
|
+
if (!isMemberListBase(member) && !isMemberDictionaryBase(member)) return [];
|
|
62947
|
+
const entryMember = evalMemberById(ctx.vm, member.entryMemberId);
|
|
62948
|
+
if (entryMember === null) return [];
|
|
62949
|
+
return constructionGenericSlotsForMember(
|
|
62950
|
+
resolveMember2(entryMember, ctx.vm.members),
|
|
62951
|
+
ctx,
|
|
62952
|
+
instanceEnv,
|
|
62953
|
+
nextVisited
|
|
62954
|
+
);
|
|
62955
|
+
}
|
|
62956
|
+
function withConstructionGenericSlots(member, ctx, instanceEnv, evaluate) {
|
|
62957
|
+
const slots = constructionGenericSlotsForMember(member, ctx, instanceEnv);
|
|
62958
|
+
if (slots.length === 0) return evaluate();
|
|
62959
|
+
const previousSlots = ctx.__constructionGenericSlots;
|
|
62960
|
+
ctx.__constructionGenericSlots = [...previousSlots ?? [], ...slots];
|
|
62961
|
+
try {
|
|
62962
|
+
return evaluate();
|
|
62963
|
+
} finally {
|
|
62964
|
+
ctx.__constructionGenericSlots = previousSlots;
|
|
62965
|
+
}
|
|
62966
|
+
}
|
|
62171
62967
|
function evaluateConstructorFields(descriptor, scope, ctx) {
|
|
62172
62968
|
const schemaClass2 = descriptor.schemaClass;
|
|
62173
62969
|
const evaluatedValues = descriptor.fields.map((validated) => {
|
|
@@ -62176,7 +62972,13 @@ function evaluateConstructorFields(descriptor, scope, ctx) {
|
|
|
62176
62972
|
`Constructor field '${validated.schemaKey}' on '${schemaClass2.name}' has no call-site expression to evaluate.`
|
|
62177
62973
|
);
|
|
62178
62974
|
}
|
|
62179
|
-
|
|
62975
|
+
const valuePointer = validated.valuePointer;
|
|
62976
|
+
return withConstructionGenericSlots(
|
|
62977
|
+
validated.member,
|
|
62978
|
+
ctx,
|
|
62979
|
+
descriptor.instanceEnv,
|
|
62980
|
+
() => evalPointer(valuePointer, scope, ctx)
|
|
62981
|
+
);
|
|
62180
62982
|
});
|
|
62181
62983
|
return descriptor.fields.map((validated, index) => {
|
|
62182
62984
|
let value = evaluatedValues[index];
|
|
@@ -62214,6 +63016,14 @@ function syntheticConstructorMember(schemaClass2, classArguments2) {
|
|
|
62214
63016
|
accessModifierKind: "public"
|
|
62215
63017
|
};
|
|
62216
63018
|
}
|
|
63019
|
+
function stampConstructedRootGenericBindings(root, descriptor) {
|
|
63020
|
+
const stamp = {};
|
|
63021
|
+
for (const parameter4 of descriptor.schemaClass.genericParams ?? []) {
|
|
63022
|
+
const binding = descriptor.instanceEnv.get(parameter4.id);
|
|
63023
|
+
if (binding?.kind === "member") stamp[parameter4.id] = binding.memberId;
|
|
63024
|
+
}
|
|
63025
|
+
if (Object.keys(stamp).length > 0) root.genericBindings = stamp;
|
|
63026
|
+
}
|
|
62217
63027
|
function applyConstructorFields(args) {
|
|
62218
63028
|
const {
|
|
62219
63029
|
root,
|
|
@@ -62551,7 +63361,8 @@ function constructClassValueWithinFrame(descriptor, scope, ctx) {
|
|
|
62551
63361
|
valuesByClassId: /* @__PURE__ */ new Map(),
|
|
62552
63362
|
missingScopeReason: "no-constructor"
|
|
62553
63363
|
},
|
|
62554
|
-
classId
|
|
63364
|
+
classId,
|
|
63365
|
+
descriptor.instanceEnv
|
|
62555
63366
|
),
|
|
62556
63367
|
constructorRoot: {
|
|
62557
63368
|
providedSchemaKeys: new Set(
|
|
@@ -62560,6 +63371,7 @@ function constructClassValueWithinFrame(descriptor, scope, ctx) {
|
|
|
62560
63371
|
}
|
|
62561
63372
|
});
|
|
62562
63373
|
root.classId = classId;
|
|
63374
|
+
stampConstructedRootGenericBindings(root, descriptor);
|
|
62563
63375
|
if (typeof root.value !== "object" || root.value === null || Array.isArray(root.value)) {
|
|
62564
63376
|
throw new Error(
|
|
62565
63377
|
`Class constructor for '${schemaClass2.name}' produced a non-record root.`
|
|
@@ -62918,7 +63730,7 @@ function evaluateBaseInitializerFields(args) {
|
|
|
62918
63730
|
return { validated, value };
|
|
62919
63731
|
});
|
|
62920
63732
|
}
|
|
62921
|
-
function constructionInitEvaluator(ctx, createdValues, argumentScopes, constructedClassId) {
|
|
63733
|
+
function constructionInitEvaluator(ctx, createdValues, argumentScopes, constructedClassId, instanceEnv) {
|
|
62922
63734
|
const indexes = constructorInitializerIndexes(ctx);
|
|
62923
63735
|
const inheritanceChain = resolveInheritanceChain(
|
|
62924
63736
|
constructedClassId,
|
|
@@ -62940,36 +63752,19 @@ function constructionInitEvaluator(ctx, createdValues, argumentScopes, construct
|
|
|
62940
63752
|
};
|
|
62941
63753
|
return (member, init, sourceValueId) => {
|
|
62942
63754
|
const evaluate = (argumentValues = []) => {
|
|
62943
|
-
|
|
62944
|
-
|
|
62945
|
-
|
|
62946
|
-
|
|
62947
|
-
|
|
62948
|
-
createdValues,
|
|
62949
|
-
argumentValues,
|
|
62950
|
-
sourceValueId ?? null
|
|
62951
|
-
);
|
|
62952
|
-
}
|
|
62953
|
-
const previousSlots = ctx.__constructionGenericSlots;
|
|
62954
|
-
ctx.__constructionGenericSlots = [
|
|
62955
|
-
...previousSlots ?? [],
|
|
62956
|
-
{
|
|
62957
|
-
classId: member.classId,
|
|
62958
|
-
classArguments: member.classArguments ?? {}
|
|
62959
|
-
}
|
|
62960
|
-
];
|
|
62961
|
-
try {
|
|
62962
|
-
return evaluateInitializerInContext(
|
|
63755
|
+
return withConstructionGenericSlots(
|
|
63756
|
+
member,
|
|
63757
|
+
ctx,
|
|
63758
|
+
instanceEnv,
|
|
63759
|
+
() => evaluateInitializerInContext(
|
|
62963
63760
|
init,
|
|
62964
63761
|
member,
|
|
62965
63762
|
ctx,
|
|
62966
63763
|
createdValues,
|
|
62967
63764
|
argumentValues,
|
|
62968
63765
|
sourceValueId ?? null
|
|
62969
|
-
)
|
|
62970
|
-
|
|
62971
|
-
ctx.__constructionGenericSlots = previousSlots;
|
|
62972
|
-
}
|
|
63766
|
+
)
|
|
63767
|
+
);
|
|
62973
63768
|
};
|
|
62974
63769
|
if (init.compiled === void 0) {
|
|
62975
63770
|
return evaluate();
|
|
@@ -63172,6 +63967,7 @@ function evaluateInitializerInContext(init, member, ctx, createdValues, argument
|
|
|
63172
63967
|
return {
|
|
63173
63968
|
value: result.value,
|
|
63174
63969
|
classId: rootRow.classId ?? null,
|
|
63970
|
+
...rootRow.genericBindings === void 0 ? {} : { genericBindings: { ...rootRow.genericBindings } },
|
|
63175
63971
|
provisionalRootId: rootRow.id,
|
|
63176
63972
|
...constructorArgs === void 0 ? {} : { constructorArgs: structuredClone(constructorArgs) }
|
|
63177
63973
|
};
|
|
@@ -63281,7 +64077,7 @@ function encodeRequiredConstructorArgument(args) {
|
|
|
63281
64077
|
return adoptTracked(trackedId, "root");
|
|
63282
64078
|
}
|
|
63283
64079
|
if (args.typeInfo.type !== 6 /* List */ && args.typeInfo.type !== 5 /* Dictionary */) {
|
|
63284
|
-
return args.value;
|
|
64080
|
+
return cloneConstructorLiteralValue(args.value);
|
|
63285
64081
|
}
|
|
63286
64082
|
if (args.value === null || args.value === void 0) return null;
|
|
63287
64083
|
if (trackedId !== null) return adoptTracked(trackedId, "root");
|
|
@@ -63325,7 +64121,7 @@ function encodeRequiredConstructorArgument(args) {
|
|
|
63325
64121
|
}
|
|
63326
64122
|
return nested;
|
|
63327
64123
|
}
|
|
63328
|
-
return registerRow(value).id;
|
|
64124
|
+
return registerRow(cloneConstructorLiteralValue(value)).id;
|
|
63329
64125
|
};
|
|
63330
64126
|
if (collectionType.type === 6 /* List */) {
|
|
63331
64127
|
if (!Array.isArray(args.value)) {
|
|
@@ -63407,7 +64203,8 @@ function constructDeclaredClassValueWithinFrame(descriptor, record3, info, scope
|
|
|
63407
64203
|
ctx,
|
|
63408
64204
|
createdValues,
|
|
63409
64205
|
preparedArgumentScopes,
|
|
63410
|
-
classId
|
|
64206
|
+
classId,
|
|
64207
|
+
descriptor.instanceEnv
|
|
63411
64208
|
),
|
|
63412
64209
|
constructorRoot: {
|
|
63413
64210
|
providedSchemaKeys: new Set(
|
|
@@ -63417,6 +64214,7 @@ function constructDeclaredClassValueWithinFrame(descriptor, record3, info, scope
|
|
|
63417
64214
|
}
|
|
63418
64215
|
});
|
|
63419
64216
|
root.classId = classId;
|
|
64217
|
+
stampConstructedRootGenericBindings(root, descriptor);
|
|
63420
64218
|
} catch (error) {
|
|
63421
64219
|
if (error instanceof NSGetterRuntimeError) throw error;
|
|
63422
64220
|
throw new NSGetterRuntimeError(
|
|
@@ -63917,10 +64715,10 @@ function cloneConstructorArgumentGraph(args) {
|
|
|
63917
64715
|
return cloneRow(args.source, args.member, args.genericEnv);
|
|
63918
64716
|
}
|
|
63919
64717
|
function cloneConstructorLiteralValue(value) {
|
|
64718
|
+
if (typeof value !== "object" || value === null) return value;
|
|
63920
64719
|
if (Array.isArray(value)) {
|
|
63921
64720
|
return value.map((entry) => cloneConstructorLiteralValue(entry));
|
|
63922
64721
|
}
|
|
63923
|
-
if (typeof value !== "object" || value === null) return value;
|
|
63924
64722
|
return Object.fromEntries(
|
|
63925
64723
|
Object.entries(value).map(([key, entry]) => [
|
|
63926
64724
|
key,
|
|
@@ -64752,6 +65550,7 @@ function evaluateMemberInitializer(args) {
|
|
|
64752
65550
|
return {
|
|
64753
65551
|
value: result.value,
|
|
64754
65552
|
classId: rootRow.classId ?? null,
|
|
65553
|
+
...rootRow.genericBindings === void 0 ? {} : { genericBindings: { ...rootRow.genericBindings } },
|
|
64755
65554
|
provisionalRootId: rootRow.id,
|
|
64756
65555
|
...constructorArgs === void 0 ? {} : { constructorArgs: structuredClone(constructorArgs) }
|
|
64757
65556
|
};
|
|
@@ -64811,6 +65610,7 @@ function materializeInitializerValue(args) {
|
|
|
64811
65610
|
...envelope,
|
|
64812
65611
|
value: evaluated.value,
|
|
64813
65612
|
...evaluated.classId === null ? {} : { classId: evaluated.classId },
|
|
65613
|
+
...evaluated.genericBindings === void 0 ? {} : { genericBindings: { ...evaluated.genericBindings } },
|
|
64814
65614
|
...evaluated.constructorArgs === void 0 ? {} : { constructorArgs: structuredClone(evaluated.constructorArgs) }
|
|
64815
65615
|
};
|
|
64816
65616
|
if (evaluated.provisionalRootId !== void 0) {
|
|
@@ -66456,6 +67256,7 @@ var init_project_document_read = __esm({
|
|
|
66456
67256
|
});
|
|
66457
67257
|
|
|
66458
67258
|
// src/workspace.ts
|
|
67259
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
66459
67260
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2 } from "node:fs";
|
|
66460
67261
|
import { dirname, join as join2, resolve } from "node:path";
|
|
66461
67262
|
function recordStateKey(recordKind, recordId) {
|
|
@@ -66688,9 +67489,12 @@ function matchUnityScalarField(content, field) {
|
|
|
66688
67489
|
function readWorkspaceState(root, options = {}) {
|
|
66689
67490
|
const statePath = join2(root, NEO_STATE_DIR, NEO_STATE_FILE);
|
|
66690
67491
|
if (!existsSync2(statePath)) {
|
|
67492
|
+
options.onSourceRead?.(null);
|
|
66691
67493
|
return { records: {} };
|
|
66692
67494
|
}
|
|
66693
|
-
const
|
|
67495
|
+
const source = readFileSync2(statePath, "utf8");
|
|
67496
|
+
options.onSourceRead?.(source);
|
|
67497
|
+
const parsed = JSON.parse(source);
|
|
66694
67498
|
if (typeof parsed !== "object" || parsed === null) {
|
|
66695
67499
|
throw new Error(`"${statePath}" must contain a JSON object.`);
|
|
66696
67500
|
}
|
|
@@ -66733,10 +67537,20 @@ function loadWorkspace(startDir, options = {}) {
|
|
|
66733
67537
|
`No "${NEO_CONFIG_FILE}" found in "${startDir}" or any parent directory. Run "neo init" first.`
|
|
66734
67538
|
);
|
|
66735
67539
|
}
|
|
67540
|
+
let stateSourceSha256;
|
|
67541
|
+
const state = readWorkspaceState(root, {
|
|
67542
|
+
discardLegacyFormat2State: options.discardLegacyFormat2State,
|
|
67543
|
+
...options.fingerprintStateSource === true ? {
|
|
67544
|
+
onSourceRead: (source) => {
|
|
67545
|
+
stateSourceSha256 = createHash2("sha256").update(source ?? "<missing>").digest("hex");
|
|
67546
|
+
}
|
|
67547
|
+
} : {}
|
|
67548
|
+
});
|
|
66736
67549
|
return {
|
|
66737
67550
|
root,
|
|
66738
67551
|
config: readWorkspaceConfig(root),
|
|
66739
|
-
state
|
|
67552
|
+
state,
|
|
67553
|
+
...stateSourceSha256 === void 0 ? {} : { stateSourceSha256 }
|
|
66740
67554
|
};
|
|
66741
67555
|
}
|
|
66742
67556
|
var NEO_CONFIG_FILE, NEO_STATE_DIR, NEO_STATE_FILE, CURRENT_FORMAT_VERSION;
|
|
@@ -72095,7 +72909,7 @@ var init_animation_clips = __esm({
|
|
|
72095
72909
|
|
|
72096
72910
|
// src/project-source/materialized-construction-cache.ts
|
|
72097
72911
|
import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
72098
|
-
import { createHash as
|
|
72912
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
72099
72913
|
import { dirname as dirname2, join as join3 } from "node:path";
|
|
72100
72914
|
function createMaterializedConstructionExpressionsV1(args) {
|
|
72101
72915
|
const warm = args.useBuildCaches ? readMaterializedConstructionBuildCacheV1(args.root, args.state) : null;
|
|
@@ -72187,7 +73001,7 @@ function writeMaterializedConstructionBuildCacheV1(root, state, expressions) {
|
|
|
72187
73001
|
renameSync(temporary, file);
|
|
72188
73002
|
}
|
|
72189
73003
|
function materializedConstructionStateFingerprint(state) {
|
|
72190
|
-
const hash =
|
|
73004
|
+
const hash = createHash3("sha256");
|
|
72191
73005
|
hash.update(String(MATERIALIZED_CONSTRUCTION_BUILD_CACHE_REVISION));
|
|
72192
73006
|
for (const [key, record3] of Object.entries(state.records).sort(
|
|
72193
73007
|
([left], [right]) => left.localeCompare(right)
|
|
@@ -73013,10 +73827,10 @@ var init_neo_script_recompile_scope = __esm({
|
|
|
73013
73827
|
});
|
|
73014
73828
|
|
|
73015
73829
|
// ../src/database/project-content-hash.ts
|
|
73016
|
-
import { createHash as
|
|
73830
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
73017
73831
|
function hashCanonicalJson(value) {
|
|
73018
73832
|
const canonicalJson = canonicalJsonStringify(value);
|
|
73019
|
-
return
|
|
73833
|
+
return createHash4("sha256").update(canonicalJson).digest("hex");
|
|
73020
73834
|
}
|
|
73021
73835
|
var init_project_content_hash = __esm({
|
|
73022
73836
|
"../src/database/project-content-hash.ts"() {
|
|
@@ -73083,7 +73897,7 @@ var init_project_fingerprint = __esm({
|
|
|
73083
73897
|
|
|
73084
73898
|
// src/project-source/neoscript-build-cache.ts
|
|
73085
73899
|
import { mkdirSync as mkdirSync4, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
73086
|
-
import { createHash as
|
|
73900
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
73087
73901
|
import { dirname as dirname3, join as join4 } from "node:path";
|
|
73088
73902
|
function loadOrBuildNeoScriptProjectV1(root, document) {
|
|
73089
73903
|
const fingerprint = neoScriptProjectFingerprint(document);
|
|
@@ -73110,7 +73924,7 @@ function loadOrBuildNeoScriptProjectV1(root, document) {
|
|
|
73110
73924
|
return project;
|
|
73111
73925
|
}
|
|
73112
73926
|
function neoScriptProjectFingerprint(document) {
|
|
73113
|
-
return
|
|
73927
|
+
return createHash5("sha256").update(
|
|
73114
73928
|
canonicalJsonStringify(neoScriptCompilationProjectContract(document))
|
|
73115
73929
|
).digest("hex");
|
|
73116
73930
|
}
|
|
@@ -74550,6 +75364,13 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
|
|
|
74550
75364
|
const classesById = new Map(
|
|
74551
75365
|
classes.map((schemaClass2) => [schemaClass2.id, schemaClass2])
|
|
74552
75366
|
);
|
|
75367
|
+
const genericParamConstraintsById = new Map(
|
|
75368
|
+
classes.flatMap(
|
|
75369
|
+
(schemaClass2) => (schemaClass2.genericParams ?? []).map(
|
|
75370
|
+
(param) => [param.id, param.constraint]
|
|
75371
|
+
)
|
|
75372
|
+
)
|
|
75373
|
+
);
|
|
74553
75374
|
const interfacesById = new Map(
|
|
74554
75375
|
interfaces.map((neoInterface) => [neoInterface.id, neoInterface])
|
|
74555
75376
|
);
|
|
@@ -75439,6 +76260,33 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
|
|
|
75439
76260
|
}
|
|
75440
76261
|
return { type: resolved.kind, required: required2 };
|
|
75441
76262
|
};
|
|
76263
|
+
const constrainedGenericTypeInfo = (typeInfo) => {
|
|
76264
|
+
if (!isRecord7(typeInfo) || typeInfo.type !== 21 || typeof typeInfo.genericParamId !== "string") {
|
|
76265
|
+
return null;
|
|
76266
|
+
}
|
|
76267
|
+
const constraint = genericParamConstraintsById.get(typeInfo.genericParamId);
|
|
76268
|
+
if (!constraint) return null;
|
|
76269
|
+
return constraint.kind === "class" ? {
|
|
76270
|
+
type: 7,
|
|
76271
|
+
required: typeInfo.required === true,
|
|
76272
|
+
classId: constraint.classId
|
|
76273
|
+
} : {
|
|
76274
|
+
type: 8,
|
|
76275
|
+
required: typeInfo.required === true,
|
|
76276
|
+
enumId: constraint.enumId
|
|
76277
|
+
};
|
|
76278
|
+
};
|
|
76279
|
+
const constrainedGenericMemberTypeInfo = (member, schemaClass2) => {
|
|
76280
|
+
const resolved = substituteMemberForClass(member, schemaClass2);
|
|
76281
|
+
if (resolved.kind !== 21 || typeof resolved.genericParamId !== "string") {
|
|
76282
|
+
return null;
|
|
76283
|
+
}
|
|
76284
|
+
return constrainedGenericTypeInfo({
|
|
76285
|
+
type: 21,
|
|
76286
|
+
required: true,
|
|
76287
|
+
genericParamId: resolved.genericParamId
|
|
76288
|
+
});
|
|
76289
|
+
};
|
|
75442
76290
|
const substituteTypeInfoForClass = (typeInfo, schemaClass2) => {
|
|
75443
76291
|
if (!isRecord7(typeInfo)) return typeInfo;
|
|
75444
76292
|
if (typeInfo.type === 21 && typeof typeInfo.genericParamId === "string") {
|
|
@@ -75509,7 +76357,8 @@ function assertProjectInterfaceDocumentValid(view, options = {}) {
|
|
|
75509
76357
|
if (resolved.kind === 13 || resolved.kind === 23) {
|
|
75510
76358
|
return "Schema member is a Function but the interface declares a property.";
|
|
75511
76359
|
}
|
|
75512
|
-
const
|
|
76360
|
+
const storedType = memberTypeInfo(member, schemaClass2);
|
|
76361
|
+
const implementationType = declaration.settable === true ? storedType : storedType ? constrainedGenericTypeInfo(storedType) ?? storedType : constrainedGenericMemberTypeInfo(member, schemaClass2);
|
|
75513
76362
|
if (!implementationType) return "Schema member type could not be resolved.";
|
|
75514
76363
|
const matches = declaration.settable === true ? invariantTypeInfo(implementationType, declaration.typeInfo) : typeInfoAssignable(implementationType, declaration.typeInfo);
|
|
75515
76364
|
if (!matches) return "Property type does not conform.";
|
|
@@ -92198,7 +93047,7 @@ var init_project_documents = __esm({
|
|
|
92198
93047
|
|
|
92199
93048
|
// src/project-source/project-document-cache.ts
|
|
92200
93049
|
import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, renameSync as renameSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
92201
|
-
import { createHash as
|
|
93050
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
92202
93051
|
import { dirname as dirname4, join as join5 } from "node:path";
|
|
92203
93052
|
function readProjectSourceAnalysisBuildCacheV4(root, sources) {
|
|
92204
93053
|
try {
|
|
@@ -92322,7 +93171,7 @@ function writeProjectSourceDocumentBuildCacheV1(root, sources, documents) {
|
|
|
92322
93171
|
renameSync3(temporary, file);
|
|
92323
93172
|
}
|
|
92324
93173
|
function projectSourceFileFingerprint(source) {
|
|
92325
|
-
return
|
|
93174
|
+
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");
|
|
92326
93175
|
}
|
|
92327
93176
|
function isCachedProjectSourceDocument(value, source) {
|
|
92328
93177
|
if (value === null || typeof value !== "object") return false;
|
|
@@ -92330,7 +93179,7 @@ function isCachedProjectSourceDocument(value, source) {
|
|
|
92330
93179
|
return document.kind === source.kind && document.sourceText === source.text && Array.isArray(document.declarations) && Array.isArray(document.diagnostics);
|
|
92331
93180
|
}
|
|
92332
93181
|
function projectSourceFingerprint(sources) {
|
|
92333
|
-
const hash =
|
|
93182
|
+
const hash = createHash6("sha256");
|
|
92334
93183
|
hash.update(String(PROJECT_SOURCE_BUILD_CACHE_REVISION));
|
|
92335
93184
|
hash.update("\0");
|
|
92336
93185
|
hash.update(String(NEOSCRIPT_COMPILER_REVISION));
|
|
@@ -92358,7 +93207,7 @@ var init_project_document_cache = __esm({
|
|
|
92358
93207
|
});
|
|
92359
93208
|
|
|
92360
93209
|
// src/project-source/project-files.ts
|
|
92361
|
-
import { createHash as
|
|
93210
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
92362
93211
|
import {
|
|
92363
93212
|
existsSync as existsSync3,
|
|
92364
93213
|
mkdirSync as mkdirSync6,
|
|
@@ -92605,7 +93454,7 @@ function discoverProjectBinariesV4(root, explicit, ignoredPaths = []) {
|
|
|
92605
93454
|
}).sort((left, right) => compareCodePoints(left.path, right.path));
|
|
92606
93455
|
}
|
|
92607
93456
|
function sha256Bytes(bytes) {
|
|
92608
|
-
return
|
|
93457
|
+
return createHash7("sha256").update(bytes).digest("hex");
|
|
92609
93458
|
}
|
|
92610
93459
|
function sha256File(path) {
|
|
92611
93460
|
return sha256Bytes(readFileSync6(path));
|
|
@@ -98058,7 +98907,7 @@ var init_script = __esm({
|
|
|
98058
98907
|
});
|
|
98059
98908
|
|
|
98060
98909
|
// ../src/database/project-source-identity.ts
|
|
98061
|
-
import { createHash as
|
|
98910
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
98062
98911
|
function hashProjectSourceFiles(inputFiles) {
|
|
98063
98912
|
const files = normalizeSourceFiles(inputFiles);
|
|
98064
98913
|
const bytes = Buffer.from(JSON.stringify({ version: 1, files }), "utf8");
|
|
@@ -98067,7 +98916,7 @@ function hashProjectSourceFiles(inputFiles) {
|
|
|
98067
98916
|
`Project source identity is ${bytes.byteLength} bytes; the limit is ${MAX_SOURCE_BYTES} bytes.`
|
|
98068
98917
|
);
|
|
98069
98918
|
}
|
|
98070
|
-
return
|
|
98919
|
+
return createHash8("sha256").update(bytes).digest("hex");
|
|
98071
98920
|
}
|
|
98072
98921
|
function normalizeSourceFiles(inputFiles) {
|
|
98073
98922
|
if (inputFiles.length > MAX_SOURCE_FILES) {
|
|
@@ -98159,14 +99008,14 @@ var init_project_source_identity = __esm({
|
|
|
98159
99008
|
|
|
98160
99009
|
// src/push-hook.ts
|
|
98161
99010
|
import { spawn } from "node:child_process";
|
|
98162
|
-
import { createHash as
|
|
99011
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
98163
99012
|
import { existsSync as existsSync10, readFileSync as readFileSync13, readdirSync as readdirSync4 } from "node:fs";
|
|
98164
99013
|
import { join as join13, relative as relative3, sep as sep3 } from "node:path";
|
|
98165
|
-
function fingerprintPushInputs(workspace) {
|
|
99014
|
+
function fingerprintPushInputs(workspace, options = {}) {
|
|
98166
99015
|
const paths = /* @__PURE__ */ new Set([
|
|
98167
99016
|
join13(workspace.root, "neo.json"),
|
|
98168
99017
|
...listProjectSourceFilesV4(workspace.root),
|
|
98169
|
-
...listProjectTestFilesV1(workspace.root),
|
|
99018
|
+
...options.includeTests === false ? [] : listProjectTestFilesV1(workspace.root),
|
|
98170
99019
|
...workspace.config.unityConfigPath === void 0 ? [] : [join13(workspace.root, workspace.config.unityConfigPath)]
|
|
98171
99020
|
]);
|
|
98172
99021
|
const visitManaged = (directory) => {
|
|
@@ -98180,7 +99029,7 @@ function fingerprintPushInputs(workspace) {
|
|
|
98180
99029
|
};
|
|
98181
99030
|
visitManaged(join13(workspace.root, "Files", "Images"));
|
|
98182
99031
|
visitManaged(join13(workspace.root, "Files", "AudioClips"));
|
|
98183
|
-
const hash =
|
|
99032
|
+
const hash = createHash9("sha256");
|
|
98184
99033
|
for (const path of [...paths].sort()) {
|
|
98185
99034
|
const name = relative3(workspace.root, path).split(sep3).join("/");
|
|
98186
99035
|
hash.update(name);
|
|
@@ -98837,7 +99686,7 @@ __export(push_exports, {
|
|
|
98837
99686
|
runPush: () => runPush,
|
|
98838
99687
|
stripServerDerivedNeoScript: () => stripServerDerivedNeoScript
|
|
98839
99688
|
});
|
|
98840
|
-
import { createHash as
|
|
99689
|
+
import { createHash as createHash10, randomUUID as randomUUID2 } from "node:crypto";
|
|
98841
99690
|
import {
|
|
98842
99691
|
mkdirSync as mkdirSync10,
|
|
98843
99692
|
writeFileSync as writeFileSync10,
|
|
@@ -98877,8 +99726,13 @@ function assignPendingIds(changes, authoredValueSeeds, reconstructed3, localInit
|
|
|
98877
99726
|
return fresh;
|
|
98878
99727
|
};
|
|
98879
99728
|
const collect = (value) => {
|
|
98880
|
-
if (typeof value === "string"
|
|
98881
|
-
|
|
99729
|
+
if (typeof value === "string") {
|
|
99730
|
+
const interfaceOwner = pendingInterfaceMemberSymbolOwner(value);
|
|
99731
|
+
if (interfaceOwner !== null) {
|
|
99732
|
+
assign(interfaceOwner);
|
|
99733
|
+
return;
|
|
99734
|
+
}
|
|
99735
|
+
if (isPendingId(value)) assign(value);
|
|
98882
99736
|
return;
|
|
98883
99737
|
}
|
|
98884
99738
|
if (Array.isArray(value)) {
|
|
@@ -99032,6 +99886,18 @@ function assignPendingIds(changes, authoredValueSeeds, reconstructed3, localInit
|
|
|
99032
99886
|
}
|
|
99033
99887
|
};
|
|
99034
99888
|
}
|
|
99889
|
+
function pendingInterfaceMemberSymbolOwner(value) {
|
|
99890
|
+
const marker = ":member:";
|
|
99891
|
+
const markerIndex = value.indexOf(marker);
|
|
99892
|
+
if (markerIndex < 0) return null;
|
|
99893
|
+
const owner = value.slice(0, markerIndex);
|
|
99894
|
+
const parts = owner.split(":");
|
|
99895
|
+
if (parts.length !== 6) return null;
|
|
99896
|
+
if (parts[0] !== "__pending__" || parts[1] !== "interface") return null;
|
|
99897
|
+
if (!/^\d+$/u.test(parts[3] ?? "")) return null;
|
|
99898
|
+
if (!/^\d+$/u.test(parts[4] ?? "")) return null;
|
|
99899
|
+
return owner;
|
|
99900
|
+
}
|
|
99035
99901
|
function readAcceptedProjectVersionCommitResponse(value) {
|
|
99036
99902
|
if (!isObjectRecord2(value) || value.kind !== "accepted") return null;
|
|
99037
99903
|
if (typeof value.transactionId !== "string") {
|
|
@@ -99603,7 +100469,7 @@ async function runPush(workspace, options, preparationOverride) {
|
|
|
99603
100469
|
version: 1,
|
|
99604
100470
|
projectFingerprint: `sha256:${preparedLocal.source.sourceHash}`,
|
|
99605
100471
|
inputFingerprint: preparedInputFingerprint,
|
|
99606
|
-
documentSha256:
|
|
100472
|
+
documentSha256: createHash10("sha256").update(documentJson).digest("hex"),
|
|
99607
100473
|
document: candidate.document
|
|
99608
100474
|
})}
|
|
99609
100475
|
`,
|
|
@@ -101612,7 +102478,7 @@ var init_registry2 = __esm({
|
|
|
101612
102478
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
101613
102479
|
formatVersion: 3,
|
|
101614
102480
|
contractVersion: "3.9",
|
|
101615
|
-
cliVersion: "0.26.
|
|
102481
|
+
cliVersion: "0.26.2",
|
|
101616
102482
|
projectFileUploadBatchSize: 32,
|
|
101617
102483
|
documentRecords: {
|
|
101618
102484
|
member: {
|
|
@@ -102905,7 +103771,7 @@ __export(test_exports, {
|
|
|
102905
103771
|
maintainNeoTestBuildCache: () => maintainNeoTestBuildCache,
|
|
102906
103772
|
runTest: () => runTest
|
|
102907
103773
|
});
|
|
102908
|
-
import { createHash as
|
|
103774
|
+
import { createHash as createHash11, randomUUID as randomUUID3 } from "node:crypto";
|
|
102909
103775
|
import {
|
|
102910
103776
|
existsSync as existsSync12,
|
|
102911
103777
|
mkdirSync as mkdirSync11,
|
|
@@ -103019,10 +103885,11 @@ function errorMessage2(error) {
|
|
|
103019
103885
|
function findDelegateTargetMemberId(value) {
|
|
103020
103886
|
return isRecord10(value) && typeof value.memberId === "string" ? value.memberId : null;
|
|
103021
103887
|
}
|
|
103022
|
-
function
|
|
103023
|
-
const
|
|
103024
|
-
|
|
103025
|
-
const
|
|
103888
|
+
function sharedEvaluatorBase(rawDocument) {
|
|
103889
|
+
const cached = SHARED_EVALUATOR_BASES.get(rawDocument);
|
|
103890
|
+
if (cached !== void 0) return cached;
|
|
103891
|
+
const document = readDocumentArrays(rawDocument);
|
|
103892
|
+
const constructors = Array.isArray(rawDocument.constructors) ? rawDocument.constructors.filter(isRecord10) : [];
|
|
103026
103893
|
const vm = {
|
|
103027
103894
|
project: document.project,
|
|
103028
103895
|
members: document.members,
|
|
@@ -103047,10 +103914,19 @@ function makeEvaluatorContext(rawDocument, interceptor, documentAlreadyIsolated
|
|
|
103047
103914
|
}
|
|
103048
103915
|
)
|
|
103049
103916
|
};
|
|
103050
|
-
|
|
103917
|
+
const created = {
|
|
103051
103918
|
vm,
|
|
103919
|
+
rootValue: buildRootValue(document)
|
|
103920
|
+
};
|
|
103921
|
+
SHARED_EVALUATOR_BASES.set(rawDocument, created);
|
|
103922
|
+
return created;
|
|
103923
|
+
}
|
|
103924
|
+
function makeEvaluatorContext(rawDocument, interceptor) {
|
|
103925
|
+
const base = sharedEvaluatorBase(rawDocument);
|
|
103926
|
+
return createNeoScriptEvaluationRuntime({
|
|
103927
|
+
vm: base.vm,
|
|
103052
103928
|
thisValue: null,
|
|
103053
|
-
rootValue:
|
|
103929
|
+
rootValue: base.rootValue,
|
|
103054
103930
|
dialogueContext: null,
|
|
103055
103931
|
callInterceptor: interceptor,
|
|
103056
103932
|
nativeFunctionErrorCheckBehavior: "strict"
|
|
@@ -103117,14 +103993,15 @@ function preparedHookCandidate(workspace) {
|
|
|
103117
103993
|
);
|
|
103118
103994
|
}
|
|
103119
103995
|
const documentJson = JSON.stringify(parsed.document);
|
|
103120
|
-
if (
|
|
103996
|
+
if (createHash11("sha256").update(documentJson).digest("hex") !== parsed.documentSha256) {
|
|
103121
103997
|
throw new NeoTestPreparedCandidateError(
|
|
103122
103998
|
"Configured push hook candidate project document failed checksum verification."
|
|
103123
103999
|
);
|
|
103124
104000
|
}
|
|
103125
104001
|
return {
|
|
103126
104002
|
document: parsed.document,
|
|
103127
|
-
sourceHash: configuredFingerprint.replace(/^sha256:/u, "")
|
|
104003
|
+
sourceHash: configuredFingerprint.replace(/^sha256:/u, ""),
|
|
104004
|
+
documentSha256: parsed.documentSha256
|
|
103128
104005
|
};
|
|
103129
104006
|
} catch (error) {
|
|
103130
104007
|
if (error instanceof NeoTestPreparedCandidateError) throw error;
|
|
@@ -103133,11 +104010,79 @@ function preparedHookCandidate(workspace) {
|
|
|
103133
104010
|
);
|
|
103134
104011
|
}
|
|
103135
104012
|
}
|
|
104013
|
+
function fingerprintTestCandidateInputs(workspace) {
|
|
104014
|
+
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(
|
|
104015
|
+
workspace.stateSourceSha256 === void 0 ? `object\0${JSON.stringify(workspace.state)}` : `source\0${workspace.stateSourceSha256}`
|
|
104016
|
+
).digest("hex");
|
|
104017
|
+
}
|
|
104018
|
+
function testCandidateCachePath(workspace, inputFingerprint) {
|
|
104019
|
+
const cacheKey = createHash11("sha256").update(inputFingerprint).digest("hex");
|
|
104020
|
+
return join16(
|
|
104021
|
+
workspace.root,
|
|
104022
|
+
".neo",
|
|
104023
|
+
"test-build",
|
|
104024
|
+
"v1",
|
|
104025
|
+
"project",
|
|
104026
|
+
cacheKey,
|
|
104027
|
+
"candidate.json"
|
|
104028
|
+
);
|
|
104029
|
+
}
|
|
104030
|
+
function cachedTestCandidate(workspace, inputFingerprint) {
|
|
104031
|
+
try {
|
|
104032
|
+
const candidatePath = testCandidateCachePath(workspace, inputFingerprint);
|
|
104033
|
+
const parsed = JSON.parse(readFileSync16(candidatePath, "utf8"));
|
|
104034
|
+
if (!isRecord10(parsed)) return null;
|
|
104035
|
+
if (parsed.version !== 1) return null;
|
|
104036
|
+
if (parsed.candidateRevision !== TEST_CANDIDATE_CACHE_REVISION) return null;
|
|
104037
|
+
if (parsed.cliVersion !== PROJECT_SCHEMA_CONTRACT.cliVersion) return null;
|
|
104038
|
+
if (parsed.compilerRevision !== NEOSCRIPT_COMPILER_REVISION) return null;
|
|
104039
|
+
if (parsed.inputFingerprint !== inputFingerprint) return null;
|
|
104040
|
+
if (typeof parsed.sourceHash !== "string" || parsed.sourceHash.length === 0) {
|
|
104041
|
+
return null;
|
|
104042
|
+
}
|
|
104043
|
+
if (typeof parsed.documentSha256 !== "string") return null;
|
|
104044
|
+
const documentJson = readFileSync16(
|
|
104045
|
+
join16(dirname9(candidatePath), "document.json"),
|
|
104046
|
+
"utf8"
|
|
104047
|
+
);
|
|
104048
|
+
if (createHash11("sha256").update(documentJson).digest("hex") !== parsed.documentSha256) {
|
|
104049
|
+
return null;
|
|
104050
|
+
}
|
|
104051
|
+
const document = JSON.parse(documentJson);
|
|
104052
|
+
if (!isRecord10(document)) return null;
|
|
104053
|
+
return {
|
|
104054
|
+
document,
|
|
104055
|
+
sourceHash: parsed.sourceHash,
|
|
104056
|
+
documentSha256: parsed.documentSha256
|
|
104057
|
+
};
|
|
104058
|
+
} catch {
|
|
104059
|
+
return null;
|
|
104060
|
+
}
|
|
104061
|
+
}
|
|
104062
|
+
function cacheTestCandidate(workspace, inputFingerprint, candidate) {
|
|
104063
|
+
const documentJson = JSON.stringify(candidate.document);
|
|
104064
|
+
const documentSha256 = createHash11("sha256").update(documentJson).digest("hex");
|
|
104065
|
+
const candidatePath = testCandidateCachePath(workspace, inputFingerprint);
|
|
104066
|
+
atomicWrite(join16(dirname9(candidatePath), "document.json"), documentJson);
|
|
104067
|
+
atomicWrite(
|
|
104068
|
+
candidatePath,
|
|
104069
|
+
JSON.stringify({
|
|
104070
|
+
version: 1,
|
|
104071
|
+
candidateRevision: TEST_CANDIDATE_CACHE_REVISION,
|
|
104072
|
+
cliVersion: PROJECT_SCHEMA_CONTRACT.cliVersion,
|
|
104073
|
+
compilerRevision: NEOSCRIPT_COMPILER_REVISION,
|
|
104074
|
+
inputFingerprint,
|
|
104075
|
+
sourceHash: candidate.sourceHash,
|
|
104076
|
+
documentSha256
|
|
104077
|
+
}) + "\n"
|
|
104078
|
+
);
|
|
104079
|
+
return { ...candidate, documentSha256 };
|
|
104080
|
+
}
|
|
103136
104081
|
function compileSpec(workspace, document, absolutePath, projectCompilationHash2) {
|
|
103137
104082
|
const scriptDocument = readDocumentArrays(document);
|
|
103138
104083
|
const path = relative5(workspace.root, absolutePath).split(sep5).join("/");
|
|
103139
104084
|
const source = readFileSync16(absolutePath, "utf8");
|
|
103140
|
-
const sourceHash =
|
|
104085
|
+
const sourceHash = createHash11("sha256").update(source).digest("hex");
|
|
103141
104086
|
const artifactPath = join16(
|
|
103142
104087
|
workspace.root,
|
|
103143
104088
|
".neo",
|
|
@@ -103148,7 +104093,7 @@ function compileSpec(workspace, document, absolutePath, projectCompilationHash2)
|
|
|
103148
104093
|
);
|
|
103149
104094
|
try {
|
|
103150
104095
|
const cached = JSON.parse(readFileSync16(artifactPath, "utf8"));
|
|
103151
|
-
if (isRecord10(cached) && cached.version === 1 && cached.compilerRevision === NEOSCRIPT_COMPILER_REVISION && cached.projectCompilationHash === projectCompilationHash2 && cached.sourceHash === sourceHash && isRecord10(cached.action) && typeof cached.artifactSha256 === "string" &&
|
|
104096
|
+
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)) {
|
|
103152
104097
|
return {
|
|
103153
104098
|
path,
|
|
103154
104099
|
source,
|
|
@@ -103180,15 +104125,16 @@ function compileSpec(workspace, document, absolutePath, projectCompilationHash2)
|
|
|
103180
104125
|
compilerRevision: NEOSCRIPT_COMPILER_REVISION,
|
|
103181
104126
|
projectCompilationHash: projectCompilationHash2,
|
|
103182
104127
|
sourceHash,
|
|
103183
|
-
artifactSha256:
|
|
104128
|
+
artifactSha256: createHash11("sha256").update(JSON.stringify(compiled.action)).digest("hex"),
|
|
103184
104129
|
action: compiled.action
|
|
103185
104130
|
})}
|
|
103186
104131
|
`
|
|
103187
104132
|
);
|
|
103188
104133
|
return compiled;
|
|
103189
104134
|
}
|
|
103190
|
-
function projectCompilationHash(projectSourceHash, document) {
|
|
103191
|
-
|
|
104135
|
+
function projectCompilationHash(projectSourceHash, document, knownDocumentSha256) {
|
|
104136
|
+
const documentSha256 = knownDocumentSha256 ?? createHash11("sha256").update(JSON.stringify(document)).digest("hex");
|
|
104137
|
+
return createHash11("sha256").update(projectSourceHash).update("\0").update(documentSha256).digest("hex");
|
|
103192
104138
|
}
|
|
103193
104139
|
function selectedSpecPaths(workspace, selectors) {
|
|
103194
104140
|
const all = listProjectTestFilesV1(workspace.root);
|
|
@@ -103421,7 +104367,7 @@ function registerSpec(spec, document) {
|
|
|
103421
104367
|
}
|
|
103422
104368
|
names.add(fullName);
|
|
103423
104369
|
const test = {
|
|
103424
|
-
id: `sha256:${
|
|
104370
|
+
id: `sha256:${createHash11("sha256").update(`${spec.path}\0${namePath}`).digest("hex")}`,
|
|
103425
104371
|
name: namePath,
|
|
103426
104372
|
fullName,
|
|
103427
104373
|
body: portableDelegate(call.args[1]),
|
|
@@ -103772,24 +104718,32 @@ function interceptTestCall(environment, call) {
|
|
|
103772
104718
|
throw error;
|
|
103773
104719
|
}
|
|
103774
104720
|
}
|
|
103775
|
-
function createTestEnvironment(document
|
|
104721
|
+
function createTestEnvironment(document) {
|
|
103776
104722
|
const environment = {
|
|
103777
104723
|
baseDocument: document,
|
|
103778
104724
|
context: void 0,
|
|
103779
104725
|
mocks: /* @__PURE__ */ new Map(),
|
|
103780
104726
|
mocksByMember: /* @__PURE__ */ new Map(),
|
|
103781
|
-
nextMockId: 1
|
|
104727
|
+
nextMockId: 1,
|
|
104728
|
+
hasStateChanges: false
|
|
103782
104729
|
};
|
|
103783
104730
|
environment.context = makeEvaluatorContext(
|
|
103784
104731
|
document,
|
|
103785
|
-
(call) => interceptTestCall(environment, call)
|
|
103786
|
-
documentAlreadyIsolated
|
|
104732
|
+
(call) => interceptTestCall(environment, call)
|
|
103787
104733
|
);
|
|
103788
104734
|
return environment;
|
|
103789
104735
|
}
|
|
103790
104736
|
function snapshotEnvironmentDocument(environment) {
|
|
103791
|
-
const
|
|
103792
|
-
const
|
|
104737
|
+
const overlay = environment.context.__valueOverlay;
|
|
104738
|
+
const runtime = environment.context.__runtimeSessionValues;
|
|
104739
|
+
const bindings = new Map([
|
|
104740
|
+
...environment.context.__saveStaticBindings ?? [],
|
|
104741
|
+
...environment.context.__sessionStaticBindings ?? []
|
|
104742
|
+
]);
|
|
104743
|
+
if (!environment.hasStateChanges) return environment.baseDocument;
|
|
104744
|
+
const snapshot = { ...environment.baseDocument };
|
|
104745
|
+
const baseValues = Array.isArray(snapshot.values) ? snapshot.values : [];
|
|
104746
|
+
const values = [...baseValues];
|
|
103793
104747
|
const byId = /* @__PURE__ */ new Map();
|
|
103794
104748
|
values.forEach((value, index) => {
|
|
103795
104749
|
if (isRecord10(value) && typeof value.id === "string")
|
|
@@ -103806,20 +104760,17 @@ function snapshotEnvironmentDocument(environment) {
|
|
|
103806
104760
|
values[index] = cloned;
|
|
103807
104761
|
}
|
|
103808
104762
|
};
|
|
103809
|
-
for (const row of
|
|
103810
|
-
|
|
103811
|
-
for (const row of environment.context.__runtimeSessionValues?.values() ?? [])
|
|
103812
|
-
mergeRow(row);
|
|
104763
|
+
for (const row of overlay?.values() ?? []) mergeRow(row);
|
|
104764
|
+
for (const row of runtime?.values() ?? []) mergeRow(row);
|
|
103813
104765
|
snapshot.values = values;
|
|
103814
|
-
|
|
103815
|
-
|
|
103816
|
-
|
|
103817
|
-
|
|
103818
|
-
|
|
103819
|
-
|
|
103820
|
-
|
|
103821
|
-
|
|
103822
|
-
member.valueId = bindings.get(member.id) ?? null;
|
|
104766
|
+
if (bindings.size > 0) {
|
|
104767
|
+
const baseMembers = Array.isArray(snapshot.members) ? snapshot.members : [];
|
|
104768
|
+
snapshot.members = baseMembers.map((member) => {
|
|
104769
|
+
if (!isRecord10(member) || typeof member.id !== "string" || !bindings.has(member.id)) {
|
|
104770
|
+
return member;
|
|
104771
|
+
}
|
|
104772
|
+
return { ...member, valueId: bindings.get(member.id) ?? null };
|
|
104773
|
+
});
|
|
103823
104774
|
}
|
|
103824
104775
|
return snapshot;
|
|
103825
104776
|
}
|
|
@@ -103840,10 +104791,7 @@ function copyMocks(source, target) {
|
|
|
103840
104791
|
}
|
|
103841
104792
|
}
|
|
103842
104793
|
function cloneTestEnvironment(source) {
|
|
103843
|
-
const cloned = createTestEnvironment(
|
|
103844
|
-
snapshotEnvironmentDocument(source),
|
|
103845
|
-
true
|
|
103846
|
-
);
|
|
104794
|
+
const cloned = createTestEnvironment(snapshotEnvironmentDocument(source));
|
|
103847
104795
|
copyMocks(source, cloned);
|
|
103848
104796
|
return cloned;
|
|
103849
104797
|
}
|
|
@@ -103854,10 +104802,14 @@ function runCallback(environment, delegate, deadlineMs) {
|
|
|
103854
104802
|
__indexes: void 0,
|
|
103855
104803
|
wallClockDeadlineMs: deadlineMs
|
|
103856
104804
|
});
|
|
103857
|
-
|
|
103858
|
-
|
|
103859
|
-
|
|
103860
|
-
|
|
104805
|
+
try {
|
|
104806
|
+
evaluateNSDelegate(
|
|
104807
|
+
bindNeoScriptDelegateToContext(delegate, environment.context),
|
|
104808
|
+
environment.context
|
|
104809
|
+
);
|
|
104810
|
+
} finally {
|
|
104811
|
+
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;
|
|
104812
|
+
}
|
|
103861
104813
|
}
|
|
103862
104814
|
function failureFor(error, file, position, member = null) {
|
|
103863
104815
|
const timeout = error instanceof NeoScriptWallClockTimeoutError;
|
|
@@ -103883,18 +104835,22 @@ function suiteHasSelectedTests(suite, selected2) {
|
|
|
103883
104835
|
async function executeRegisteredSpec(registered, document, selected2, timeoutMs, interrupted) {
|
|
103884
104836
|
const results = [];
|
|
103885
104837
|
const fileFailures = [];
|
|
104838
|
+
let testDurationMs = 0;
|
|
103886
104839
|
const executeSuite = async (suite, parentEnvironment, inheritedFailures) => {
|
|
103887
104840
|
if (!suiteHasSelectedTests(suite, selected2)) return;
|
|
103888
104841
|
const fixture = cloneTestEnvironment(parentEnvironment);
|
|
103889
104842
|
const suiteFailures = [...inheritedFailures];
|
|
103890
104843
|
const suiteDeadline = Date.now() + timeoutMs;
|
|
103891
104844
|
for (const hook of suite.beforeAll) {
|
|
104845
|
+
const hookStarted = performance.now();
|
|
103892
104846
|
try {
|
|
103893
104847
|
runCallback(fixture, hook, suiteDeadline);
|
|
103894
104848
|
} catch (error) {
|
|
103895
104849
|
suiteFailures.push(
|
|
103896
104850
|
failureFor(error, registered.spec.path, suite, "beforeAll")
|
|
103897
104851
|
);
|
|
104852
|
+
} finally {
|
|
104853
|
+
testDurationMs += performance.now() - hookStarted;
|
|
103898
104854
|
}
|
|
103899
104855
|
}
|
|
103900
104856
|
for (const test of suite.tests) {
|
|
@@ -103902,6 +104858,8 @@ async function executeRegisteredSpec(registered, document, selected2, timeoutMs,
|
|
|
103902
104858
|
const started = performance.now();
|
|
103903
104859
|
const deadline = Date.now() + timeoutMs;
|
|
103904
104860
|
const environment = cloneTestEnvironment(fixture);
|
|
104861
|
+
const startupBeforeTestMs = performance.now() - started;
|
|
104862
|
+
const testStarted = performance.now();
|
|
103905
104863
|
const failures = [...suiteFailures];
|
|
103906
104864
|
let setupFailed = failures.length > 0;
|
|
103907
104865
|
if (!setupFailed) {
|
|
@@ -103938,19 +104896,24 @@ async function executeRegisteredSpec(registered, document, selected2, timeoutMs,
|
|
|
103938
104896
|
}
|
|
103939
104897
|
}
|
|
103940
104898
|
}
|
|
103941
|
-
const
|
|
104899
|
+
const currentTestDurationMs = performance.now() - testStarted;
|
|
104900
|
+
const schedulerStarted = performance.now();
|
|
104901
|
+
await new Promise((resolvePromise) => {
|
|
104902
|
+
setImmediate(resolvePromise);
|
|
104903
|
+
});
|
|
104904
|
+
const startupDurationMs = startupBeforeTestMs + performance.now() - schedulerStarted;
|
|
104905
|
+
testDurationMs += currentTestDurationMs;
|
|
103942
104906
|
results.push({
|
|
103943
104907
|
id: test.id,
|
|
103944
104908
|
file: registered.spec.path,
|
|
103945
104909
|
name: test.name,
|
|
103946
104910
|
fullName: test.fullName,
|
|
103947
104911
|
status: failures.length === 0 ? "passed" : "failed",
|
|
103948
|
-
durationMs,
|
|
104912
|
+
durationMs: startupDurationMs + currentTestDurationMs,
|
|
104913
|
+
startupDurationMs,
|
|
104914
|
+
testDurationMs: currentTestDurationMs,
|
|
103949
104915
|
failures
|
|
103950
104916
|
});
|
|
103951
|
-
await new Promise((resolvePromise) => {
|
|
103952
|
-
setImmediate(resolvePromise);
|
|
103953
|
-
});
|
|
103954
104917
|
if (interrupted()) break;
|
|
103955
104918
|
}
|
|
103956
104919
|
for (const child of suite.suites) {
|
|
@@ -103958,12 +104921,15 @@ async function executeRegisteredSpec(registered, document, selected2, timeoutMs,
|
|
|
103958
104921
|
await executeSuite(child, fixture, suiteFailures);
|
|
103959
104922
|
}
|
|
103960
104923
|
for (const hook of suite.afterAll) {
|
|
104924
|
+
const hookStarted = performance.now();
|
|
103961
104925
|
try {
|
|
103962
104926
|
runCallback(fixture, hook, Date.now() + timeoutMs);
|
|
103963
104927
|
} catch (error) {
|
|
103964
104928
|
fileFailures.push(
|
|
103965
104929
|
failureFor(error, registered.spec.path, suite, "afterAll")
|
|
103966
104930
|
);
|
|
104931
|
+
} finally {
|
|
104932
|
+
testDurationMs += performance.now() - hookStarted;
|
|
103967
104933
|
}
|
|
103968
104934
|
}
|
|
103969
104935
|
};
|
|
@@ -103974,7 +104940,7 @@ async function executeRegisteredSpec(registered, document, selected2, timeoutMs,
|
|
|
103974
104940
|
results.sort(
|
|
103975
104941
|
(left, right) => (registrationOrder.get(left.id) ?? Number.MAX_SAFE_INTEGER) - (registrationOrder.get(right.id) ?? Number.MAX_SAFE_INTEGER)
|
|
103976
104942
|
);
|
|
103977
|
-
return { tests: results, failures: fileFailures };
|
|
104943
|
+
return { tests: results, failures: fileFailures, testDurationMs };
|
|
103978
104944
|
}
|
|
103979
104945
|
function atomicWrite(path, content) {
|
|
103980
104946
|
mkdirSync11(dirname9(path), { recursive: true });
|
|
@@ -104027,8 +104993,12 @@ function maintainNeoTestBuildCache(root, maxBytes = TEST_BUILD_CACHE_LIMIT_BYTES
|
|
|
104027
104993
|
total -= file.size;
|
|
104028
104994
|
}
|
|
104029
104995
|
}
|
|
104996
|
+
function formatTestDuration(durationMs) {
|
|
104997
|
+
return `${durationMs < 10 ? durationMs.toFixed(2) : durationMs.toFixed(1)}ms`;
|
|
104998
|
+
}
|
|
104030
104999
|
async function runTest(workspace, options, dependencies = {}) {
|
|
104031
105000
|
const started = Date.now();
|
|
105001
|
+
const performanceStarted = performance.now();
|
|
104032
105002
|
const testBuildRoot = join16(workspace.root, ".neo", "test-build");
|
|
104033
105003
|
maintainNeoTestBuildCache(testBuildRoot);
|
|
104034
105004
|
const startedAt = new Date(started).toISOString();
|
|
@@ -104041,6 +105011,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104041
105011
|
const selectedTestCountByFile = /* @__PURE__ */ new Map();
|
|
104042
105012
|
const fileFailuresByPath = /* @__PURE__ */ new Map();
|
|
104043
105013
|
const diagnostics = [];
|
|
105014
|
+
let testDurationMs = 0;
|
|
104044
105015
|
let exitCode = 0;
|
|
104045
105016
|
let interrupted = false;
|
|
104046
105017
|
const handleSigint = () => {
|
|
@@ -104056,18 +105027,47 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104056
105027
|
process.on("SIGINT", handleSigint);
|
|
104057
105028
|
let phase = "prepare";
|
|
104058
105029
|
try {
|
|
104059
|
-
|
|
105030
|
+
let candidate = dependencies.prepareLocalCandidate === void 0 ? preparedHookCandidate(workspace) : null;
|
|
105031
|
+
let candidateInputFingerprint = null;
|
|
105032
|
+
let shouldCacheCandidate = false;
|
|
105033
|
+
if (candidate === null) {
|
|
105034
|
+
const canUseCandidateCache = dependencies.prepareLocalCandidate === void 0 || dependencies.fingerprintCandidateInputs !== void 0;
|
|
105035
|
+
if (canUseCandidateCache) {
|
|
105036
|
+
candidateInputFingerprint = dependencies.fingerprintCandidateInputs?.(workspace) ?? fingerprintTestCandidateInputs(workspace);
|
|
105037
|
+
candidate = cachedTestCandidate(workspace, candidateInputFingerprint);
|
|
105038
|
+
}
|
|
105039
|
+
if (candidate === null) {
|
|
105040
|
+
const prepared = dependencies.prepareLocalCandidate === void 0 ? await prepareLocalCandidateV4(workspace) : await dependencies.prepareLocalCandidate(workspace);
|
|
105041
|
+
if (prepared.document === null) {
|
|
105042
|
+
throw new NeoTestReportWriteError(
|
|
105043
|
+
"Local test preparation did not produce a project document."
|
|
105044
|
+
);
|
|
105045
|
+
}
|
|
105046
|
+
candidate = {
|
|
105047
|
+
document: prepared.document,
|
|
105048
|
+
sourceHash: prepared.sourceHash
|
|
105049
|
+
};
|
|
105050
|
+
shouldCacheCandidate = canUseCandidateCache;
|
|
105051
|
+
}
|
|
105052
|
+
}
|
|
104060
105053
|
assertNotInterrupted();
|
|
104061
|
-
if (candidate
|
|
105054
|
+
if (candidate === null) {
|
|
104062
105055
|
throw new NeoTestReportWriteError(
|
|
104063
|
-
"Local test preparation
|
|
105056
|
+
"Local test preparation produced no reusable candidate."
|
|
104064
105057
|
);
|
|
104065
105058
|
}
|
|
105059
|
+
if (shouldCacheCandidate && candidateInputFingerprint !== null) {
|
|
105060
|
+
candidate = cacheTestCandidate(workspace, candidateInputFingerprint, {
|
|
105061
|
+
document: candidate.document,
|
|
105062
|
+
sourceHash: candidate.sourceHash
|
|
105063
|
+
});
|
|
105064
|
+
}
|
|
104066
105065
|
projectFingerprint = `sha256:${candidate.sourceHash}`;
|
|
104067
105066
|
const rawDocument = documentRecord(candidate.document);
|
|
104068
105067
|
const compilationHash = projectCompilationHash(
|
|
104069
105068
|
candidate.sourceHash,
|
|
104070
|
-
rawDocument
|
|
105069
|
+
rawDocument,
|
|
105070
|
+
candidate.documentSha256
|
|
104071
105071
|
);
|
|
104072
105072
|
phase = "select";
|
|
104073
105073
|
let selectedPaths;
|
|
@@ -104126,6 +105126,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104126
105126
|
() => interrupted
|
|
104127
105127
|
);
|
|
104128
105128
|
results.push(...executed.tests);
|
|
105129
|
+
testDurationMs += executed.testDurationMs;
|
|
104129
105130
|
fileFailuresByPath.set(entry.spec.path, executed.failures);
|
|
104130
105131
|
assertNotInterrupted();
|
|
104131
105132
|
}
|
|
@@ -104139,14 +105140,14 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104139
105140
|
compilerRevision: NEOSCRIPT_COMPILER_REVISION,
|
|
104140
105141
|
evaluatorRevision: 4,
|
|
104141
105142
|
projectFingerprint,
|
|
104142
|
-
configurationSha256:
|
|
105143
|
+
configurationSha256: createHash11("sha256").update(JSON.stringify(workspace.config.test ?? {})).digest("hex"),
|
|
104143
105144
|
dependencyGraph: Object.fromEntries(
|
|
104144
105145
|
specs.map((spec) => [spec.path, [projectFingerprint]])
|
|
104145
105146
|
),
|
|
104146
105147
|
artifacts: specs.map((spec) => ({
|
|
104147
105148
|
path: spec.path,
|
|
104148
|
-
sourceSha256:
|
|
104149
|
-
artifactSha256:
|
|
105149
|
+
sourceSha256: createHash11("sha256").update(spec.source).digest("hex"),
|
|
105150
|
+
artifactSha256: createHash11("sha256").update(JSON.stringify(spec.action)).digest("hex")
|
|
104150
105151
|
}))
|
|
104151
105152
|
};
|
|
104152
105153
|
atomicWrite(
|
|
@@ -104174,7 +105175,16 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104174
105175
|
0
|
|
104175
105176
|
);
|
|
104176
105177
|
const skipped = Math.max(0, selectedTestTotal - results.length);
|
|
104177
|
-
const durationMs =
|
|
105178
|
+
const durationMs = performance.now() - performanceStarted;
|
|
105179
|
+
const startupDurationMs = Math.max(0, durationMs - testDurationMs);
|
|
105180
|
+
const perTestStartupDurationMs = results.reduce(
|
|
105181
|
+
(sum, result) => sum + result.startupDurationMs,
|
|
105182
|
+
0
|
|
105183
|
+
);
|
|
105184
|
+
const sharedStartupDurationMs = Math.max(
|
|
105185
|
+
0,
|
|
105186
|
+
startupDurationMs - perTestStartupDurationMs
|
|
105187
|
+
);
|
|
104178
105188
|
const testFiles = specs.map((spec) => {
|
|
104179
105189
|
const tests = results.filter((result) => result.file === spec.path);
|
|
104180
105190
|
const failures = fileFailuresByPath.get(spec.path) ?? [];
|
|
@@ -104191,7 +105201,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104191
105201
|
success: exitCode === 0,
|
|
104192
105202
|
projectFingerprint,
|
|
104193
105203
|
seed: Number.parseInt(
|
|
104194
|
-
|
|
105204
|
+
createHash11("sha256").update(projectFingerprint ?? "neo-test:no-project").digest("hex").slice(0, 8),
|
|
104195
105205
|
16
|
|
104196
105206
|
),
|
|
104197
105207
|
selection: {
|
|
@@ -104206,7 +105216,10 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104206
105216
|
failed,
|
|
104207
105217
|
skipped,
|
|
104208
105218
|
todo: 0,
|
|
104209
|
-
durationMs
|
|
105219
|
+
durationMs,
|
|
105220
|
+
startupDurationMs,
|
|
105221
|
+
sharedStartupDurationMs,
|
|
105222
|
+
testDurationMs
|
|
104210
105223
|
},
|
|
104211
105224
|
testFiles,
|
|
104212
105225
|
diagnostics,
|
|
@@ -104231,9 +105244,12 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104231
105244
|
if (options.reporter === "json") {
|
|
104232
105245
|
if (options.outputFile === null) process.stdout.write(serialized);
|
|
104233
105246
|
} else {
|
|
105247
|
+
console.log(
|
|
105248
|
+
`\u21BB shared startup (${formatTestDuration(report.summary.sharedStartupDurationMs)})`
|
|
105249
|
+
);
|
|
104234
105250
|
for (const result of results) {
|
|
104235
105251
|
console.log(
|
|
104236
|
-
`${result.status === "passed" ? "\u2713" : "\u2717"} ${result.file} > ${result.name} (${result.durationMs.
|
|
105252
|
+
`${result.status === "passed" ? "\u2713" : "\u2717"} ${result.file} > ${result.name} (total ${formatTestDuration(result.durationMs)}; test ${formatTestDuration(result.testDurationMs)}; startup ${formatTestDuration(result.startupDurationMs)})`
|
|
104237
105253
|
);
|
|
104238
105254
|
for (const failure of result.failures)
|
|
104239
105255
|
console.log(` ${failure.message}`);
|
|
@@ -104254,7 +105270,7 @@ async function runTest(workspace, options, dependencies = {}) {
|
|
|
104254
105270
|
for (const diagnostic of diagnostics)
|
|
104255
105271
|
console.log(`\u2717 ${diagnostic.message}`);
|
|
104256
105272
|
console.log(
|
|
104257
|
-
`${report.summary.passed} passed, ${report.summary.failed} failed (${report.summary.durationMs}
|
|
105273
|
+
`${report.summary.passed} passed, ${report.summary.failed} failed (total ${formatTestDuration(report.summary.durationMs)}; test ${formatTestDuration(report.summary.testDurationMs)}; startup ${formatTestDuration(report.summary.startupDurationMs)})`
|
|
104258
105274
|
);
|
|
104259
105275
|
}
|
|
104260
105276
|
if (!report.success) process.exitCode = exitCode;
|
|
@@ -104301,7 +105317,7 @@ async function inspectNeoTestCompilation(workspace, dependencies = {}) {
|
|
|
104301
105317
|
errors
|
|
104302
105318
|
};
|
|
104303
105319
|
}
|
|
104304
|
-
var TEST_BUILD_CACHE_LIMIT_BYTES, ABANDONED_TEMP_MAX_AGE_MS, NeoTestUsageError, NeoTestNoTestsError, NeoTestRegistrationError, NeoTestReportWriteError, NeoTestPreparedCandidateError, NeoTestInterruptedError, NeoTestAssertionError, ERROR_SOURCE_POSITIONS, REGISTRATION_IDS;
|
|
105320
|
+
var TEST_BUILD_CACHE_LIMIT_BYTES, ABANDONED_TEMP_MAX_AGE_MS, TEST_CANDIDATE_CACHE_REVISION, NeoTestUsageError, NeoTestNoTestsError, NeoTestRegistrationError, NeoTestReportWriteError, NeoTestPreparedCandidateError, NeoTestInterruptedError, NeoTestAssertionError, ERROR_SOURCE_POSITIONS, SHARED_EVALUATOR_BASES, REGISTRATION_IDS;
|
|
104305
105321
|
var init_test = __esm({
|
|
104306
105322
|
"src/commands/test.ts"() {
|
|
104307
105323
|
"use strict";
|
|
@@ -104316,6 +105332,7 @@ var init_test = __esm({
|
|
|
104316
105332
|
init_push_hook();
|
|
104317
105333
|
TEST_BUILD_CACHE_LIMIT_BYTES = 512 * 1024 * 1024;
|
|
104318
105334
|
ABANDONED_TEMP_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
105335
|
+
TEST_CANDIDATE_CACHE_REVISION = 1;
|
|
104319
105336
|
NeoTestUsageError = class extends Error {
|
|
104320
105337
|
name = "NeoTestUsageError";
|
|
104321
105338
|
};
|
|
@@ -104347,6 +105364,7 @@ var init_test = __esm({
|
|
|
104347
105364
|
received;
|
|
104348
105365
|
};
|
|
104349
105366
|
ERROR_SOURCE_POSITIONS = /* @__PURE__ */ new WeakMap();
|
|
105367
|
+
SHARED_EVALUATOR_BASES = /* @__PURE__ */ new WeakMap();
|
|
104350
105368
|
REGISTRATION_IDS = /* @__PURE__ */ new Set([
|
|
104351
105369
|
NEO_TEST_IDS.describe,
|
|
104352
105370
|
NEO_TEST_IDS.test,
|
|
@@ -107742,7 +108760,8 @@ function loadWorkspaceForCommand(args) {
|
|
|
107742
108760
|
// A reset reconstructs the working copy from the server and may therefore
|
|
107743
108761
|
// discard an unsupported pre-cutover cache. No other command gets this
|
|
107744
108762
|
// exception, so format 2 never becomes an active compatibility read path.
|
|
107745
|
-
discardLegacyFormat2State: args.command === "pull" && boolFlag(args, "reset")
|
|
108763
|
+
discardLegacyFormat2State: args.command === "pull" && boolFlag(args, "reset"),
|
|
108764
|
+
fingerprintStateSource: args.command === "test"
|
|
107746
108765
|
});
|
|
107747
108766
|
const apiOverride = stringFlag(args, "api");
|
|
107748
108767
|
if (apiOverride !== null) {
|
|
@@ -107920,7 +108939,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
107920
108939
|
async function main() {
|
|
107921
108940
|
const args = parseArgs(process.argv.slice(2));
|
|
107922
108941
|
if (args.command === "--version") {
|
|
107923
|
-
console.log("0.26.
|
|
108942
|
+
console.log("0.26.2");
|
|
107924
108943
|
return;
|
|
107925
108944
|
}
|
|
107926
108945
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|