@scriptc/compiler 0.0.9 → 0.0.10
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/dist/backend/emission/emit-exprs.js +136 -12
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/emission/emit-walkers.js +29 -2
- package/dist/backend/emission/emit-walkers.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +1 -0
- package/dist/backend/llvm/dyn.js +83 -1
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.js +151 -9
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +21 -7
- package/dist/diagnostics/diagnostic.js +35 -16
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/diagnostics/render.js +8 -0
- package/dist/diagnostics/render.js.map +1 -1
- package/dist/frontend/lowering/lib-boundary.js +11 -1
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +13 -0
- package/dist/frontend/lowering/lower-builtins.js +146 -1
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +41 -0
- package/dist/frontend/lowering/lower-calls.js +524 -10
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +17 -0
- package/dist/frontend/lowering/lower-containers.js +193 -10
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.js +92 -17
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +179 -10
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +33 -2
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.d.ts +25 -11
- package/dist/frontend/lowering/lower-namespaces.js +50 -15
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-server.js +211 -4
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +1 -5
- package/dist/frontend/lowering/lower-stmts.js +216 -7
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +65 -4
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +36 -1
- package/dist/frontend/lowering/lowerer.js +106 -3
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/types.d.ts +13 -0
- package/dist/frontend/types.js +84 -7
- package/dist/frontend/types.js.map +1 -1
- package/dist/index.js +20 -8
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +99 -5
- package/dist/ir/nodes.js +44 -3
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +53 -3
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/fence-eval.d.ts +77 -0
- package/dist/library/fence-eval.js +385 -0
- package/dist/library/fence-eval.js.map +1 -0
- package/dist/library/profile.d.ts +11 -1
- package/dist/library/profile.js +102 -18
- package/dist/library/profile.js.map +1 -1
- package/package.json +2 -2
- package/surface-manifest.json +1 -1
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* beyond these shapes fences member-qualified — never a generic
|
|
10
10
|
* rejection, never silence. */
|
|
11
11
|
import * as ts from "../ts7/adapter.js";
|
|
12
|
-
import {
|
|
12
|
+
import { ladderFenceExpr, nodeThrowExpr } from "./lowerer.js";
|
|
13
|
+
import { isJsSourceFile, locOf } from "../program.js";
|
|
13
14
|
import { arrayOf, BOOL, BYTES_U8, canBoxFuncIntoDyn, canConvertToDyn, DYN, DYN_HANDLE_KINDS, F64, funcOf, HTTP2SESSION_T, HTTP2STREAM_T, HTTPCLIENTREQ_T, HTTPREQ_T, HTTPRES_T, NETSERVER_T, NETSOCKET_T, NULL_T, SECURECTX_T, STRING, UNDEFINED_T, typeKey, VOID } from "../../ir/nodes.js";
|
|
14
15
|
import { builtinFenceHintOf, builtinModuleFnOf, fenceOrDropOptionKey, HTTP_CLIENT_DOCUMENTED_OPTIONS, HTTP_SERVER_DOCUMENTED_OPTIONS, HTTP2_SECURE_SERVER_DOCUMENTED_OPTIONS, HTTPS_CLIENT_DOCUMENTED_OPTIONS, sideEffectFreeOptionValue, TLS_SERVER_DOCUMENTED_OPTIONS, } from "./surfaces.js";
|
|
15
16
|
import { conditionalSpreadOf } from "./lower-exprs.js";
|
|
@@ -420,6 +421,28 @@ export function lowerNetModuleCall(L, expr, bi, loc) {
|
|
|
420
421
|
return { kind: "libCall", fn: "net.createServer", args: [], type: NETSERVER_T, loc };
|
|
421
422
|
}
|
|
422
423
|
if (args.length === 1) {
|
|
424
|
+
// A provably-non-object, non-function argument (the invalid-input
|
|
425
|
+
// probes: createServer('path'), createServer(0)): Node throws
|
|
426
|
+
// ERR_INVALID_ARG_TYPE on 'options' before any server exists. DYN
|
|
427
|
+
// result — the checked-dynamic lane's concise arrows box it, and
|
|
428
|
+
// the throw means it never materializes.
|
|
429
|
+
if (isJsSourceFile(expr.getSourceFile())) {
|
|
430
|
+
const t = L.mapTypeOf(L.typeOf(args[0]));
|
|
431
|
+
if (t !== null && (t.kind === "string" || t.kind === "f64" || t.kind === "bool")) {
|
|
432
|
+
const raw = L.lowerExpr(args[0]);
|
|
433
|
+
return {
|
|
434
|
+
kind: "libCall",
|
|
435
|
+
fn: "error.argTypeThrow",
|
|
436
|
+
args: [
|
|
437
|
+
{ kind: "strLit", value: "options", type: STRING, loc },
|
|
438
|
+
{ kind: "strLit", value: "of type object", type: STRING, loc },
|
|
439
|
+
{ kind: "dynFrom", value: raw, type: DYN, loc },
|
|
440
|
+
],
|
|
441
|
+
type: NETSERVER_T,
|
|
442
|
+
loc,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
}
|
|
423
446
|
const { cb } = lowerCallbackArg(L, args[0], "connection handlers", 1, (p) => p.kind === "netSocket", "use (socket) or ()", [NETSOCKET_T]);
|
|
424
447
|
return { kind: "libCall", fn: "net.createServerCb", args: [cb], type: NETSERVER_T, loc };
|
|
425
448
|
}
|
|
@@ -438,6 +461,26 @@ export function lowerNetModuleCall(L, expr, bi, loc) {
|
|
|
438
461
|
if (args.length >= 1 && ts.isObjectLiteralExpression(args[0])) {
|
|
439
462
|
return lowerNetConnectOptions(L, expr, bi.member, loc);
|
|
440
463
|
}
|
|
464
|
+
// A RUNTIME option bag (a record binding or dyn value — the
|
|
465
|
+
// invalid-input probes build theirs with computed keys): the
|
|
466
|
+
// checked-dynamic walk validates Node-order and the compiler-rendered
|
|
467
|
+
// fence is the post-validation tail.
|
|
468
|
+
if (args.length === 1 && isJsSourceFile(expr.getSourceFile())) {
|
|
469
|
+
const t = L.mapTypeOf(L.typeOf(args[0]));
|
|
470
|
+
if (t !== null && (t.kind === "dyn" || t.kind === "record")) {
|
|
471
|
+
const raw = L.lowerExpr(args[0]);
|
|
472
|
+
if (raw.type.kind === "dyn" || L.dynConvertible(raw.type)) {
|
|
473
|
+
const bag = raw.type.kind === "dyn" ? raw : { kind: "dynFrom", value: raw, type: DYN, loc };
|
|
474
|
+
return {
|
|
475
|
+
kind: "libCall",
|
|
476
|
+
fn: "net.connectOptsChk",
|
|
477
|
+
args: [bag, ladderFenceExpr(L, `${bi.member} with a runtime options record`, expr, "pass the options as an object literal — port, host, autoSelectFamily, autoSelectFamilyAttemptTimeout, and lookup are the supported options")],
|
|
478
|
+
type: NETSOCKET_T,
|
|
479
|
+
loc,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
441
484
|
if (args.length < 1 || args.length > 3) {
|
|
442
485
|
L.noLowering(`${bi.member} with ${args.length} arguments`, expr, `the supported form is ${bi.member}(port, host?, connectListener?)`);
|
|
443
486
|
}
|
|
@@ -510,10 +553,49 @@ function lookupFnShapeOk(L, t) {
|
|
|
510
553
|
function lowerNetConnectOptions(L, expr, member, loc) {
|
|
511
554
|
const args = expr.arguments;
|
|
512
555
|
const optsNode = args[0];
|
|
556
|
+
const isJs = isJsSourceFile(expr.getSourceFile());
|
|
557
|
+
// The checked-dynamic option-bag route (JS sources): a literal with
|
|
558
|
+
// computed keys (the invalid-input probes' spelling) or an objectMode-
|
|
559
|
+
// trio member rides WHOLE to the runtime walk — Node's Socket-ctor
|
|
560
|
+
// validation order (the trio's ERR_INVALID_ARG_VALUE first, then
|
|
561
|
+
// port/host/autoSelectFamily), with the compiler-rendered fence as the
|
|
562
|
+
// post-validation tail.
|
|
563
|
+
if (isJs) {
|
|
564
|
+
const needsBag = optsNode.properties.some((p) => (!ts.isPropertyAssignment(p) && !ts.isShorthandPropertyAssignment(p)) ||
|
|
565
|
+
(ts.isPropertyAssignment(p) && ts.isComputedPropertyName(p.name)) ||
|
|
566
|
+
["objectMode", "readableObjectMode", "writableObjectMode"].includes((ts.isPropertyAssignment(p) || ts.isShorthandPropertyAssignment(p)) &&
|
|
567
|
+
(ts.isIdentifier(p.name) || ts.isStringLiteral(p.name)) ? p.name.text : ""));
|
|
568
|
+
if (needsBag) {
|
|
569
|
+
const raw = L.lowerExpr(optsNode);
|
|
570
|
+
if (raw.type.kind === "dyn" || L.dynConvertible(raw.type)) {
|
|
571
|
+
const bag = raw.type.kind === "dyn" ? raw : { kind: "dynFrom", value: raw, type: DYN, loc };
|
|
572
|
+
return {
|
|
573
|
+
kind: "libCall",
|
|
574
|
+
fn: "net.connectOptsChk",
|
|
575
|
+
args: [bag, ladderFenceExpr(L, `${member} with these options`, optsNode, "port, host, autoSelectFamily, autoSelectFamilyAttemptTimeout, and lookup are the supported options")],
|
|
576
|
+
type: NETSOCKET_T,
|
|
577
|
+
loc,
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
513
582
|
let port = null;
|
|
514
583
|
let host = null;
|
|
515
584
|
let lookup = null;
|
|
516
585
|
let autoSelect = false;
|
|
586
|
+
let attempt = null;
|
|
587
|
+
let optionThrow = null;
|
|
588
|
+
const propThrow = (name, expected, got) => ({
|
|
589
|
+
kind: "libCall",
|
|
590
|
+
fn: "error.propTypeThrow",
|
|
591
|
+
args: [
|
|
592
|
+
{ kind: "strLit", value: name, type: STRING, loc },
|
|
593
|
+
{ kind: "strLit", value: expected, type: STRING, loc },
|
|
594
|
+
got.type.kind === "dyn" ? got : { kind: "dynFrom", value: got, type: DYN, loc },
|
|
595
|
+
],
|
|
596
|
+
type: NETSOCKET_T,
|
|
597
|
+
loc,
|
|
598
|
+
});
|
|
517
599
|
for (const prop of optsNode.properties) {
|
|
518
600
|
let initializer;
|
|
519
601
|
if (ts.isPropertyAssignment(prop) &&
|
|
@@ -539,6 +621,13 @@ function lowerNetConnectOptions(L, expr, member, loc) {
|
|
|
539
621
|
else if (key === "host") {
|
|
540
622
|
host = lowerVal();
|
|
541
623
|
if (host.type.kind !== "string") {
|
|
624
|
+
// A provably-non-string host (the invalid-input probes): Node's
|
|
625
|
+
// lookupAndConnect throws ERR_INVALID_ARG_TYPE at connect time.
|
|
626
|
+
if (isJs && (host.type.kind === "dyn" || L.dynConvertible(host.type))) {
|
|
627
|
+
optionThrow ??= propThrow("options.host", "of type string", host);
|
|
628
|
+
host = null;
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
542
631
|
L.noLowering(`a ${member} 'host' option of '${L.fmt(host.type)}' values`, prop, "the host is a string here");
|
|
543
632
|
}
|
|
544
633
|
}
|
|
@@ -547,10 +636,28 @@ function lowerNetConnectOptions(L, expr, member, loc) {
|
|
|
547
636
|
// dial below (false/dynamic would mean Node's single-address dial,
|
|
548
637
|
// which the lookup form does not implement).
|
|
549
638
|
if (initializer === null || initializer.kind !== ts.SyntaxKind.TrueKeyword) {
|
|
639
|
+
// A provably-non-boolean value throws Node's validateBoolean
|
|
640
|
+
// ladder instead of fencing.
|
|
641
|
+
const raw = initializer !== null && isJs ? L.lowerExpr(initializer) : null;
|
|
642
|
+
if (raw !== null && raw.type.kind !== "bool" &&
|
|
643
|
+
(raw.type.kind === "dyn" || L.dynConvertible(raw.type))) {
|
|
644
|
+
optionThrow ??= propThrow("options.autoSelectFamily", "of type boolean", raw);
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
550
647
|
L.noLowering(`${member} with a non-literal autoSelectFamily option`, prop, "the lowered form is autoSelectFamily: true beside a lookup function");
|
|
551
648
|
}
|
|
552
649
|
autoSelect = true;
|
|
553
650
|
}
|
|
651
|
+
else if (key === "autoSelectFamilyAttemptTimeout") {
|
|
652
|
+
// The attempt budget validates at runtime (Node's validateInt32-
|
|
653
|
+
// from-1 ladder) and is then inert — the single dial has nothing
|
|
654
|
+
// to time, the autoSelectFamily simplification's sibling.
|
|
655
|
+
const raw = lowerVal();
|
|
656
|
+
if (!(raw.type.kind === "dyn" || raw.kind === "unitLit" || L.dynConvertible(raw.type))) {
|
|
657
|
+
L.noLowering(`a ${member} 'autoSelectFamilyAttemptTimeout' option of '${L.fmt(raw.type)}' values`, prop, "the budget is a number here");
|
|
658
|
+
}
|
|
659
|
+
attempt = raw.type.kind === "dyn" ? raw : { kind: "dynFrom", value: raw, type: DYN, loc };
|
|
660
|
+
}
|
|
554
661
|
else if (key === "lookup") {
|
|
555
662
|
if (initializer === null) {
|
|
556
663
|
L.noLowering(`${member} with a shorthand lookup option`, prop, "spell it out: lookup: theResolver");
|
|
@@ -564,10 +671,21 @@ function lowerNetConnectOptions(L, expr, member, loc) {
|
|
|
564
671
|
L.noLowering(`${member} option '${key}'`, prop, "port, host, autoSelectFamily, and lookup are the supported options");
|
|
565
672
|
}
|
|
566
673
|
}
|
|
674
|
+
// A collected option-contract violation replaces the whole call: Node
|
|
675
|
+
// throws it from Socket.connect before dialing (port validation held —
|
|
676
|
+
// the port arm above fenced non-number ports already).
|
|
677
|
+
if (optionThrow !== null)
|
|
678
|
+
return optionThrow;
|
|
567
679
|
if (port === null) {
|
|
568
680
|
L.noLowering(`${member} options without a port`, optsNode, "the supported options object is { port, host?, autoSelectFamily?, lookup? }");
|
|
569
681
|
}
|
|
570
682
|
host ??= { kind: "strLit", value: "localhost", type: STRING, loc };
|
|
683
|
+
if (attempt !== null) {
|
|
684
|
+
if (lookup !== null || args.length !== 1) {
|
|
685
|
+
L.noLowering(`${member} with an autoSelectFamilyAttemptTimeout beside a lookup or connect listener`, expr, "the validated-budget form is the bare options call — register listeners separately");
|
|
686
|
+
}
|
|
687
|
+
return { kind: "libCall", fn: "net.connectAttempt", args: [port, host, attempt], type: NETSOCKET_T, loc };
|
|
688
|
+
}
|
|
571
689
|
if (lookup !== null) {
|
|
572
690
|
if (!autoSelect) {
|
|
573
691
|
L.noLowering(`${member} with a lookup but no autoSelectFamily: true`, optsNode, "the lookup form dials every answered address in order — Node does that under autoSelectFamily: true, so spell it");
|
|
@@ -771,6 +889,30 @@ function lowerNetServerMethodCall(L, call, access) {
|
|
|
771
889
|
v6only = v;
|
|
772
890
|
}
|
|
773
891
|
}
|
|
892
|
+
else if (key === "signal" && ts.isPropertyAssignment(prop) &&
|
|
893
|
+
isJsSourceFile(call.getSourceFile())) {
|
|
894
|
+
// A provably-non-AbortSignal signal (the invalid-input probes:
|
|
895
|
+
// strings, numbers, plain records) throws Node's
|
|
896
|
+
// validateAbortSignal ladder; plausible signal values keep the
|
|
897
|
+
// fence — abort-driven close has no lowering yet.
|
|
898
|
+
const raw = L.lowerExpr(prop.initializer);
|
|
899
|
+
const provablyNot = raw.type.kind === "string" || raw.type.kind === "f64" ||
|
|
900
|
+
raw.type.kind === "bool" || raw.type.kind === "record" || raw.type.kind === "array";
|
|
901
|
+
if (provablyNot && L.dynConvertible(raw.type)) {
|
|
902
|
+
return {
|
|
903
|
+
kind: "libCall",
|
|
904
|
+
fn: "error.propTypeThrow",
|
|
905
|
+
args: [
|
|
906
|
+
{ kind: "strLit", value: "options.signal", type: STRING, loc },
|
|
907
|
+
{ kind: "strLit", value: "an instance of AbortSignal", type: STRING, loc },
|
|
908
|
+
{ kind: "dynFrom", value: raw, type: DYN, loc },
|
|
909
|
+
],
|
|
910
|
+
type: ts.isExpressionStatement(call.parent) ? VOID : NETSERVER_T,
|
|
911
|
+
loc,
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
L.noLowering(`listen option 'signal'`, prop, "abort-driven close has no lowering yet — port, host, and ipv6Only are the supported listen options");
|
|
915
|
+
}
|
|
774
916
|
else {
|
|
775
917
|
L.noLowering(`listen option '${key}'`, prop, "port, host, and ipv6Only are the supported listen options");
|
|
776
918
|
}
|
|
@@ -1022,6 +1164,31 @@ function lowerNetSocketMethodCall(L, call, access) {
|
|
|
1022
1164
|
const args = call.arguments;
|
|
1023
1165
|
if (name === "write" || name === "end") {
|
|
1024
1166
|
requireStatementPosition(L, call, `socket.${name}(...)`);
|
|
1167
|
+
// write(chunk, encoding) — the two-argument encoding form: 'buffer'
|
|
1168
|
+
// beside a string chunk is Node's stream_base typecheck ("Second
|
|
1169
|
+
// argument must be a buffer", thrown synchronously on an established
|
|
1170
|
+
// socket — the invalid-input probes' shape); utf8 spellings are the
|
|
1171
|
+
// plain write (that IS the encoding written); a Buffer chunk ignores
|
|
1172
|
+
// the encoding like Node does. Other encodings keep the fence.
|
|
1173
|
+
if (name === "write" && args.length === 2) {
|
|
1174
|
+
const encT = L.typeOf(args[1]);
|
|
1175
|
+
const chunkT = L.mapTypeOf(L.typeOf(args[0]));
|
|
1176
|
+
if (encT.isStringLiteralType() && chunkT !== null) {
|
|
1177
|
+
if (encT.value === "buffer" && chunkT.kind === "string" &&
|
|
1178
|
+
isJsSourceFile(call.getSourceFile())) {
|
|
1179
|
+
L.lowerExpr(args[0]); // evaluation order (effect-free in practice)
|
|
1180
|
+
return nodeThrowExpr(1, "ERR_INVALID_ARG_TYPE", "Second argument must be a buffer", VOID, loc);
|
|
1181
|
+
}
|
|
1182
|
+
const passthrough = (chunkT.kind === "string" && (encT.value === "utf8" || encT.value === "utf-8")) ||
|
|
1183
|
+
(chunkT.kind === "bytes" && chunkT.elem === "u8");
|
|
1184
|
+
if (passthrough) {
|
|
1185
|
+
const receiver2 = handleReceiver(L, access.expression, NETSOCKET_T);
|
|
1186
|
+
const data2 = L.lowerExpr(args[0]);
|
|
1187
|
+
const fn = data2.type.kind === "string" ? "net.sockWrite" : "net.sockWriteBytes";
|
|
1188
|
+
return { kind: "libCall", fn, args: [receiver2, data2], type: VOID, loc };
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1025
1192
|
const maxArgs = name === "write" ? 1 : 1;
|
|
1026
1193
|
const minArgs = name === "write" ? 1 : 0;
|
|
1027
1194
|
if (args.length < minArgs || args.length > maxArgs) {
|
|
@@ -1981,9 +2148,29 @@ function lowerTlsServerOptions(L, node, what) {
|
|
|
1981
2148
|
* checked-dynamic JS lane's record — passes whole to the runtime walk
|
|
1982
2149
|
* (scr_tls_srv_opts_walk: same member split, fences thrown at runtime,
|
|
1983
2150
|
* the divergence-66 stance); anything else keeps the compile fence. */
|
|
2151
|
+
/** The option keys whose Node argument contracts the runtime walker
|
|
2152
|
+
* validates (scr_tls_opts_validate) — a literal carrying any of them
|
|
2153
|
+
* rides WHOLE to the walker so the typed ladders run in Node's order
|
|
2154
|
+
* (the static walk would fence them before validating). */
|
|
2155
|
+
const TLS_VALIDATED_OPTIONS = new Set([
|
|
2156
|
+
"ciphers", "passphrase", "ecdhCurve", "sessionIdContext",
|
|
2157
|
+
"clientCertEngine", "privateKeyEngine", "privateKeyIdentifier",
|
|
2158
|
+
"minVersion", "maxVersion", "handshakeTimeout", "keepAliveInitialDelay",
|
|
2159
|
+
"sessionTimeout", "ticketKeys",
|
|
2160
|
+
]);
|
|
2161
|
+
/** True when a literal options bag carries a runtime-validated key (and
|
|
2162
|
+
* the source is JS — TypeScript keeps its compile fences). */
|
|
2163
|
+
function tlsLiteralNeedsRuntimeWalk(node) {
|
|
2164
|
+
if (!isJsSourceFile(node.getSourceFile()))
|
|
2165
|
+
return false;
|
|
2166
|
+
return node.properties.some((p) => (ts.isPropertyAssignment(p) || ts.isShorthandPropertyAssignment(p)) &&
|
|
2167
|
+
(ts.isIdentifier(p.name) || ts.isStringLiteral(p.name)) &&
|
|
2168
|
+
TLS_VALIDATED_OPTIONS.has(p.name.text));
|
|
2169
|
+
}
|
|
1984
2170
|
function lowerTlsServerOptionsOrDyn(L, node, what) {
|
|
1985
|
-
if (ts.isObjectLiteralExpression(node))
|
|
2171
|
+
if (ts.isObjectLiteralExpression(node) && !tlsLiteralNeedsRuntimeWalk(node)) {
|
|
1986
2172
|
return lowerTlsServerOptions(L, node, what);
|
|
2173
|
+
}
|
|
1987
2174
|
const v = L.lowerExpr(node);
|
|
1988
2175
|
if (v.type.kind === "dyn")
|
|
1989
2176
|
return { dyn: v };
|
|
@@ -2123,6 +2310,23 @@ function lowerTlsModuleCall(L, expr, bi, loc) {
|
|
|
2123
2310
|
if (bi.member === "connect") {
|
|
2124
2311
|
return lowerTlsConnectCall(L, expr, loc);
|
|
2125
2312
|
}
|
|
2313
|
+
if (bi.member === "getCACertificates" && args.length === 1 && !args.some(ts.isSpreadElement) &&
|
|
2314
|
+
isJsSourceFile(expr.getSourceFile())) {
|
|
2315
|
+
// The type-argument ladder (validateString + the documented name
|
|
2316
|
+
// set); the real CA list has no lowering, so a valid name meets the
|
|
2317
|
+
// compiler-rendered fence after the validation.
|
|
2318
|
+
const raw = L.lowerExpr(args[0]);
|
|
2319
|
+
if (raw.type.kind === "dyn" || raw.kind === "unitLit" || L.dynConvertible(raw.type)) {
|
|
2320
|
+
const t = raw.type.kind === "dyn" ? raw : { kind: "dynFrom", value: raw, type: DYN, loc };
|
|
2321
|
+
return {
|
|
2322
|
+
kind: "libCall",
|
|
2323
|
+
fn: "tls.caCertsChk",
|
|
2324
|
+
args: [t, ladderFenceExpr(L, "tls.getCACertificates", expr)],
|
|
2325
|
+
type: L.mapTypeOf(L.typeOf(expr)) ?? DYN,
|
|
2326
|
+
loc,
|
|
2327
|
+
};
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2126
2330
|
if (bi.member === "createSecureContext") {
|
|
2127
2331
|
// createSecureContext({ cert, key }) → the opaque SecureContext handle
|
|
2128
2332
|
// an SNI callback answers with. The minimal honest form: exactly the
|
|
@@ -2131,8 +2335,11 @@ function lowerTlsModuleCall(L, expr, bi, loc) {
|
|
|
2131
2335
|
if (args.length !== 1) {
|
|
2132
2336
|
L.noLowering(`createSecureContext with ${args.length} arguments`, expr, "the supported form is createSecureContext({ cert, key })");
|
|
2133
2337
|
}
|
|
2134
|
-
const
|
|
2135
|
-
|
|
2338
|
+
const opts = lowerTlsServerOptionsOrDyn(L, args[0], "tls.createSecureContext");
|
|
2339
|
+
if (opts.dyn !== undefined) {
|
|
2340
|
+
return { kind: "libCall", fn: "tls.createSecureContextDyn", args: [opts.dyn], type: SECURECTX_T, loc };
|
|
2341
|
+
}
|
|
2342
|
+
return { kind: "libCall", fn: "tls.createSecureContext", args: [opts.cert, opts.key], type: SECURECTX_T, loc };
|
|
2136
2343
|
}
|
|
2137
2344
|
L.noLowering(`tls.${bi.member}`, expr, builtinFenceHintOf("tls", bi.member) ??
|
|
2138
2345
|
"createServer({ cert, key }, handler) and createSecureContext({ cert, key }) are the lowered tls module functions", L.resolveValueSymbol(expr.expression));
|