carrick 0.3.127 → 0.3.129
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/package.json +6 -6
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/sidecar/dist/src/capture/anchors.js +5 -1
- package/sidecar/dist/src/capture/check-classify.d.ts +8 -1
- package/sidecar/dist/src/capture/check-classify.js +21 -1
- package/sidecar/dist/src/capture/check-probe.d.ts +7 -7
- package/sidecar/dist/src/capture/check-probe.js +13 -14
- package/sidecar/dist/src/capture/check.js +5 -5
- package/sidecar/dist/src/index.js +43 -4
- package/sidecar/dist/src/library-claims.d.ts +63 -3
- package/sidecar/dist/src/library-claims.js +380 -39
- package/sidecar/dist/src/retype.js +36 -0
- package/sidecar/dist/src/server-labels.d.ts +29 -0
- package/sidecar/dist/src/server-labels.js +45 -0
- package/sidecar/dist/src/stated-params.d.ts +138 -0
- package/sidecar/dist/src/stated-params.js +547 -0
- package/sidecar/dist/src/type-inferrer.d.ts +89 -1
- package/sidecar/dist/src/type-inferrer.js +429 -17
- package/sidecar/dist/src/types.d.ts +76 -3
- package/sidecar/dist/src/unwidened.d.ts +11 -2
- package/sidecar/dist/src/unwidened.js +50 -3
- package/sidecar/dist/src/validators.d.ts +228 -59
- package/sidecar/dist/src/validators.js +45 -2
|
@@ -130,6 +130,14 @@ const HTTP_V2_RULES = { http: false, message: true, ops: new Set(['request']), m
|
|
|
130
130
|
* the method from the member's own name (`get` registers GET) or from a slot.
|
|
131
131
|
*/
|
|
132
132
|
const SERVER_RULES = { http: false, message: true, ops: new Set(['receive']), methods: ROUTE_METHODS };
|
|
133
|
+
/**
|
|
134
|
+
* A server's rules as `labelledMembers` reads them (carrick#2674): a `send`
|
|
135
|
+
* op is the reply a handler sends back through its reply parameter, on the
|
|
136
|
+
* connection the request came in on, so it names nothing on the wire. Only
|
|
137
|
+
* the stated-parameter reading takes these; `run` keeps `SERVER_RULES`, so
|
|
138
|
+
* no verdict the scanner reads rows from changes.
|
|
139
|
+
*/
|
|
140
|
+
const SERVER_REPLY_RULES = { ...SERVER_RULES, ops: new Set(['receive', 'send']), namelessSends: true };
|
|
133
141
|
/**
|
|
134
142
|
* The role table: the role alone picks the checks. A role this build does
|
|
135
143
|
* not read yet (GraphQL executors) answers `role_unsupported`, and `none`
|
|
@@ -263,7 +271,8 @@ export class LibraryClaimsVerifier {
|
|
|
263
271
|
* A check on an instance or a scope reads the maker or scope claims of the
|
|
264
272
|
* same request first, whatever their place in it.
|
|
265
273
|
*/
|
|
266
|
-
run(fromDir, checks, budgetMs, scanRoot) {
|
|
274
|
+
run(fromDir, checks, budgetMs, scanRoot, options = {}) {
|
|
275
|
+
const { observe, readReplies = false, typePackages = {} } = options;
|
|
267
276
|
const deadline = performance.now() + budgetMs;
|
|
268
277
|
const stamp = (check, outcome) => outcome.verdict === 'verified'
|
|
269
278
|
? {
|
|
@@ -294,7 +303,11 @@ export class LibraryClaimsVerifier {
|
|
|
294
303
|
if (check.role === 'http_client' && hasV2Field(check.claim))
|
|
295
304
|
v2Exports.add(exportKey(check));
|
|
296
305
|
}
|
|
297
|
-
const rulesFor = (check) => check.role === 'http_client' && v2Exports.has(exportKey(check))
|
|
306
|
+
const rulesFor = (check) => check.role === 'http_client' && v2Exports.has(exportKey(check))
|
|
307
|
+
? HTTP_V2_RULES
|
|
308
|
+
: readReplies && check.role === 'server_framework'
|
|
309
|
+
? SERVER_REPLY_RULES
|
|
310
|
+
: ROLE_TABLE[check.role];
|
|
298
311
|
for (const check of checks) {
|
|
299
312
|
const key = exportKey(check);
|
|
300
313
|
if (!importIndex.has(key)) {
|
|
@@ -448,14 +461,19 @@ export class LibraryClaimsVerifier {
|
|
|
448
461
|
if (types.some(type => reader.returnSaysNothing(type))) {
|
|
449
462
|
return { reason: receiverPath.maker ? 'maker_unresolved' : 'export_untyped' };
|
|
450
463
|
}
|
|
464
|
+
const claim = check.claim;
|
|
465
|
+
const keyBound = claim.kind === 'op' && claim.name !== undefined && 'bound' in claim.name && claim.name.bound === 'key'
|
|
466
|
+
? verifiedCollects(check.package).length > 0
|
|
467
|
+
: undefined;
|
|
451
468
|
return {
|
|
452
469
|
value: types.map(type => ({
|
|
453
470
|
type,
|
|
454
471
|
pkg: check.package,
|
|
455
|
-
home: reader.homeOf(check.package, [exported.target, ...typeSymbols(type)]),
|
|
472
|
+
home: withTypePackages(reader.homeOf(check.package, [exported.target, ...typeSymbols(type)]), typePackages[check.package]),
|
|
456
473
|
makerBindsName,
|
|
457
474
|
scoped: receiverPath.scope !== undefined,
|
|
458
475
|
makerHolding,
|
|
476
|
+
...(keyBound === undefined ? {} : { keyBound }),
|
|
459
477
|
madeBy: receiverPath.maker?.member === null && receiverPath.scope === undefined ? check.export : undefined,
|
|
460
478
|
})),
|
|
461
479
|
};
|
|
@@ -480,6 +498,32 @@ export class LibraryClaimsVerifier {
|
|
|
480
498
|
return { reason: 'unresolved' };
|
|
481
499
|
return { value: returns };
|
|
482
500
|
};
|
|
501
|
+
/**
|
|
502
|
+
* The `collects` scope checks of the request (#2474 R6a) that verify,
|
|
503
|
+
* of one package or of any: judged only when a claim reads them, so a
|
|
504
|
+
* request with none judges exactly what it judged before.
|
|
505
|
+
*/
|
|
506
|
+
const verifiedCollects = (pkg) => checks
|
|
507
|
+
.map((other, i) => ({ other, i }))
|
|
508
|
+
.filter(({ other }) => other.claim.kind === 'scope' && other.claim.collects !== undefined && (pkg === undefined || other.package === pkg))
|
|
509
|
+
.filter(({ i }) => judge(i).outcome.verdict === 'verified')
|
|
510
|
+
.map(({ i }) => i);
|
|
511
|
+
/**
|
|
512
|
+
* What the request's verified `collects` scopes return, read at their
|
|
513
|
+
* defaults: the collections an adapter's `runs` slot can take, matched
|
|
514
|
+
* across packages (an HTTP framework's adapter serves another
|
|
515
|
+
* package's router). Undefined when there are none.
|
|
516
|
+
*/
|
|
517
|
+
const collections = () => {
|
|
518
|
+
const types = new Set();
|
|
519
|
+
for (const i of verifiedCollects()) {
|
|
520
|
+
const built = builtReceiver(checks[i]);
|
|
521
|
+
const read = holdingReturns([judge(i)], built === undefined ? undefined : atDefaults(checks[i], built));
|
|
522
|
+
if ('value' in read)
|
|
523
|
+
read.value.forEach(type => types.add(type));
|
|
524
|
+
}
|
|
525
|
+
return types.size > 0 ? [...types] : undefined;
|
|
526
|
+
};
|
|
483
527
|
const judge = (index) => {
|
|
484
528
|
const cached = judged.get(index);
|
|
485
529
|
if (cached)
|
|
@@ -535,16 +579,28 @@ export class LibraryClaimsVerifier {
|
|
|
535
579
|
return { outcome: unchecked(receivers.reason) };
|
|
536
580
|
const built = builtReceiver(check);
|
|
537
581
|
const builtAtDefaults = built === undefined ? undefined : atDefaults(check, built);
|
|
582
|
+
// An adapter's `runs` is read against the request's collections only
|
|
583
|
+
// when today's reading refuses it (#2474 R6a): `judgeMake` asks.
|
|
584
|
+
const collectionsOf = check.claim.kind === 'make' && check.claim.runs !== undefined ? collections : undefined;
|
|
538
585
|
const holding = [];
|
|
539
586
|
const declarations = [];
|
|
587
|
+
const members = [];
|
|
588
|
+
const bodyMembers = [];
|
|
540
589
|
for (const receiver of receivers.value) {
|
|
541
|
-
const result = reader.judgeMessage(receiver, check.claim, rules, builtAtDefaults);
|
|
590
|
+
const result = reader.judgeMessage(receiver, check.claim, rules, builtAtDefaults, collectionsOf);
|
|
542
591
|
if (result.outcome.verdict !== 'verified')
|
|
543
592
|
return result;
|
|
544
593
|
holding.push(...(result.holding ?? []));
|
|
545
594
|
declarations.push(...(result.outcome.declarations ?? []));
|
|
595
|
+
members.push(...(result.outcome.members ?? []));
|
|
596
|
+
bodyMembers.push(...(result.outcome.bodyMembers ?? []));
|
|
546
597
|
}
|
|
547
|
-
|
|
598
|
+
const verified = declarations.length > 0 ? { verdict: 'verified', declarations: sortedDeclarations(declarations) } : { ...VERIFIED };
|
|
599
|
+
if (verified.verdict === 'verified' && members.length > 0)
|
|
600
|
+
verified.members = members;
|
|
601
|
+
if (verified.verdict === 'verified' && bodyMembers.length > 0)
|
|
602
|
+
verified.bodyMembers = bodyMembers;
|
|
603
|
+
return { outcome: verified, holding };
|
|
548
604
|
};
|
|
549
605
|
const semantics = [];
|
|
550
606
|
for (let index = 0; index < checks.length; index++) {
|
|
@@ -553,7 +609,9 @@ export class LibraryClaimsVerifier {
|
|
|
553
609
|
semantics.push(stamp(check, unchecked('budget')));
|
|
554
610
|
continue;
|
|
555
611
|
}
|
|
556
|
-
|
|
612
|
+
const outcome = judge(index).outcome;
|
|
613
|
+
observe?.(check, outcome);
|
|
614
|
+
semantics.push(stamp(check, outcome));
|
|
557
615
|
}
|
|
558
616
|
return {
|
|
559
617
|
semantics,
|
|
@@ -564,6 +622,42 @@ export class LibraryClaimsVerifier {
|
|
|
564
622
|
this.project.removeSourceFile(probe);
|
|
565
623
|
}
|
|
566
624
|
}
|
|
625
|
+
/**
|
|
626
|
+
* The members a service's server-framework labels name, read with the
|
|
627
|
+
* verifier itself so only a label that verifies in the service's own
|
|
628
|
+
* program counts (carrick#2674): each verified `send` op that carries a
|
|
629
|
+
* `payload` slot, and each verified `receive` op whose `request` names a
|
|
630
|
+
* `body` path. Other checks are not judged.
|
|
631
|
+
*/
|
|
632
|
+
labelledMembers(fromDir, checks, budgetMs, scanRoot, typePackages = {}) {
|
|
633
|
+
const sends = new Map();
|
|
634
|
+
const bodies = new Set();
|
|
635
|
+
const wanted = checks.filter(check => check.role === 'server_framework' &&
|
|
636
|
+
check.claim.kind === 'op' &&
|
|
637
|
+
((check.claim.op === 'send' && check.claim.payload !== undefined) ||
|
|
638
|
+
(check.claim.op === 'receive' && check.claim.request?.body !== undefined)));
|
|
639
|
+
// A receiver an op is read on can need the maker or scope claims beside it.
|
|
640
|
+
const context = checks.filter(check => check.role === 'server_framework' && (check.claim.kind === 'make' || check.claim.kind === 'scope'));
|
|
641
|
+
if (wanted.length === 0)
|
|
642
|
+
return { sends, bodies };
|
|
643
|
+
const outcomes = {};
|
|
644
|
+
const observe = (check, outcome) => {
|
|
645
|
+
if (check.claim.kind !== 'op')
|
|
646
|
+
return;
|
|
647
|
+
const read = outcome.verdict === 'verified' ? 'verified' : `${outcome.verdict} ${outcome.reason}`;
|
|
648
|
+
outcomes[read] = (outcomes[read] ?? 0) + 1;
|
|
649
|
+
if (outcome.verdict !== 'verified')
|
|
650
|
+
return;
|
|
651
|
+
if (check.claim.op === 'send' && check.claim.payload !== undefined) {
|
|
652
|
+
for (const member of outcome.members ?? [])
|
|
653
|
+
sends.set(declarationKey(member), check.claim.payload);
|
|
654
|
+
}
|
|
655
|
+
for (const member of outcome.bodyMembers ?? [])
|
|
656
|
+
bodies.add(declarationKey(member));
|
|
657
|
+
};
|
|
658
|
+
this.run(fromDir, [...context, ...wanted], budgetMs, scanRoot, { observe, readReplies: true, typePackages });
|
|
659
|
+
return { sends, bodies, outcomes };
|
|
660
|
+
}
|
|
567
661
|
/**
|
|
568
662
|
* Each specifier's declared surface, read with the verifier's predicates
|
|
569
663
|
* (carrick#1660): every value export (or only those `only` names for the
|
|
@@ -668,7 +762,8 @@ function resolvedBuild(checker, statement) {
|
|
|
668
762
|
* array of `[package, exports]` for every surface that listed at least one
|
|
669
763
|
* export, sorted by `package` (code unit order). A specifier that lists
|
|
670
764
|
* nothing (unresolved, local, no value exports) is left out, so asking for a
|
|
671
|
-
* subpath a version does not have changes nothing.
|
|
765
|
+
* subpath a version does not have changes nothing. Handler members are not
|
|
766
|
+
* hashed. Type text already names
|
|
672
767
|
* the request's directory as `<root>`.
|
|
673
768
|
*/
|
|
674
769
|
export function fullSurfaceSha256(surfaces) {
|
|
@@ -676,7 +771,10 @@ export function fullSurfaceSha256(surfaces) {
|
|
|
676
771
|
.filter(surface => surface.reason === undefined && surface.exports.length > 0)
|
|
677
772
|
.map(surface => [surface.package, surface.exports])
|
|
678
773
|
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
|
|
679
|
-
|
|
774
|
+
// A member's `handlers` (carrick#2674) is out of the hash at every depth, so
|
|
775
|
+
// a package's key does not change when the lister learns to list them.
|
|
776
|
+
const text = JSON.stringify(listed, (key, value) => (key === 'handlers' ? undefined : value));
|
|
777
|
+
return crypto.createHash('sha256').update(text).digest('hex');
|
|
680
778
|
}
|
|
681
779
|
function exportKey(check) {
|
|
682
780
|
return JSON.stringify([check.package, check.export]);
|
|
@@ -733,17 +831,31 @@ function placementInvalid(claim) {
|
|
|
733
831
|
return of === undefined || (of.maker === undefined && of.scope === undefined);
|
|
734
832
|
}
|
|
735
833
|
/**
|
|
736
|
-
* Where a handler's request holds its path and
|
|
737
|
-
* a receive op with a handler, and names `path
|
|
738
|
-
* it gives is non-empty.
|
|
834
|
+
* Where a handler's request holds its path, method and body (#2474 R0,
|
|
835
|
+
* carrick#2674) is read on a receive op with a handler, and names `path`,
|
|
836
|
+
* `url` or `body`; every member path it gives is non-empty.
|
|
739
837
|
*/
|
|
740
838
|
function requestAtValid(claim) {
|
|
741
839
|
const request = claim.request;
|
|
742
840
|
if (claim.op !== 'receive' || claim.handler === undefined)
|
|
743
841
|
return false;
|
|
744
|
-
if (request.path === undefined && request.url === undefined)
|
|
842
|
+
if (request.path === undefined && request.url === undefined && request.body === undefined)
|
|
745
843
|
return false;
|
|
746
|
-
return [request.path, request.url, request.method].every(members => members === undefined || members.length > 0);
|
|
844
|
+
return [request.path, request.url, request.method, request.body].every(members => members === undefined || members.length > 0);
|
|
845
|
+
}
|
|
846
|
+
/** A receiver's home packages, with the type-only packages the store lists for its package. */
|
|
847
|
+
function withTypePackages(home, typePackages) {
|
|
848
|
+
return typePackages && typePackages.length > 0 ? new Set([...home, ...typePackages]) : home;
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* A declaration's key within one process: its file as the compiler names it
|
|
852
|
+
* and its start. Two programs of one project name a declaration alike, so a
|
|
853
|
+
* label read in the verifier's probe program joins a member read in the
|
|
854
|
+
* inferrer's (carrick#2674).
|
|
855
|
+
*/
|
|
856
|
+
export function declarationKey(declaration) {
|
|
857
|
+
const file = declaration.getSourceFile();
|
|
858
|
+
return `${file.fileName}:${declaration.getStart(file)}`;
|
|
747
859
|
}
|
|
748
860
|
/**
|
|
749
861
|
* A message check names a receiver its claim can be read on (contract
|
|
@@ -1502,10 +1614,10 @@ class DeclarationReader {
|
|
|
1502
1614
|
* overloads it holds on. `built` is the probe's no-argument build of the
|
|
1503
1615
|
* receiver a maker or scope claim makes (see `returnOf`).
|
|
1504
1616
|
*/
|
|
1505
|
-
judgeMessage(receiver, claim, rules, built) {
|
|
1617
|
+
judgeMessage(receiver, claim, rules, built, collections) {
|
|
1506
1618
|
switch (claim.kind) {
|
|
1507
1619
|
case 'make':
|
|
1508
|
-
return this.judgeMake(receiver, claim, built);
|
|
1620
|
+
return this.judgeMake(receiver, claim, built, collections);
|
|
1509
1621
|
case 'scope':
|
|
1510
1622
|
return this.judgeScope(receiver, claim, built);
|
|
1511
1623
|
case 'op':
|
|
@@ -1523,8 +1635,15 @@ class DeclarationReader {
|
|
|
1523
1635
|
* defaults (`returnOf`). Those overloads are the ones an instance is read
|
|
1524
1636
|
* through. A definition (`task({ id, run })`) is a maker with a `name` and a
|
|
1525
1637
|
* `handler` slot; a queue (`new Queue("emails")`) one with a positional name.
|
|
1526
|
-
|
|
1527
|
-
|
|
1638
|
+
*
|
|
1639
|
+
* An adapter (#2474 R6a, contract amendment 3 on carrick#2434) is a maker
|
|
1640
|
+
* whose `runs` slot takes a collection rather than a function. Today's
|
|
1641
|
+
* reading runs first, unchanged; only an overload it refuses on `runs` is
|
|
1642
|
+
* read again, when the request holds verified `collects` scopes
|
|
1643
|
+
* (`collections`), with `runs` taking what one of them returns
|
|
1644
|
+
* (`runsCollectionOutcome`). With no such scope this arm never runs.
|
|
1645
|
+
*/
|
|
1646
|
+
judgeMake(receiver, claim, built, collections) {
|
|
1528
1647
|
const layout = this.layout({
|
|
1529
1648
|
base: claim.base,
|
|
1530
1649
|
prefix: claim.prefix,
|
|
@@ -1542,6 +1661,12 @@ class DeclarationReader {
|
|
|
1542
1661
|
let best;
|
|
1543
1662
|
for (const signature of callee.signatures) {
|
|
1544
1663
|
let result = this.messageSignatureOutcome(signature, layout.value, labels);
|
|
1664
|
+
if (result.outcome.verdict !== 'verified' && result.outcome.reason.startsWith('runs_') && collections !== undefined) {
|
|
1665
|
+
const collected = collections();
|
|
1666
|
+
if (collected !== undefined) {
|
|
1667
|
+
result = this.messageSignatureOutcome(signature, layout.value, labels, declared => this.runsCollectionOutcome(signature, declared, collected));
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1545
1670
|
if (result.rank === Infinity && this.returnSaysNothing(this.returnOf(signature, built))) {
|
|
1546
1671
|
result = { rank: 6, outcome: unchecked('maker_unresolved') };
|
|
1547
1672
|
}
|
|
@@ -1570,12 +1695,23 @@ class DeclarationReader {
|
|
|
1570
1695
|
* overloads: a `>scope:` receiver read through it is not resolved.
|
|
1571
1696
|
* `runs` without `yields` (or the reverse), or `mounts` beside either, is
|
|
1572
1697
|
* `claim_invalid`.
|
|
1698
|
+
*
|
|
1699
|
+
* Procedure routers (#2474 R6a, contract amendment 3 on carrick#2434): a
|
|
1700
|
+
* scope carries exactly one of `name` and `collects`, and `collects` never
|
|
1701
|
+
* beside `runs`, `yields` or `mounts` (`claim_invalid`). With `collects`
|
|
1702
|
+
* the member takes an object of procedures there (`collectsOutcome`), and
|
|
1703
|
+
* its return, the collection, is read as a plain scope's is.
|
|
1573
1704
|
*/
|
|
1574
1705
|
judgeScope(receiver, claim, built) {
|
|
1575
1706
|
if ((claim.runs === undefined) !== (claim.yields === undefined))
|
|
1576
1707
|
return { outcome: unchecked('claim_invalid') };
|
|
1577
1708
|
if (claim.mounts !== undefined && claim.runs !== undefined)
|
|
1578
1709
|
return { outcome: unchecked('claim_invalid') };
|
|
1710
|
+
if ((claim.name === undefined) === (claim.collects === undefined))
|
|
1711
|
+
return { outcome: unchecked('claim_invalid') };
|
|
1712
|
+
if (claim.collects !== undefined && (claim.runs !== undefined || claim.mounts !== undefined)) {
|
|
1713
|
+
return { outcome: unchecked('claim_invalid') };
|
|
1714
|
+
}
|
|
1579
1715
|
const binds = claim.runs !== undefined || claim.mounts !== undefined;
|
|
1580
1716
|
const layout = this.layout({ name: claim.name, runs: claim.runs, mounts: claim.mounts });
|
|
1581
1717
|
if ('failure' in layout)
|
|
@@ -1598,6 +1734,11 @@ class DeclarationReader {
|
|
|
1598
1734
|
if (mounted)
|
|
1599
1735
|
result = { rank: 5, outcome: mounted };
|
|
1600
1736
|
}
|
|
1737
|
+
if (result.rank === Infinity && claim.collects !== undefined) {
|
|
1738
|
+
const collected = this.collectsOutcome(signature, claim.collects);
|
|
1739
|
+
if (collected)
|
|
1740
|
+
result = { rank: 5, outcome: collected };
|
|
1741
|
+
}
|
|
1601
1742
|
if (result.rank === Infinity && !binds && this.returnSaysNothing(this.returnOf(signature, built))) {
|
|
1602
1743
|
result = { rank: 6, outcome: unchecked('scope_unresolved') };
|
|
1603
1744
|
}
|
|
@@ -1646,6 +1787,63 @@ class DeclarationReader {
|
|
|
1646
1787
|
return erased ? undefined : failed('mounts_not_instance');
|
|
1647
1788
|
return this.checker.isTypeAssignableTo(receiver.type, slot) ? undefined : failed('mounts_not_instance');
|
|
1648
1789
|
}
|
|
1790
|
+
/**
|
|
1791
|
+
* `collects: { arg, key?, join }` on a scope (#2474 R6a): the parameter
|
|
1792
|
+
* there is an object type that is not a function, whose keys name the
|
|
1793
|
+
* procedures. A parameter typed `any`, `unknown`, `{}` or by an
|
|
1794
|
+
* unconstrained type parameter says nothing (`collects_untyped`).
|
|
1795
|
+
* Undefined when it holds.
|
|
1796
|
+
*/
|
|
1797
|
+
collectsOutcome(signature, collects) {
|
|
1798
|
+
let declared = this.keyParameterAt(signature, collects.arg);
|
|
1799
|
+
if (declared !== undefined && collects.key !== undefined) {
|
|
1800
|
+
const property = this.declaredProperty(declared, collects.key);
|
|
1801
|
+
declared = property ? this.throughConstraint(this.checker.getTypeOfSymbol(property)) : undefined;
|
|
1802
|
+
}
|
|
1803
|
+
if (declared === undefined)
|
|
1804
|
+
return failed('param_missing');
|
|
1805
|
+
if (declared === VARIADIC)
|
|
1806
|
+
return unchecked('collects_untyped');
|
|
1807
|
+
const parts = this.parts(declared);
|
|
1808
|
+
if (parts.length === 0)
|
|
1809
|
+
return failed('collects_not_object');
|
|
1810
|
+
if (parts.some(part => this.isOpenTop(part) || this.isUnconstrained(part) || this.isEmptyObject(part))) {
|
|
1811
|
+
return unchecked('collects_untyped');
|
|
1812
|
+
}
|
|
1813
|
+
if (parts.some(part => !this.isObjectLike(part) || part.getCallSignatures().length > 0)) {
|
|
1814
|
+
return failed('collects_not_object');
|
|
1815
|
+
}
|
|
1816
|
+
return undefined;
|
|
1817
|
+
}
|
|
1818
|
+
/**
|
|
1819
|
+
* An adapter's `runs` slot (#2474 R6a) takes one of `collections`, the
|
|
1820
|
+
* types the request's verified `collects` scopes return, read as a mounted
|
|
1821
|
+
* instance is (`fitsErased`, then assignability). A slot typed `any`,
|
|
1822
|
+
* `unknown`, `{}` or by an unconstrained type parameter says nothing
|
|
1823
|
+
* (`runs_untyped`). Undefined when it holds.
|
|
1824
|
+
*/
|
|
1825
|
+
runsCollectionOutcome(signature, declared, collections) {
|
|
1826
|
+
if (declared === undefined)
|
|
1827
|
+
return failed('param_missing');
|
|
1828
|
+
const slot = this.throughConstraint(declared);
|
|
1829
|
+
if (slot === VARIADIC)
|
|
1830
|
+
return unchecked('runs_untyped');
|
|
1831
|
+
const parts = this.parts(slot);
|
|
1832
|
+
if (parts.length === 0)
|
|
1833
|
+
return failed('runs_not_collection');
|
|
1834
|
+
if (parts.some(part => this.isOpenTop(part) || this.isUnconstrained(part) || this.isEmptyObject(part))) {
|
|
1835
|
+
return unchecked('runs_untyped');
|
|
1836
|
+
}
|
|
1837
|
+
const own = signature.typeParameters ?? [];
|
|
1838
|
+
for (const collection of collections) {
|
|
1839
|
+
const erased = this.fitsErased(collection, slot, own);
|
|
1840
|
+
if (erased === true)
|
|
1841
|
+
return undefined;
|
|
1842
|
+
if (erased === undefined && this.checker.isTypeAssignableTo(collection, slot))
|
|
1843
|
+
return undefined;
|
|
1844
|
+
}
|
|
1845
|
+
return failed('runs_not_collection');
|
|
1846
|
+
}
|
|
1649
1847
|
/**
|
|
1650
1848
|
* `receiver` fits `slot` with the signature's own type parameters
|
|
1651
1849
|
* (`own`) erased to their constraints (carrick#2652), or undefined when
|
|
@@ -1776,7 +1974,7 @@ class DeclarationReader {
|
|
|
1776
1974
|
// what it runs, and one that hands its handler a receiver (a server's
|
|
1777
1975
|
// connection event) names nothing on the wire itself, so neither needs a
|
|
1778
1976
|
// name of its own.
|
|
1779
|
-
const nameless = claim.runs !== undefined || claim.yields !== undefined;
|
|
1977
|
+
const nameless = claim.runs !== undefined || claim.yields !== undefined || (claim.op === 'send' && rules.namelessSends === true);
|
|
1780
1978
|
if ((name === undefined && !nameless) || (claim.op === 'send' && claim.payload === undefined)) {
|
|
1781
1979
|
return unchecked('claim_invalid');
|
|
1782
1980
|
}
|
|
@@ -1785,7 +1983,8 @@ class DeclarationReader {
|
|
|
1785
1983
|
nameSlot = undefined;
|
|
1786
1984
|
}
|
|
1787
1985
|
else if ('bound' in name) {
|
|
1788
|
-
|
|
1986
|
+
const bound = name.bound === 'maker' ? receiver.makerBindsName : name.bound === 'scope' ? receiver.scoped : receiver.keyBound === true;
|
|
1987
|
+
if (!bound)
|
|
1789
1988
|
return failed('name_unbound');
|
|
1790
1989
|
}
|
|
1791
1990
|
else {
|
|
@@ -1812,6 +2011,7 @@ class DeclarationReader {
|
|
|
1812
2011
|
const labels = claim.key_labels ?? {};
|
|
1813
2012
|
let best;
|
|
1814
2013
|
let held = false;
|
|
2014
|
+
const bodyMembers = [];
|
|
1815
2015
|
for (const signature of callee.signatures) {
|
|
1816
2016
|
let result = this.messageSignatureOutcome(signature, layout.value, labels);
|
|
1817
2017
|
if (result.rank === Infinity && claim.yields !== undefined) {
|
|
@@ -1820,7 +2020,7 @@ class DeclarationReader {
|
|
|
1820
2020
|
result = { rank: 5, outcome: given };
|
|
1821
2021
|
}
|
|
1822
2022
|
if (result.rank === Infinity && claim.request !== undefined) {
|
|
1823
|
-
const read = this.requestOutcome(signature, claim.handler, claim.request);
|
|
2023
|
+
const read = this.requestOutcome(signature, claim.handler, claim.request, bodyMembers);
|
|
1824
2024
|
if (read)
|
|
1825
2025
|
result = { rank: 5, outcome: read };
|
|
1826
2026
|
}
|
|
@@ -1835,7 +2035,15 @@ class DeclarationReader {
|
|
|
1835
2035
|
if (boundRuns)
|
|
1836
2036
|
return this.boundRunsOutcome(receiver.makerHolding, boundRuns);
|
|
1837
2037
|
const declarations = this.declarationsOf(callee);
|
|
1838
|
-
|
|
2038
|
+
const members = callee.named
|
|
2039
|
+
? (callee.named.property.declarations ?? [])
|
|
2040
|
+
: callee.signatures.flatMap(signature => signature.getDeclaration() ?? []);
|
|
2041
|
+
return {
|
|
2042
|
+
verdict: 'verified',
|
|
2043
|
+
...(declarations.length > 0 ? { declarations } : {}),
|
|
2044
|
+
...(members.length > 0 ? { members } : {}),
|
|
2045
|
+
...(bodyMembers.length > 0 ? { bodyMembers } : {}),
|
|
2046
|
+
};
|
|
1839
2047
|
}
|
|
1840
2048
|
/**
|
|
1841
2049
|
* Where a verified op or scope's member is declared, as position rows spell
|
|
@@ -1882,6 +2090,18 @@ class DeclarationReader {
|
|
|
1882
2090
|
*/
|
|
1883
2091
|
methodOutcome(claim, rules) {
|
|
1884
2092
|
const words = rules.methods;
|
|
2093
|
+
// A procedure named by its key (#2474 R6a): a receive op with a handler
|
|
2094
|
+
// whose label states its method, a route word. The member names the
|
|
2095
|
+
// procedure kind (`query`), not a verb, so it need not equal the method.
|
|
2096
|
+
if (claim.name !== undefined && 'bound' in claim.name && claim.name.bound === 'key') {
|
|
2097
|
+
if (!words || claim.op !== 'receive' || claim.handler === undefined || claim.method === undefined) {
|
|
2098
|
+
return unchecked('claim_invalid');
|
|
2099
|
+
}
|
|
2100
|
+
if (claim.method_key !== undefined || claim.method_default !== undefined || claim.options !== undefined) {
|
|
2101
|
+
return unchecked('claim_invalid');
|
|
2102
|
+
}
|
|
2103
|
+
return words.has(claim.method) ? undefined : failed('method_not_word');
|
|
2104
|
+
}
|
|
1885
2105
|
if (!words) {
|
|
1886
2106
|
const any = claim.method !== undefined ||
|
|
1887
2107
|
claim.method_key !== undefined ||
|
|
@@ -2010,13 +2230,14 @@ class DeclarationReader {
|
|
|
2010
2230
|
})));
|
|
2011
2231
|
}
|
|
2012
2232
|
/**
|
|
2013
|
-
* `request: { param, path?, url?, method? }` on a receive op (#2474
|
|
2014
|
-
* some signature of the handler this overload takes
|
|
2015
|
-
* at `param` on which every member path the claim
|
|
2016
|
-
* step, through properties the library declares
|
|
2017
|
-
* Undefined when it holds
|
|
2233
|
+
* `request: { param, path?, url?, method?, body? }` on a receive op (#2474
|
|
2234
|
+
* R0, carrick#2674): some signature of the handler this overload takes
|
|
2235
|
+
* declares a parameter at `param` on which every member path the claim
|
|
2236
|
+
* gives resolves, step by step, through properties the library declares
|
|
2237
|
+
* (`declaredProperty`). Undefined when it holds; the declarations of the
|
|
2238
|
+
* member the `body` path ends on are then added to `bodyMembers`.
|
|
2018
2239
|
*/
|
|
2019
|
-
requestOutcome(signature, handler, request) {
|
|
2240
|
+
requestOutcome(signature, handler, request, bodyMembers) {
|
|
2020
2241
|
let declared = this.keyParameterAt(signature, handler.arg);
|
|
2021
2242
|
if (declared !== undefined && handler.key !== undefined) {
|
|
2022
2243
|
const property = this.declaredProperty(declared, handler.key);
|
|
@@ -2027,25 +2248,33 @@ class DeclarationReader {
|
|
|
2027
2248
|
const slot = this.throughConditional(this.throughConstraint(declared));
|
|
2028
2249
|
if (slot === VARIADIC)
|
|
2029
2250
|
return unchecked('handler_untyped');
|
|
2030
|
-
const paths = [request.path, request.url, request.method].filter((p) => p !== undefined);
|
|
2251
|
+
const paths = [request.path, request.url, request.method, request.body].filter((p) => p !== undefined);
|
|
2031
2252
|
let best = failed('param_missing');
|
|
2032
2253
|
for (const part of this.parts(slot)) {
|
|
2033
2254
|
for (const handed of part.getCallSignatures()) {
|
|
2034
2255
|
const given = this.parameterAt(handed, request.param);
|
|
2035
2256
|
if (given === undefined || given === VARIADIC)
|
|
2036
2257
|
continue;
|
|
2258
|
+
const ends = new Map();
|
|
2037
2259
|
const resolves = paths.every(members => {
|
|
2038
2260
|
let at = given;
|
|
2261
|
+
let last;
|
|
2039
2262
|
for (const member of members) {
|
|
2040
2263
|
const property = this.declaredProperty(at, member);
|
|
2041
2264
|
if (!property)
|
|
2042
2265
|
return false;
|
|
2266
|
+
last = property;
|
|
2043
2267
|
at = this.checker.getTypeOfSymbol(property);
|
|
2044
2268
|
}
|
|
2269
|
+
if (last)
|
|
2270
|
+
ends.set(members, last);
|
|
2045
2271
|
return true;
|
|
2046
2272
|
});
|
|
2047
|
-
if (resolves)
|
|
2273
|
+
if (resolves) {
|
|
2274
|
+
const body = request.body ? ends.get(request.body) : undefined;
|
|
2275
|
+
bodyMembers.push(...(body?.declarations ?? []));
|
|
2048
2276
|
return undefined;
|
|
2277
|
+
}
|
|
2049
2278
|
best = failed('request_member_missing');
|
|
2050
2279
|
}
|
|
2051
2280
|
}
|
|
@@ -2110,8 +2339,12 @@ class DeclarationReader {
|
|
|
2110
2339
|
* prefix key accepting a string and a handler key a declared function.
|
|
2111
2340
|
* 4. Every string slot of the call besides the name is accounted for
|
|
2112
2341
|
* (design D2, `nameSiblings`).
|
|
2342
|
+
*
|
|
2343
|
+
* `runsAs` replaces the `runs` predicate (an adapter's collection, #2474
|
|
2344
|
+
* R6a); absent, a `runs` slot is a declared function.
|
|
2113
2345
|
*/
|
|
2114
|
-
messageSignatureOutcome(signature, layout, labels) {
|
|
2346
|
+
messageSignatureOutcome(signature, layout, labels, runsAs) {
|
|
2347
|
+
const runsFailure = runsAs ?? ((declared) => this.runsFailure(declared));
|
|
2115
2348
|
for (const [arg, part] of layout.positional) {
|
|
2116
2349
|
if (part === 'method') {
|
|
2117
2350
|
const declared = this.keyParameterAt(signature, arg);
|
|
@@ -2148,7 +2381,7 @@ class DeclarationReader {
|
|
|
2148
2381
|
if (part !== 'handler' && part !== 'ack' && part !== 'runs')
|
|
2149
2382
|
continue;
|
|
2150
2383
|
const declared = this.keyParameterAt(signature, arg);
|
|
2151
|
-
const failure = part === 'runs' ?
|
|
2384
|
+
const failure = part === 'runs' ? runsFailure(declared) : this.handlerFailure(declared);
|
|
2152
2385
|
if (failure)
|
|
2153
2386
|
return { rank: 3, outcome: failure };
|
|
2154
2387
|
}
|
|
@@ -2157,7 +2390,7 @@ class DeclarationReader {
|
|
|
2157
2390
|
const slot = this.keyParameterAt(signature, arg);
|
|
2158
2391
|
if (slot === undefined)
|
|
2159
2392
|
return { rank: 1, outcome: failed('param_missing') };
|
|
2160
|
-
const view = this.viewFor(slot, keys);
|
|
2393
|
+
const view = this.viewFor(slot, keys, runsFailure);
|
|
2161
2394
|
if ('rank' in view)
|
|
2162
2395
|
return view;
|
|
2163
2396
|
views.set(arg, view.view);
|
|
@@ -2172,7 +2405,7 @@ class DeclarationReader {
|
|
|
2172
2405
|
* union member that is an object type and not a function type, declaring
|
|
2173
2406
|
* every claimed key with the type its part needs.
|
|
2174
2407
|
*/
|
|
2175
|
-
viewFor(slot, keys) {
|
|
2408
|
+
viewFor(slot, keys, runsFailure) {
|
|
2176
2409
|
if (slot === VARIADIC || !this.isObjectType(slot)) {
|
|
2177
2410
|
return { rank: 1, outcome: this.slotFailure(slot, 'param_missing') };
|
|
2178
2411
|
}
|
|
@@ -2202,7 +2435,7 @@ class DeclarationReader {
|
|
|
2202
2435
|
break;
|
|
2203
2436
|
}
|
|
2204
2437
|
if (part === 'runs') {
|
|
2205
|
-
const bad =
|
|
2438
|
+
const bad = runsFailure(type);
|
|
2206
2439
|
if (bad) {
|
|
2207
2440
|
failure = { rank: 3, outcome: bad };
|
|
2208
2441
|
break;
|
|
@@ -2769,8 +3002,20 @@ class DeclarationReader {
|
|
|
2769
3002
|
dropped += 1;
|
|
2770
3003
|
return false;
|
|
2771
3004
|
};
|
|
2772
|
-
//
|
|
3005
|
+
// Handler-parameter members (carrick#2674) have a cap of their own, so they
|
|
3006
|
+
// take nothing from the main one: the listing, `truncated` and the hash are
|
|
3007
|
+
// the ones the lister gave before handlers were listed.
|
|
3008
|
+
let handlerBudget = maxEntries;
|
|
3009
|
+
const takeHandler = () => {
|
|
3010
|
+
if (handlerBudget <= 0)
|
|
3011
|
+
return false;
|
|
3012
|
+
handlerBudget -= 1;
|
|
3013
|
+
return true;
|
|
3014
|
+
};
|
|
3015
|
+
// Four passes: every export and receiver, then every member name, then the
|
|
3016
|
+
// members of each handler's parameters (carrick#2674), then signatures.
|
|
2773
3017
|
const names = [];
|
|
3018
|
+
const handlers = [];
|
|
2774
3019
|
const fills = [];
|
|
2775
3020
|
// What the package's default export names: a maker also exported by name
|
|
2776
3021
|
// under this declaration is imported the same way, so it is read the same.
|
|
@@ -2786,7 +3031,7 @@ class DeclarationReader {
|
|
|
2786
3031
|
if (!take())
|
|
2787
3032
|
return;
|
|
2788
3033
|
const home = this.homeOf(pkg, [target, ...typeSymbols(receiverType)]);
|
|
2789
|
-
entry.receivers.push(this.outlineReceiver(pkg, receiverName, receiverType, home, take, names, fills));
|
|
3034
|
+
entry.receivers.push(this.outlineReceiver(pkg, receiverName, receiverType, home, take, takeHandler, names, handlers, fills));
|
|
2790
3035
|
};
|
|
2791
3036
|
receiverOf('export', type);
|
|
2792
3037
|
for (const maker of this.makers(pkg, target, type)) {
|
|
@@ -2803,6 +3048,8 @@ class DeclarationReader {
|
|
|
2803
3048
|
}
|
|
2804
3049
|
for (const run of names)
|
|
2805
3050
|
run();
|
|
3051
|
+
for (const run of handlers)
|
|
3052
|
+
run();
|
|
2806
3053
|
for (const fill of fills)
|
|
2807
3054
|
fill();
|
|
2808
3055
|
surface.truncated = dropped;
|
|
@@ -2947,10 +3194,11 @@ class DeclarationReader {
|
|
|
2947
3194
|
}
|
|
2948
3195
|
/**
|
|
2949
3196
|
* A receiver, now; its member names later (`names`), once every export and
|
|
2950
|
-
* receiver of the package is listed;
|
|
2951
|
-
*
|
|
3197
|
+
* receiver of the package is listed; the members of its handlers'
|
|
3198
|
+
* parameters next (`handlers`), once every name is; its call, construct and
|
|
3199
|
+
* member signatures last (`fills`), once every handler is.
|
|
2952
3200
|
*/
|
|
2953
|
-
outlineReceiver(pkg, receiverName, type, home, take, names, fills) {
|
|
3201
|
+
outlineReceiver(pkg, receiverName, type, home, take, takeHandler, names, handlers, fills) {
|
|
2954
3202
|
const receiver = { receiver: receiverName, members: [] };
|
|
2955
3203
|
const holder = this.surfaceHolder(pkg, type, home);
|
|
2956
3204
|
// The receiver's own call and construct signatures, as a claim with a
|
|
@@ -2977,11 +3225,102 @@ class DeclarationReader {
|
|
|
2977
3225
|
const own = 'signatures' in callee;
|
|
2978
3226
|
const member = { name: property.getName(), own, signatures: [] };
|
|
2979
3227
|
receiver.members.push(member);
|
|
3228
|
+
handlers.push(() => {
|
|
3229
|
+
const listed = this.listHandlers(own ? callee.signatures : library, takeHandler);
|
|
3230
|
+
if (listed.length > 0)
|
|
3231
|
+
member.handlers = listed;
|
|
3232
|
+
});
|
|
2980
3233
|
fills.push(() => (member.signatures = this.listSignatures(own ? callee.signatures : library, holder.type, take)));
|
|
2981
3234
|
}
|
|
2982
3235
|
});
|
|
2983
3236
|
return receiver;
|
|
2984
3237
|
}
|
|
3238
|
+
/**
|
|
3239
|
+
* The functions a member's signatures take, at a positional argument or at a
|
|
3240
|
+
* key of an options object, with the members their parameters declare. A
|
|
3241
|
+
* handler is listed once per place, from the first signature that states it.
|
|
3242
|
+
* A parameter that declares no member lists nothing, and so does a handler
|
|
3243
|
+
* none of whose parameters do.
|
|
3244
|
+
*/
|
|
3245
|
+
listHandlers(signatures, take) {
|
|
3246
|
+
const listed = [];
|
|
3247
|
+
const seen = new Set();
|
|
3248
|
+
const add = (arg, key, slot) => {
|
|
3249
|
+
const place = JSON.stringify([arg, key ?? null]);
|
|
3250
|
+
if (seen.has(place))
|
|
3251
|
+
return;
|
|
3252
|
+
const params = this.listHandlerParams(slot, take);
|
|
3253
|
+
if (params.length === 0)
|
|
3254
|
+
return;
|
|
3255
|
+
seen.add(place);
|
|
3256
|
+
listed.push(key === undefined ? { arg, params } : { arg, key, params });
|
|
3257
|
+
};
|
|
3258
|
+
for (const signature of signatures) {
|
|
3259
|
+
const count = signature.getParameters().length;
|
|
3260
|
+
for (let arg = 0; arg < count; arg++) {
|
|
3261
|
+
const slot = this.keyParameterAt(signature, arg);
|
|
3262
|
+
if (slot === undefined || slot === VARIADIC)
|
|
3263
|
+
continue;
|
|
3264
|
+
if (this.handlerFailure(slot) === undefined) {
|
|
3265
|
+
add(arg, undefined, slot);
|
|
3266
|
+
continue;
|
|
3267
|
+
}
|
|
3268
|
+
if (!this.isObjectType(slot))
|
|
3269
|
+
continue;
|
|
3270
|
+
const keys = new Map();
|
|
3271
|
+
for (const view of this.keyViews(slot)) {
|
|
3272
|
+
for (const property of this.namedProperties(view)) {
|
|
3273
|
+
const type = this.checker.getTypeOfSymbol(property);
|
|
3274
|
+
if (!keys.has(property.getName()) && this.handlerFailure(type) === undefined)
|
|
3275
|
+
keys.set(property.getName(), type);
|
|
3276
|
+
}
|
|
3277
|
+
}
|
|
3278
|
+
for (const key of [...keys.keys()].sort(byName))
|
|
3279
|
+
add(arg, key, keys.get(key));
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3282
|
+
return listed;
|
|
3283
|
+
}
|
|
3284
|
+
/** The parameters of a function type's first signature that declare members, each member counting against the cap. */
|
|
3285
|
+
listHandlerParams(handler, take) {
|
|
3286
|
+
const slot = this.throughConditional(this.throughConstraint(handler));
|
|
3287
|
+
if (slot === VARIADIC)
|
|
3288
|
+
return [];
|
|
3289
|
+
const signature = this.parts(slot)
|
|
3290
|
+
.flatMap(part => part.getCallSignatures())
|
|
3291
|
+
.find(each => each.getParameters().length > 0);
|
|
3292
|
+
if (!signature)
|
|
3293
|
+
return [];
|
|
3294
|
+
const listed = [];
|
|
3295
|
+
signature.getParameters().forEach((parameter, index) => {
|
|
3296
|
+
const type = this.checker.getTypeOfSymbol(parameter);
|
|
3297
|
+
if (this.namedProperties(type).length === 0 || !take())
|
|
3298
|
+
return;
|
|
3299
|
+
const members = [];
|
|
3300
|
+
this.listMembers(type, [], members, take);
|
|
3301
|
+
listed.push({ param: index, name: parameter.getName(), type: this.printed(type), members });
|
|
3302
|
+
});
|
|
3303
|
+
return listed;
|
|
3304
|
+
}
|
|
3305
|
+
/** A type's declared members by path, parents before children, each level sorted by name, down to `HANDLER_MEMBER_DEPTH`. */
|
|
3306
|
+
listMembers(type, prefix, into, take) {
|
|
3307
|
+
for (const property of sortedByName(this.namedProperties(type))) {
|
|
3308
|
+
if (!take())
|
|
3309
|
+
continue;
|
|
3310
|
+
const memberType = this.checker.getTypeOfSymbol(property);
|
|
3311
|
+
const path = [...prefix, property.getName()];
|
|
3312
|
+
const callable = this.librarySignatures(memberType, 'call').length > 0;
|
|
3313
|
+
into.push({
|
|
3314
|
+
path,
|
|
3315
|
+
type: this.printed(memberType),
|
|
3316
|
+
optional: (property.flags & ts.SymbolFlags.Optional) !== 0,
|
|
3317
|
+
function: callable,
|
|
3318
|
+
});
|
|
3319
|
+
if (!callable && path.length < HANDLER_MEMBER_DEPTH && this.isObjectType(memberType)) {
|
|
3320
|
+
this.listMembers(memberType, path, into, take);
|
|
3321
|
+
}
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
2985
3324
|
listSignatures(signatures, holder, take) {
|
|
2986
3325
|
const listed = [];
|
|
2987
3326
|
for (const signature of signatures) {
|
|
@@ -3532,6 +3871,8 @@ class DeclarationReader {
|
|
|
3532
3871
|
* union the builder cuts short keeps the members it made first, so the
|
|
3533
3872
|
* listing orders every union before its own cut (`truncate`).
|
|
3534
3873
|
*/
|
|
3874
|
+
/** The longest member path a handler parameter's members are listed to (`['raw', 'url']`). */
|
|
3875
|
+
const HANDLER_MEMBER_DEPTH = 2;
|
|
3535
3876
|
const PRINT_FLAGS = ts.NodeBuilderFlags.AllowUniqueESSymbolType |
|
|
3536
3877
|
ts.NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope |
|
|
3537
3878
|
ts.NodeBuilderFlags.IgnoreErrors |
|