@scriptc/compiler 0.3.3 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ambient/scriptc-node-fallback.d.ts +713 -26
- package/dist/backend/cycle-mutability.d.ts +5 -0
- package/dist/backend/cycle-mutability.js +62 -3
- package/dist/backend/cycle-mutability.js.map +1 -1
- package/dist/backend/executable-features.js +1 -0
- package/dist/backend/executable-features.js.map +1 -1
- package/dist/backend/library-pack.js +1 -0
- package/dist/backend/library-pack.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.d.ts +5 -1
- package/dist/backend/llvm/call-lifetimes.js +11 -3
- package/dist/backend/llvm/call-lifetimes.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.test.js +31 -1
- package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/common.d.ts +5 -0
- package/dist/backend/llvm/common.js +7 -0
- package/dist/backend/llvm/common.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.js +2 -2
- package/dist/backend/llvm/dense-array-access.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +40 -1
- package/dist/backend/llvm/dyn.js +178 -27
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +12 -0
- package/dist/backend/llvm/emitter.js +164 -27
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.d.ts +9 -0
- package/dist/backend/llvm/expr-bytes.js +158 -63
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-calls.d.ts +3 -1
- package/dist/backend/llvm/expr-calls.js +49 -1
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +16 -5
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/intern-tables.test.d.ts +1 -0
- package/dist/backend/llvm/intern-tables.test.js +77 -0
- package/dist/backend/llvm/intern-tables.test.js.map +1 -0
- package/dist/backend/llvm/lib-datagram.js +10 -0
- package/dist/backend/llvm/lib-datagram.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +92 -1
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +51 -0
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-network.js +16 -0
- package/dist/backend/llvm/lib-network.js.map +1 -1
- package/dist/backend/llvm/lib-shared.d.ts +5 -0
- package/dist/backend/llvm/lib-shared.js +80 -1
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/lib-stream.js +87 -0
- package/dist/backend/llvm/lib-stream.js.map +1 -1
- package/dist/backend/llvm/lib-test.js +9 -0
- package/dist/backend/llvm/lib-test.js.map +1 -1
- package/dist/backend/llvm/map-number-lookup.d.ts +4 -0
- package/dist/backend/llvm/map-number-lookup.js +22 -0
- package/dist/backend/llvm/map-number-lookup.js.map +1 -1
- package/dist/backend/llvm/map-number-lookup.test.js +56 -0
- package/dist/backend/llvm/map-number-lookup.test.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.d.ts +9 -0
- package/dist/backend/llvm/map-read-lifetimes.js +89 -1
- package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.test.js +129 -1
- package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/publish.d.ts +5 -0
- package/dist/backend/llvm/publish.js +22 -3
- package/dist/backend/llvm/publish.js.map +1 -1
- package/dist/backend/llvm/reference-writes.js +5 -2
- package/dist/backend/llvm/reference-writes.js.map +1 -1
- package/dist/backend/llvm/regions.d.ts +4 -1
- package/dist/backend/llvm/regions.js +12 -3
- package/dist/backend/llvm/regions.js.map +1 -1
- package/dist/backend/llvm/string-reads.js +2 -2
- package/dist/backend/llvm/string-reads.js.map +1 -1
- package/dist/backend/llvm/string-slices.js +2 -2
- package/dist/backend/llvm/string-slices.js.map +1 -1
- package/dist/backend/may-throw.js +4 -0
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/native/contracts.d.ts +3 -0
- package/dist/backend/native/executable.js +13 -5
- package/dist/backend/native/executable.js.map +1 -1
- package/dist/backend/native/runtime-inputs.d.ts +1 -1
- package/dist/backend/native/runtime-inputs.js +1 -0
- package/dist/backend/native/runtime-inputs.js.map +1 -1
- package/dist/backend/native-codegen-core.d.ts +4 -4
- package/dist/backend/native-codegen-core.js +4 -6
- package/dist/backend/native-codegen-core.js.map +1 -1
- package/dist/backend/native-codegen.test.js +7 -8
- package/dist/backend/native-codegen.test.js.map +1 -1
- package/dist/backend/native-link-info-core.d.ts +3 -0
- package/dist/backend/native-link-info-core.js.map +1 -1
- package/dist/backend/publication.js +3 -1
- package/dist/backend/publication.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.js +1 -0
- package/dist/backend/runtime-pack-targets.test.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +1 -0
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/backend/target-diagnostics.js +7 -0
- package/dist/backend/target-diagnostics.js.map +1 -1
- package/dist/backend/warm-cache.js +1 -0
- package/dist/backend/warm-cache.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +1 -0
- package/dist/executable/executable-cache.js +1 -0
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +1 -0
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/frontend/experimental-import.d.ts +5 -1
- package/dist/frontend/experimental-import.js +28 -3
- package/dist/frontend/experimental-import.js.map +1 -1
- package/dist/frontend/lowering/assert-instances.d.ts +38 -0
- package/dist/frontend/lowering/assert-instances.js +269 -0
- package/dist/frontend/lowering/assert-instances.js.map +1 -0
- package/dist/frontend/lowering/builtins/compression.d.ts +18 -0
- package/dist/frontend/lowering/builtins/compression.js +175 -2
- package/dist/frontend/lowering/builtins/compression.js.map +1 -1
- package/dist/frontend/lowering/builtins/constants.js +7 -2
- package/dist/frontend/lowering/builtins/constants.js.map +1 -1
- package/dist/frontend/lowering/builtins/crypto.d.ts +6 -0
- package/dist/frontend/lowering/builtins/crypto.js +111 -1
- package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
- package/dist/frontend/lowering/builtins/errors.js +23 -0
- package/dist/frontend/lowering/builtins/errors.js.map +1 -1
- package/dist/frontend/lowering/builtins/timers.d.ts +3 -0
- package/dist/frontend/lowering/builtins/timers.js +109 -23
- package/dist/frontend/lowering/builtins/timers.js.map +1 -1
- package/dist/frontend/lowering/call-signatures.js +6 -0
- package/dist/frontend/lowering/call-signatures.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.js +66 -12
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/intern-tables.d.ts +13 -0
- package/dist/frontend/lowering/intern-tables.js +536 -0
- package/dist/frontend/lowering/intern-tables.js.map +1 -0
- package/dist/frontend/lowering/lower-assert.js +700 -61
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-async-iteration.js +11 -2
- package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +17 -3
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +3 -0
- package/dist/frontend/lowering/lower-classes.js +36 -0
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.js +77 -52
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +12 -0
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.d.ts +6 -0
- package/dist/frontend/lowering/lower-inspect.js +112 -39
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-mock.d.ts +11 -0
- package/dist/frontend/lowering/lower-mock.js +504 -0
- package/dist/frontend/lowering/lower-mock.js.map +1 -0
- package/dist/frontend/lowering/lower-modules.js +7 -0
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-server.d.ts +3 -0
- package/dist/frontend/lowering/lower-server.js +380 -30
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +23 -2
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.d.ts +10 -6
- package/dist/frontend/lowering/lower-stream.js +786 -27
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lower-test.js +86 -8
- package/dist/frontend/lowering/lower-test.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +22 -0
- package/dist/frontend/lowering/lowerer.js +72 -7
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/pairs-snapshot.d.ts +6 -0
- package/dist/frontend/lowering/pairs-snapshot.js +49 -0
- package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +4 -0
- package/dist/frontend/lowering/surfaces.js +61 -15
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/lowering/zlib-constants.d.ts +1 -0
- package/dist/frontend/lowering/zlib-constants.js +181 -0
- package/dist/frontend/lowering/zlib-constants.js.map +1 -0
- package/dist/frontend/mock-shapes.d.ts +10 -0
- package/dist/frontend/mock-shapes.js +76 -0
- package/dist/frontend/mock-shapes.js.map +1 -0
- package/dist/frontend/pipeline.js +5 -3
- package/dist/frontend/pipeline.js.map +1 -1
- package/dist/frontend/program.js +6 -1
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/resolve.d.ts +4 -0
- package/dist/frontend/resolve.js +14 -0
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/tsc-codes.js +1 -0
- package/dist/frontend/tsc-codes.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +5 -0
- package/dist/frontend/type-mapper.js +102 -9
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/ir/builtin-effects.js +36 -0
- package/dist/ir/builtin-effects.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +1 -1
- package/dist/ir/builtin-signatures.js +147 -8
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/ir.d.ts +20 -1
- package/dist/ir/ir.js +17 -0
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/runtime-features.d.ts +1 -0
- package/dist/ir/runtime-features.js +29 -2
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/validate.js +195 -5
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/ir-policy.js +1 -0
- package/dist/library/ir-policy.js.map +1 -1
- package/dist/native/cli.js +1 -0
- package/dist/native/cli.js.map +1 -1
- package/dist/native/compiler.js +1 -3
- package/dist/native/compiler.js.map +1 -1
- package/dist/native/prepare.js +1 -0
- package/dist/native/prepare.js.map +1 -1
- package/dist/native/sanitizer.test.js +1 -0
- package/dist/native/sanitizer.test.js.map +1 -1
- package/package.json +20 -20
- package/surface-manifest.json +869 -48
|
@@ -3,7 +3,7 @@ import * as ts from "../ts7/adapter.js";
|
|
|
3
3
|
import { ladderFenceExpr } from "./lowerer.js";
|
|
4
4
|
import { isJsSourceFile, locOf } from "../program.js";
|
|
5
5
|
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/ir.js";
|
|
6
|
-
import { AGENT_DOCUMENTED_OPTIONS, 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";
|
|
6
|
+
import { AGENT_DOCUMENTED_OPTIONS, HTTPS_AGENT_DOCUMENTED_OPTIONS, 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";
|
|
7
7
|
import { conditionalSpreadOf } from "./expressions/object-literals.js";
|
|
8
8
|
import { resultIsDiscarded } from "./call-position.js";
|
|
9
9
|
import { lowerCallbackArg as lowerCallbackArgShared } from "./callback-arg.js";
|
|
@@ -166,7 +166,7 @@ export function voidizedCallback(lowerer, cb, loc) {
|
|
|
166
166
|
body: [
|
|
167
167
|
{
|
|
168
168
|
kind: "return",
|
|
169
|
-
value: { kind: "closure", fnName: impl, captures: ["f.0"], type: toT, loc },
|
|
169
|
+
value: { kind: "closure", fnName: impl, captures: ["f.0"], type: toT, adapts: true, loc },
|
|
170
170
|
loc,
|
|
171
171
|
},
|
|
172
172
|
],
|
|
@@ -175,6 +175,20 @@ export function voidizedCallback(lowerer, cb, loc) {
|
|
|
175
175
|
}
|
|
176
176
|
return { kind: "call", callee: name, args: [cb], type: toT, loc };
|
|
177
177
|
}
|
|
178
|
+
/** A socket or server listener with parameters that the runtime calls
|
|
179
|
+
* through the checked-dynamic boundary (close(hadError), write's
|
|
180
|
+
* cb(err), 'drop', getConnections): a dyn function value as is, or a
|
|
181
|
+
* typed function boxed with per-argument checks. */
|
|
182
|
+
function lowerSocketDynListener(lowerer, node, what) {
|
|
183
|
+
const cb = lowerer.lowerExpr(node);
|
|
184
|
+
if (cb.type.kind === "dyn")
|
|
185
|
+
return cb;
|
|
186
|
+
if (cb.type.kind === "func" &&
|
|
187
|
+
canBoxFuncIntoDyn(cb.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
188
|
+
return { kind: "dynFrom", value: cb, type: DYN, loc: locOf(node) };
|
|
189
|
+
}
|
|
190
|
+
lowerer.noLowering(`${what} that cannot cross the checked-dynamic boundary`, node, "the callback's parameters and return value must have checked-dynamic conversions");
|
|
191
|
+
}
|
|
178
192
|
/** A registration/side-effect libCall re-shaped to answer its RECEIVER —
|
|
179
193
|
* Node's `return this` chaining (server.listen(...), res.writeHead(...)):
|
|
180
194
|
* an interned helper runs the void call and returns its first argument.
|
|
@@ -1030,6 +1044,31 @@ export function lowerHttpServerTimeoutAssignment(lowerer, left, right, loc) {
|
|
|
1030
1044
|
loc,
|
|
1031
1045
|
};
|
|
1032
1046
|
}
|
|
1047
|
+
/** `server.maxConnections = n`: the value crosses as a dyn (undefined
|
|
1048
|
+
* and null unset the cap). */
|
|
1049
|
+
export function lowerNetServerMaxConnectionsAssignment(lowerer, left, right, loc) {
|
|
1050
|
+
if (!ts.isPropertyAccessExpression(left) || left.questionDotToken)
|
|
1051
|
+
return null;
|
|
1052
|
+
if (left.name.text !== "maxConnections")
|
|
1053
|
+
return null;
|
|
1054
|
+
if (lowerer.mapTypeOf(lowerer.typeOf(left.expression))?.kind !== "netServer")
|
|
1055
|
+
return null;
|
|
1056
|
+
if (!lowerer.isStdlibMember(left))
|
|
1057
|
+
return null;
|
|
1058
|
+
const receiver = coerceToHandle(lowerer, left.expression, NETSERVER_T);
|
|
1059
|
+
const value = lowerer.coerceToExpected(lowerer.lowerExpr(right), DYN);
|
|
1060
|
+
return {
|
|
1061
|
+
kind: "exprStmt",
|
|
1062
|
+
expr: {
|
|
1063
|
+
kind: "libCall",
|
|
1064
|
+
fn: "net.serverMaxConnectionsSet",
|
|
1065
|
+
args: [receiver, value],
|
|
1066
|
+
type: VOID,
|
|
1067
|
+
loc,
|
|
1068
|
+
},
|
|
1069
|
+
loc,
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1033
1072
|
/** Method calls on net.Server receivers: listen(port[, cb]), close([cb]),
|
|
1034
1073
|
* on/once("connection" | "error" | "close", cb). address() alone fences
|
|
1035
1074
|
* toward the composed address().port read. Null for other receivers. */
|
|
@@ -1041,6 +1080,24 @@ function lowerNetServerMethodCall(lowerer, call, access) {
|
|
|
1041
1080
|
const name = access.name.text;
|
|
1042
1081
|
const loc = locOf(call);
|
|
1043
1082
|
const args = call.arguments;
|
|
1083
|
+
if (name === "getConnections") {
|
|
1084
|
+
// cb(null, count) on the next tick; answers the server.
|
|
1085
|
+
if (args.length !== 1) {
|
|
1086
|
+
lowerer.noLowering(`getConnections with ${args.length} arguments`, call, "the form is getConnections(callback)");
|
|
1087
|
+
}
|
|
1088
|
+
const receiver = coerceToHandle(lowerer, access.expression, NETSERVER_T);
|
|
1089
|
+
const cb = lowerSocketDynListener(lowerer, args[0], "getConnections callbacks");
|
|
1090
|
+
if (resultIsDiscarded(call)) {
|
|
1091
|
+
return {
|
|
1092
|
+
kind: "libCall",
|
|
1093
|
+
fn: "net.serverGetConnections",
|
|
1094
|
+
args: [receiver, cb],
|
|
1095
|
+
type: VOID,
|
|
1096
|
+
loc,
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
return receiverReturningCall(lowerer, "net.serverGetConnections", [receiver, cb], NETSERVER_T, loc);
|
|
1100
|
+
}
|
|
1044
1101
|
if (name === "setTimeout") {
|
|
1045
1102
|
if (args.length < 1 || args.length > 2)
|
|
1046
1103
|
lowerer.noLowering("server.setTimeout arguments", call, "pass milliseconds and an optional socket callback");
|
|
@@ -1356,6 +1413,17 @@ function lowerNetServerMethodCall(lowerer, call, access) {
|
|
|
1356
1413
|
loc,
|
|
1357
1414
|
};
|
|
1358
1415
|
}
|
|
1416
|
+
if (event === "drop") {
|
|
1417
|
+
// A connection past maxConnections, with its local and remote
|
|
1418
|
+
// addresses.
|
|
1419
|
+
return {
|
|
1420
|
+
kind: "libCall",
|
|
1421
|
+
fn: "net.serverOnDrop",
|
|
1422
|
+
args: [receiver, lowerSocketDynListener(lowerer, args[1], "drop listeners"), once],
|
|
1423
|
+
type: VOID,
|
|
1424
|
+
loc,
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1359
1427
|
if (event === "session") {
|
|
1360
1428
|
// The h2c server's per-connection session event: (session). The
|
|
1361
1429
|
// result is voidized; the handle passes by reference.
|
|
@@ -1450,7 +1518,7 @@ function lowerNetServerMethodCall(lowerer, call, access) {
|
|
|
1450
1518
|
loc,
|
|
1451
1519
|
};
|
|
1452
1520
|
}
|
|
1453
|
-
lowerer.noLowering(`server.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"connection", "request", "stream", "session", "upgrade", "connect", "error", "close", "listening", and "sessionError" are the supported server events (as literals)');
|
|
1521
|
+
lowerer.noLowering(`server.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"connection", "request", "drop", "stream", "session", "upgrade", "connect", "error", "close", "listening", and "sessionError" are the supported server events (as literals)');
|
|
1454
1522
|
}
|
|
1455
1523
|
if (name === "emit") {
|
|
1456
1524
|
// The demux route: emit("connection", socket) hands an accepted
|
|
@@ -1497,11 +1565,51 @@ function lowerNetServerMethodCall(lowerer, call, access) {
|
|
|
1497
1565
|
lowerer.noLowering(`address with ${args.length} arguments`, call, "address() takes no arguments");
|
|
1498
1566
|
}
|
|
1499
1567
|
const result = lowerer.mapTypeOf(lowerer.typeOf(call));
|
|
1500
|
-
if (
|
|
1568
|
+
if (result && isAddressInfoRecord(lowerer, result)) {
|
|
1569
|
+
const receiver = coerceToHandle(lowerer, access.expression, NETSERVER_T);
|
|
1570
|
+
return { kind: "libCall", fn: "net.serverAddress", args: [receiver], type: result, loc };
|
|
1571
|
+
}
|
|
1572
|
+
// @types/node's `string | AddressInfo | null`: the record while the
|
|
1573
|
+
// server listens (a TCP server never answers the pipe-path string),
|
|
1574
|
+
// null otherwise, like Node.
|
|
1575
|
+
const arms = result?.kind === "union" ? (lowerer.unions.get(result.unionId)?.arms ?? []) : [];
|
|
1576
|
+
const record = arms.find((arm) => isAddressInfoRecord(lowerer, arm));
|
|
1577
|
+
const nullTag = result?.kind === "union" ? lowerer.armTag(result.unionId, NULL_T) : -1;
|
|
1578
|
+
if (!result || result.kind !== "union" || record === undefined || nullTag < 0) {
|
|
1501
1579
|
lowerer.noLowering("address() where the result is not the {address, family, port} record", call, "the AddressInfo shape is the supported result");
|
|
1502
1580
|
}
|
|
1581
|
+
const unionId = result.unionId;
|
|
1503
1582
|
const receiver = coerceToHandle(lowerer, access.expression, NETSERVER_T);
|
|
1504
|
-
|
|
1583
|
+
const local = lowerer.declareHiddenLocal("%addressServer", NETSERVER_T);
|
|
1584
|
+
const server = varRef(local.id, NETSERVER_T, loc);
|
|
1585
|
+
return {
|
|
1586
|
+
kind: "seqExpr",
|
|
1587
|
+
stmts: [{ kind: "varDecl", localId: local.id, init: receiver, loc }],
|
|
1588
|
+
result: {
|
|
1589
|
+
kind: "ternary",
|
|
1590
|
+
cond: { kind: "libCall", fn: "net.serverListening", args: [server], type: BOOL, loc },
|
|
1591
|
+
then: {
|
|
1592
|
+
kind: "unionWrap",
|
|
1593
|
+
unionId,
|
|
1594
|
+
tag: lowerer.armTag(unionId, record),
|
|
1595
|
+
value: { kind: "libCall", fn: "net.serverAddress", args: [server], type: record, loc },
|
|
1596
|
+
type: result,
|
|
1597
|
+
loc,
|
|
1598
|
+
},
|
|
1599
|
+
else_: {
|
|
1600
|
+
kind: "unionWrap",
|
|
1601
|
+
unionId,
|
|
1602
|
+
tag: nullTag,
|
|
1603
|
+
value: { kind: "unitLit", unit: "null", type: NULL_T, loc },
|
|
1604
|
+
type: result,
|
|
1605
|
+
loc,
|
|
1606
|
+
},
|
|
1607
|
+
type: result,
|
|
1608
|
+
loc,
|
|
1609
|
+
},
|
|
1610
|
+
type: result,
|
|
1611
|
+
loc,
|
|
1612
|
+
};
|
|
1505
1613
|
}
|
|
1506
1614
|
lowerer.noLowering(`Server.${name}`, call, 'listen, close, address().port, emit("connection", socket), and on/once of connection/request/upgrade/error/close/listening/sessionError are the supported Server members', lowerer.checker.getSymbolAtLocation(access.name));
|
|
1507
1615
|
}
|
|
@@ -1556,6 +1664,79 @@ function lowerNetSocketMethodCall(lowerer, call, access) {
|
|
|
1556
1664
|
}
|
|
1557
1665
|
}
|
|
1558
1666
|
}
|
|
1667
|
+
// A trailing callback: write's runs once the data is flushed (with
|
|
1668
|
+
// null for the error), end's once the socket finishes ('finish').
|
|
1669
|
+
const last = args.length > 0 ? args[args.length - 1] : null;
|
|
1670
|
+
if (last !== null &&
|
|
1671
|
+
args.length <= 2 &&
|
|
1672
|
+
(name === "end" || args.length === 2) &&
|
|
1673
|
+
lowerer.checker.getCallSignatures(lowerer.typeOf(last)).length > 0) {
|
|
1674
|
+
const sockLocal = lowerer.declareHiddenLocal("%sockCb", NETSOCKET_T);
|
|
1675
|
+
const stmts = [
|
|
1676
|
+
{
|
|
1677
|
+
kind: "varDecl",
|
|
1678
|
+
localId: sockLocal.id,
|
|
1679
|
+
init: coerceToHandle(lowerer, access.expression, NETSOCKET_T),
|
|
1680
|
+
loc,
|
|
1681
|
+
},
|
|
1682
|
+
];
|
|
1683
|
+
const receiver = () => ({
|
|
1684
|
+
kind: "varRef",
|
|
1685
|
+
localId: sockLocal.id,
|
|
1686
|
+
type: NETSOCKET_T,
|
|
1687
|
+
loc,
|
|
1688
|
+
});
|
|
1689
|
+
const dataNode = args.length === 2 ? args[0] : null;
|
|
1690
|
+
let main = {
|
|
1691
|
+
kind: "libCall",
|
|
1692
|
+
fn: "net.sockEnd",
|
|
1693
|
+
args: [receiver()],
|
|
1694
|
+
type: VOID,
|
|
1695
|
+
loc,
|
|
1696
|
+
};
|
|
1697
|
+
if (dataNode !== null) {
|
|
1698
|
+
const data = lowerer.lowerExpr(dataNode);
|
|
1699
|
+
const fn = data.type.kind === "string"
|
|
1700
|
+
? name === "write"
|
|
1701
|
+
? "net.sockWrite"
|
|
1702
|
+
: "net.sockEndStr"
|
|
1703
|
+
: data.type.kind === "bytes" && data.type.elem === "u8"
|
|
1704
|
+
? name === "write"
|
|
1705
|
+
? "net.sockWriteBytes"
|
|
1706
|
+
: "net.sockEndBytes"
|
|
1707
|
+
: data.type.kind === "dyn"
|
|
1708
|
+
? name === "write"
|
|
1709
|
+
? "net.sockWriteDyn"
|
|
1710
|
+
: "net.sockEndDyn"
|
|
1711
|
+
: null;
|
|
1712
|
+
if (fn === null) {
|
|
1713
|
+
lowerer.noLowering(`${name} of '${lowerer.fmt(data.type)}' data`, dataNode, NARROW_DATA_HINT);
|
|
1714
|
+
}
|
|
1715
|
+
main = { kind: "libCall", fn, args: [receiver(), data], type: VOID, loc };
|
|
1716
|
+
}
|
|
1717
|
+
const cb = lowerer.lowerExpr(last);
|
|
1718
|
+
let register;
|
|
1719
|
+
if (cb.type.kind === "func" && cb.type.params.length === 0 && cb.type.ret.kind === "void") {
|
|
1720
|
+
register = {
|
|
1721
|
+
kind: "libCall",
|
|
1722
|
+
fn: name === "write" ? "net.sockOnWriteFlush" : "net.sockOnFinish",
|
|
1723
|
+
args: [receiver(), cb],
|
|
1724
|
+
type: VOID,
|
|
1725
|
+
loc,
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1728
|
+
else {
|
|
1729
|
+
register = {
|
|
1730
|
+
kind: "libCall",
|
|
1731
|
+
fn: name === "write" ? "net.sockOnWriteFlushDyn" : "net.sockOnFinishDyn",
|
|
1732
|
+
args: [receiver(), lowerSocketDynListener(lowerer, last, `${name} callbacks`)],
|
|
1733
|
+
type: VOID,
|
|
1734
|
+
loc,
|
|
1735
|
+
};
|
|
1736
|
+
}
|
|
1737
|
+
stmts.push({ kind: "exprStmt", expr: main, loc });
|
|
1738
|
+
return { kind: "seqExpr", stmts, result: register, type: VOID, loc };
|
|
1739
|
+
}
|
|
1559
1740
|
const maxArgs = name === "write" ? 1 : 1;
|
|
1560
1741
|
const minArgs = name === "write" ? 1 : 0;
|
|
1561
1742
|
if (args.length < minArgs || args.length > maxArgs) {
|
|
@@ -1604,13 +1785,44 @@ function lowerNetSocketMethodCall(lowerer, call, access) {
|
|
|
1604
1785
|
}
|
|
1605
1786
|
if (name === "setTimeout") {
|
|
1606
1787
|
requireStatementPosition(lowerer, call, "socket.setTimeout(...)");
|
|
1607
|
-
if (args.length !== 1) {
|
|
1608
|
-
lowerer.noLowering(`setTimeout with ${args.length} arguments`, call, "the supported
|
|
1788
|
+
if (args.length !== 1 && args.length !== 2) {
|
|
1789
|
+
lowerer.noLowering(`setTimeout with ${args.length} arguments`, call, "the supported forms are setTimeout(ms) and setTimeout(ms, callback)");
|
|
1609
1790
|
}
|
|
1610
1791
|
const receiver = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
|
|
1611
1792
|
const ms = lowerer.lowerExprExpecting(args[0], F64);
|
|
1793
|
+
if (args.length === 2) {
|
|
1794
|
+
// Node adds the callback as a once('timeout') listener (removes it
|
|
1795
|
+
// for 0); msecs is checked first either way.
|
|
1796
|
+
const { cb } = lowerCallbackArg(lowerer, args[1], "setTimeout callbacks", 0, () => false, "use ()", []);
|
|
1797
|
+
return {
|
|
1798
|
+
kind: "libCall",
|
|
1799
|
+
fn: "net.sockSetTimeoutCb",
|
|
1800
|
+
args: [receiver, ms, cb],
|
|
1801
|
+
type: VOID,
|
|
1802
|
+
loc,
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1612
1805
|
return { kind: "libCall", fn: "net.sockSetTimeout", args: [receiver, ms], type: VOID, loc };
|
|
1613
1806
|
}
|
|
1807
|
+
if (name === "setKeepAlive") {
|
|
1808
|
+
// SO_KEEPALIVE plus the initial delay (whole seconds, at least 1);
|
|
1809
|
+
// Node's defaults are false and 0. Answers the socket.
|
|
1810
|
+
if (args.length > 2) {
|
|
1811
|
+
lowerer.noLowering(`setKeepAlive with ${args.length} arguments`, call, "the form is setKeepAlive(enable?, initialDelay?)");
|
|
1812
|
+
}
|
|
1813
|
+
const receiver = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
|
|
1814
|
+
const enable = args.length >= 1 ? lowerer.lowerExprExpecting(args[0], BOOL) : boolLit(false, loc);
|
|
1815
|
+
const delay = args.length === 2
|
|
1816
|
+
? lowerer.lowerExprExpecting(args[1], F64)
|
|
1817
|
+
: { kind: "numLit", value: 0, type: F64, loc };
|
|
1818
|
+
return {
|
|
1819
|
+
kind: "libCall",
|
|
1820
|
+
fn: "net.sockSetKeepAlive",
|
|
1821
|
+
args: [receiver, enable, delay],
|
|
1822
|
+
type: NETSOCKET_T,
|
|
1823
|
+
loc,
|
|
1824
|
+
};
|
|
1825
|
+
}
|
|
1614
1826
|
if (name === "pause" || name === "resume") {
|
|
1615
1827
|
// Flow control (the struct's flag comments in scr_net.c): pause holds
|
|
1616
1828
|
// reads off — kernel/TCP backpressure is the buffer; resume flows
|
|
@@ -1699,6 +1911,28 @@ function lowerNetSocketMethodCall(lowerer, call, access) {
|
|
|
1699
1911
|
const event = evT.isStringLiteralType() ? evT.value : null;
|
|
1700
1912
|
const receiver = coerceToHandle(lowerer, access.expression, NETSOCKET_T);
|
|
1701
1913
|
if (event === "data") {
|
|
1914
|
+
const sigs = lowerer.checker.getCallSignatures(lowerer.typeOf(args[1]));
|
|
1915
|
+
const firstParam = sigs.length === 1 ? sigs[0].getParameters()[0] : undefined;
|
|
1916
|
+
const param = firstParam !== undefined
|
|
1917
|
+
? lowerer.mapTypeOf(lowerer.checker.getTypeOfSymbol(firstParam))
|
|
1918
|
+
: null;
|
|
1919
|
+
if (param !== null &&
|
|
1920
|
+
param.kind !== "dyn" &&
|
|
1921
|
+
!(param.kind === "bytes" && param.elem === "u8")) {
|
|
1922
|
+
// A chunk typed string (or string | Buffer): the listener takes
|
|
1923
|
+
// the chunk through a checked boundary, so a string arrives after
|
|
1924
|
+
// setEncoding and a Buffer without it fails the check instead of
|
|
1925
|
+
// being decoded.
|
|
1926
|
+
const boxed = lowerSocketDynListener(lowerer, args[1], "data listeners");
|
|
1927
|
+
const cb = { kind: "dynCheck", value: boxed, type: funcOf([DYN], VOID), loc };
|
|
1928
|
+
return {
|
|
1929
|
+
kind: "libCall",
|
|
1930
|
+
fn: "net.sockOnData",
|
|
1931
|
+
args: [receiver, cb, once],
|
|
1932
|
+
type: VOID,
|
|
1933
|
+
loc,
|
|
1934
|
+
};
|
|
1935
|
+
}
|
|
1702
1936
|
const { cb } = lowerCallbackArg(lowerer, args[1], "data listeners", 1, (p) => p.kind === "bytes" && p.elem === "u8", "use (chunk: Buffer) or ()", [DYN]);
|
|
1703
1937
|
return { kind: "libCall", fn: "net.sockOnData", args: [receiver, cb, once], type: VOID, loc };
|
|
1704
1938
|
}
|
|
@@ -1712,9 +1946,23 @@ function lowerNetSocketMethodCall(lowerer, call, access) {
|
|
|
1712
1946
|
loc,
|
|
1713
1947
|
};
|
|
1714
1948
|
}
|
|
1949
|
+
if (event === "close" &&
|
|
1950
|
+
lowerer.checker
|
|
1951
|
+
.getCallSignatures(lowerer.typeOf(args[1]))
|
|
1952
|
+
.some((sig) => sig.getParameters().length > 0)) {
|
|
1953
|
+
// close(hadError): true when the socket closed because of an error.
|
|
1954
|
+
return {
|
|
1955
|
+
kind: "libCall",
|
|
1956
|
+
fn: "net.sockOnCloseDyn",
|
|
1957
|
+
args: [receiver, lowerSocketDynListener(lowerer, args[1], "close listeners"), once],
|
|
1958
|
+
type: VOID,
|
|
1959
|
+
loc,
|
|
1960
|
+
};
|
|
1961
|
+
}
|
|
1715
1962
|
if (event === "end" ||
|
|
1716
1963
|
event === "close" ||
|
|
1717
1964
|
event === "connect" ||
|
|
1965
|
+
event === "ready" ||
|
|
1718
1966
|
event === "timeout" ||
|
|
1719
1967
|
event === "readable") {
|
|
1720
1968
|
const { cb } = lowerCallbackArg(lowerer, args[1], `${event} listeners`, 0, () => false, "use ()", []);
|
|
@@ -1726,7 +1974,9 @@ function lowerNetSocketMethodCall(lowerer, call, access) {
|
|
|
1726
1974
|
? "net.sockOnTimeout"
|
|
1727
1975
|
: event === "readable"
|
|
1728
1976
|
? "net.sockOnReadable"
|
|
1729
|
-
: "
|
|
1977
|
+
: event === "ready"
|
|
1978
|
+
? "net.sockOnReady"
|
|
1979
|
+
: "net.sockOnConnect";
|
|
1730
1980
|
return { kind: "libCall", fn, args: [receiver, cb, once], type: VOID, loc };
|
|
1731
1981
|
}
|
|
1732
1982
|
if (event === "finish") {
|
|
@@ -1761,9 +2011,9 @@ function lowerNetSocketMethodCall(lowerer, call, access) {
|
|
|
1761
2011
|
loc,
|
|
1762
2012
|
};
|
|
1763
2013
|
}
|
|
1764
|
-
lowerer.noLowering(`socket.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"data", "end", "close", "error", "connect", "timeout", "readable", "secureConnect", and "session" are the supported socket events (as literals)');
|
|
2014
|
+
lowerer.noLowering(`socket.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"data", "end", "close", "error", "connect", "ready", "timeout", "readable", "secureConnect", and "session" are the supported socket events (as literals)');
|
|
1765
2015
|
}
|
|
1766
|
-
lowerer.noLowering(`Socket.${name}`, call, "write, end, destroy, pipe, setTimeout,
|
|
2016
|
+
lowerer.noLowering(`Socket.${name}`, call, "write, end, destroy, pipe, setTimeout, setKeepAlive, setNoDelay, the address fields, read, unshift, and on/once of data/end/close/error/connect/ready/timeout/readable are the supported Socket members", lowerer.checker.getSymbolAtLocation(access.name));
|
|
1767
2017
|
}
|
|
1768
2018
|
/** The method-call dispatch for both server-surface receiver kinds — one
|
|
1769
2019
|
* entry in lower-calls.ts's intrinsic chain (the lowerChildMethodCall
|
|
@@ -1792,6 +2042,7 @@ function headersSnapshotHelper(lowerer, shapeId, loc) {
|
|
|
1792
2042
|
libCall: "http.reqHeaderPairs",
|
|
1793
2043
|
params: [{ localId: "r.0", name: "r", type: HTTPREQ_T }],
|
|
1794
2044
|
callArgs: [varRef("r.0", HTTPREQ_T, loc)],
|
|
2045
|
+
listKey: { name: "set-cookie", libCall: "http.reqHeaderList" },
|
|
1795
2046
|
});
|
|
1796
2047
|
}
|
|
1797
2048
|
function trailersSnapshotHelper(lowerer, shapeId, loc) {
|
|
@@ -2227,6 +2478,23 @@ export function lowerServerProperty(lowerer, expr) {
|
|
|
2227
2478
|
const receiver = coerceToHandle(lowerer, expr.expression, NETSERVER_T);
|
|
2228
2479
|
return { kind: "libCall", fn: "net.serverListening", args: [receiver], type: BOOL, loc };
|
|
2229
2480
|
}
|
|
2481
|
+
if (expr.name.text === "maxConnections") {
|
|
2482
|
+
const receiver = coerceToHandle(lowerer, expr.expression, NETSERVER_T);
|
|
2483
|
+
const value = {
|
|
2484
|
+
kind: "libCall",
|
|
2485
|
+
fn: "net.serverMaxConnectionsGet",
|
|
2486
|
+
args: [receiver],
|
|
2487
|
+
type: DYN,
|
|
2488
|
+
loc,
|
|
2489
|
+
};
|
|
2490
|
+
// The property's declared type: an earlier `= undefined` narrows
|
|
2491
|
+
// the read's own type to undefined.
|
|
2492
|
+
const sym = lowerer.checker.getSymbolAtLocation(expr.name);
|
|
2493
|
+
const declared = lowerer.mapTypeOf(sym ? lowerer.checker.getTypeOfSymbol(sym) : lowerer.typeOf(expr));
|
|
2494
|
+
return declared === null || declared.kind === "dyn"
|
|
2495
|
+
? value
|
|
2496
|
+
: lowerer.coerceInto(expr, value, declared);
|
|
2497
|
+
}
|
|
2230
2498
|
const field = httpServerTimeoutField(expr.name.text);
|
|
2231
2499
|
if (field !== null) {
|
|
2232
2500
|
const receiver = coerceToHandle(lowerer, expr.expression, NETSERVER_T);
|
|
@@ -2428,6 +2696,45 @@ export function lowerServerProperty(lowerer, expr) {
|
|
|
2428
2696
|
loc,
|
|
2429
2697
|
};
|
|
2430
2698
|
}
|
|
2699
|
+
if (recvKind === "netSocket" && lowerer.isStdlibMember(expr)) {
|
|
2700
|
+
const name = expr.name.text;
|
|
2701
|
+
// The other address fields: the peer's cached like remoteAddress, the
|
|
2702
|
+
// local ones read live (undefined while connecting and after close).
|
|
2703
|
+
const field = [
|
|
2704
|
+
"remotePort",
|
|
2705
|
+
"remoteFamily",
|
|
2706
|
+
"localAddress",
|
|
2707
|
+
"localPort",
|
|
2708
|
+
"localFamily",
|
|
2709
|
+
].indexOf(name);
|
|
2710
|
+
if (field >= 0) {
|
|
2711
|
+
const receiver = coerceToHandle(lowerer, expr.expression, NETSOCKET_T);
|
|
2712
|
+
const value = {
|
|
2713
|
+
kind: "libCall",
|
|
2714
|
+
fn: "net.sockAddrField",
|
|
2715
|
+
args: [receiver, { kind: "numLit", value: field, type: F64, loc }],
|
|
2716
|
+
type: DYN,
|
|
2717
|
+
loc,
|
|
2718
|
+
};
|
|
2719
|
+
const declared = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
2720
|
+
return declared === null || declared.kind === "dyn"
|
|
2721
|
+
? value
|
|
2722
|
+
: lowerer.coerceInto(expr, value, declared);
|
|
2723
|
+
}
|
|
2724
|
+
const scalar = name === "bytesRead"
|
|
2725
|
+
? { fn: "net.sockBytesRead", type: F64 }
|
|
2726
|
+
: name === "connecting"
|
|
2727
|
+
? { fn: "net.sockConnecting", type: BOOL }
|
|
2728
|
+
: name === "pending"
|
|
2729
|
+
? { fn: "net.sockPending", type: BOOL }
|
|
2730
|
+
: name === "readyState"
|
|
2731
|
+
? { fn: "net.sockReadyState", type: STRING }
|
|
2732
|
+
: null;
|
|
2733
|
+
if (scalar !== null) {
|
|
2734
|
+
const receiver = coerceToHandle(lowerer, expr.expression, NETSOCKET_T);
|
|
2735
|
+
return { kind: "libCall", fn: scalar.fn, args: [receiver], type: scalar.type, loc };
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2431
2738
|
if (recvKind === "httpClientReq" &&
|
|
2432
2739
|
lowerer.isStdlibMember(expr) &&
|
|
2433
2740
|
expr.name.text === "destroyed") {
|
|
@@ -2481,14 +2788,15 @@ export function lowerServerProperty(lowerer, expr) {
|
|
|
2481
2788
|
const collection = httpReqFieldCollection(lowerer, expr.expression);
|
|
2482
2789
|
const receiver = coerceToHandle(lowerer, expr.expression.expression, HTTPREQ_T);
|
|
2483
2790
|
const key = { kind: "strLit", value: expr.name.text, type: STRING, loc };
|
|
2484
|
-
const
|
|
2791
|
+
const list = isSetCookieRead(lowerer, expr, collection, key);
|
|
2792
|
+
const fn = collection === "headers" && !list
|
|
2485
2793
|
? "http.reqHeader"
|
|
2486
2794
|
: collection === "trailers"
|
|
2487
2795
|
? "http.reqTrailer"
|
|
2488
|
-
: collection === "headersDistinct"
|
|
2796
|
+
: collection === "headersDistinct" || list
|
|
2489
2797
|
? "http.reqHeaderValues"
|
|
2490
2798
|
: "http.reqTrailerValues";
|
|
2491
|
-
const type = collection.endsWith("Distinct")
|
|
2799
|
+
const type = collection.endsWith("Distinct") || list
|
|
2492
2800
|
? lowerer.withUndefinedArm(arrayOf(STRING))
|
|
2493
2801
|
: lowerer.envValueType();
|
|
2494
2802
|
return { kind: "libCall", fn, args: [receiver, key], type, loc };
|
|
@@ -2962,7 +3270,9 @@ export function lowerHttpAgentNew(lowerer, expr) {
|
|
|
2962
3270
|
lowerer.lowerExpr(initializer); // evaluate, like Node
|
|
2963
3271
|
break;
|
|
2964
3272
|
default:
|
|
2965
|
-
fenceOrDropOptionKey(lowerer, prop, key, api,
|
|
3273
|
+
fenceOrDropOptionKey(lowerer, prop, key, api, bi.module === "https" ? HTTPS_AGENT_DOCUMENTED_OPTIONS : AGENT_DOCUMENTED_OPTIONS, bi.module === "https"
|
|
3274
|
+
? "keepAlive, keepAliveMsecs, maxSockets, maxFreeSockets, timeout, port, and scheduling are the supported options; pass TLS options such as ca and rejectUnauthorized on each https.request"
|
|
3275
|
+
: "keepAlive, keepAliveMsecs, maxSockets, maxFreeSockets, timeout, port, and scheduling are the supported options");
|
|
2966
3276
|
}
|
|
2967
3277
|
}
|
|
2968
3278
|
}
|
|
@@ -4804,22 +5114,36 @@ export function lowerHttpHeadersElement(lowerer, expr) {
|
|
|
4804
5114
|
lowerer.unsupported("SC1090", expr.argumentExpression, `indexing req.${collection} with non-string keys`);
|
|
4805
5115
|
}
|
|
4806
5116
|
const receiver = lowerer.lowerExpr(recv);
|
|
5117
|
+
const list = isSetCookieRead(lowerer, expr, collection, key);
|
|
4807
5118
|
return {
|
|
4808
5119
|
kind: "libCall",
|
|
4809
|
-
fn: collection === "headers"
|
|
5120
|
+
fn: collection === "headers" && !list
|
|
4810
5121
|
? "http.reqHeader"
|
|
4811
5122
|
: collection === "trailers"
|
|
4812
5123
|
? "http.reqTrailer"
|
|
4813
|
-
: collection === "headersDistinct"
|
|
5124
|
+
: collection === "headersDistinct" || list
|
|
4814
5125
|
? "http.reqHeaderValues"
|
|
4815
5126
|
: "http.reqTrailerValues",
|
|
4816
5127
|
args: [receiver, key],
|
|
4817
|
-
type: collection.endsWith("Distinct")
|
|
5128
|
+
type: collection.endsWith("Distinct") || list
|
|
4818
5129
|
? lowerer.withUndefinedArm(arrayOf(STRING))
|
|
4819
5130
|
: lowerer.envValueType(),
|
|
4820
5131
|
loc: locOf(expr),
|
|
4821
5132
|
};
|
|
4822
5133
|
}
|
|
5134
|
+
/** `headers["set-cookie"]` reads Node's array of every Set-Cookie line,
|
|
5135
|
+
* the `string[] | undefined` that @types/node's IncomingHttpHeaders
|
|
5136
|
+
* declares. A read typed as a string (the bundled declarations type every
|
|
5137
|
+
* header as one) is refused, because Node's value is an array. */
|
|
5138
|
+
function isSetCookieRead(lowerer, expr, collection, key) {
|
|
5139
|
+
if (collection !== "headers" || key.kind !== "strLit" || key.value !== "set-cookie")
|
|
5140
|
+
return false;
|
|
5141
|
+
const type = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
5142
|
+
const array = lowerer.withUndefinedArm(arrayOf(STRING));
|
|
5143
|
+
if (type?.kind === "union" && array.kind === "union" && type.unionId === array.unionId)
|
|
5144
|
+
return true;
|
|
5145
|
+
lowerer.noLowering("reading set-cookie through string-typed headers", expr, "Node stores set-cookie as an array: read headersDistinct['set-cookie'], or install @types/node, which types headers['set-cookie'] as string[]");
|
|
5146
|
+
}
|
|
4823
5147
|
/** Method calls on IncomingMessage receivers: on/once("data" | "end").
|
|
4824
5148
|
* Null for other receivers. */
|
|
4825
5149
|
function lowerHttpReqMethodCall(lowerer, call, access) {
|
|
@@ -5078,12 +5402,17 @@ function lowerHttpResMethodCall(lowerer, call, access) {
|
|
|
5078
5402
|
// retains the setHeader refusal below.
|
|
5079
5403
|
value = lowerer.coerceInto(args[1], value, STRING);
|
|
5080
5404
|
}
|
|
5081
|
-
if (value.type.kind === "f64") {
|
|
5082
|
-
// Node formats number values via String(n) — the same ToString.
|
|
5083
|
-
value = { kind: "toString", operand: value, type: STRING, loc };
|
|
5084
|
-
}
|
|
5085
5405
|
if (value.type.kind !== "string") {
|
|
5086
|
-
|
|
5406
|
+
// Numbers and arrays keep their type for getHeader/getHeaders, like
|
|
5407
|
+
// Node's stored value; numbers serialize as String(n) and arrays as
|
|
5408
|
+
// one line per element.
|
|
5409
|
+
return {
|
|
5410
|
+
kind: "libCall",
|
|
5411
|
+
fn: "http.resSetHeaderDyn",
|
|
5412
|
+
args: [receiver, header, lowerer.coerceToExpected(value, DYN)],
|
|
5413
|
+
type: VOID,
|
|
5414
|
+
loc,
|
|
5415
|
+
};
|
|
5087
5416
|
}
|
|
5088
5417
|
return {
|
|
5089
5418
|
kind: "libCall",
|
|
@@ -5093,6 +5422,22 @@ function lowerHttpResMethodCall(lowerer, call, access) {
|
|
|
5093
5422
|
loc,
|
|
5094
5423
|
};
|
|
5095
5424
|
}
|
|
5425
|
+
if (name === "appendHeader") {
|
|
5426
|
+
requireStatementPosition(lowerer, call, "res.appendHeader(...)");
|
|
5427
|
+
if (args.length !== 2) {
|
|
5428
|
+
lowerer.noLowering(`appendHeader with ${args.length} arguments`, call, "the supported form is appendHeader(name, value)");
|
|
5429
|
+
}
|
|
5430
|
+
const receiver = coerceToHandle(lowerer, access.expression, HTTPRES_T);
|
|
5431
|
+
const header = lowerer.lowerExprExpecting(args[0], STRING);
|
|
5432
|
+
const value = lowerer.lowerExpr(args[1]);
|
|
5433
|
+
return {
|
|
5434
|
+
kind: "libCall",
|
|
5435
|
+
fn: "http.resAppendHeader",
|
|
5436
|
+
args: [receiver, header, lowerer.coerceToExpected(value, DYN)],
|
|
5437
|
+
type: VOID,
|
|
5438
|
+
loc,
|
|
5439
|
+
};
|
|
5440
|
+
}
|
|
5096
5441
|
if (name === "writeHead") {
|
|
5097
5442
|
if (args.length < 1 || args.length > 3) {
|
|
5098
5443
|
lowerer.noLowering(`writeHead with ${args.length} arguments`, call, "the supported forms are writeHead(status[, statusMessage][, headers]) — headers as a literal object, a Record, or a flat [name, value, ...] array");
|
|
@@ -5299,10 +5644,9 @@ function lowerHttpResMethodCall(lowerer, call, access) {
|
|
|
5299
5644
|
}
|
|
5300
5645
|
if (name === "getHeader" || name === "hasHeader" || name === "removeHeader") {
|
|
5301
5646
|
// The header CRUD trio (setHeader's readers): getHeader answers the
|
|
5302
|
-
// value as
|
|
5303
|
-
//
|
|
5304
|
-
//
|
|
5305
|
-
// goes out; hasHeader is the boolean probe.
|
|
5647
|
+
// value as set (a number, string or string[]); removeHeader drops
|
|
5648
|
+
// every case-insensitive match before the head goes out; hasHeader is
|
|
5649
|
+
// the boolean probe.
|
|
5306
5650
|
if (name === "removeHeader")
|
|
5307
5651
|
requireStatementPosition(lowerer, call, "res.removeHeader(...)");
|
|
5308
5652
|
if (args.length !== 1) {
|
|
@@ -5311,13 +5655,19 @@ function lowerHttpResMethodCall(lowerer, call, access) {
|
|
|
5311
5655
|
const receiver = coerceToHandle(lowerer, access.expression, HTTPRES_T);
|
|
5312
5656
|
const header = lowerer.lowerExprExpecting(args[0], STRING);
|
|
5313
5657
|
if (name === "getHeader") {
|
|
5314
|
-
|
|
5658
|
+
// The value as set: number, string or string[] (undefined when
|
|
5659
|
+
// absent), checked against the declared result type.
|
|
5660
|
+
const value = {
|
|
5315
5661
|
kind: "libCall",
|
|
5316
|
-
fn: "http.
|
|
5662
|
+
fn: "http.resGetHeaderDyn",
|
|
5317
5663
|
args: [receiver, header],
|
|
5318
|
-
type:
|
|
5664
|
+
type: DYN,
|
|
5319
5665
|
loc,
|
|
5320
5666
|
};
|
|
5667
|
+
const declared = lowerer.mapTypeOf(lowerer.typeOf(call));
|
|
5668
|
+
return declared === null || declared.kind === "dyn"
|
|
5669
|
+
? value
|
|
5670
|
+
: lowerer.coerceInto(call, value, declared);
|
|
5321
5671
|
}
|
|
5322
5672
|
if (name === "hasHeader") {
|
|
5323
5673
|
return {
|
|
@@ -5366,6 +5716,6 @@ function lowerHttpResMethodCall(lowerer, call, access) {
|
|
|
5366
5716
|
}
|
|
5367
5717
|
lowerer.noLowering(`res.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], '"close" and "finish" are the supported response events (as literals)');
|
|
5368
5718
|
}
|
|
5369
|
-
lowerer.noLowering(`ServerResponse.${name}`, call, "setHeader, getHeader, hasHeader, removeHeader, writeHead, writeContinue, writeProcessing, writeEarlyHints, setTimeout, write, end, destroy, response state reads, and on/once of close are the supported ServerResponse members", lowerer.checker.getSymbolAtLocation(access.name));
|
|
5719
|
+
lowerer.noLowering(`ServerResponse.${name}`, call, "setHeader, appendHeader, getHeader, hasHeader, removeHeader, writeHead, writeContinue, writeProcessing, writeEarlyHints, setTimeout, write, end, destroy, response state reads, and on/once of close are the supported ServerResponse members", lowerer.checker.getSymbolAtLocation(access.name));
|
|
5370
5720
|
}
|
|
5371
5721
|
//# sourceMappingURL=lower-server.js.map
|