candor-ts 0.5.11 → 0.5.12
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 +1 -1
- package/scan.mjs +39 -0
package/package.json
CHANGED
package/scan.mjs
CHANGED
|
@@ -788,6 +788,27 @@ function visitCalls(node) {
|
|
|
788
788
|
if (t) rec.edges.add(t);
|
|
789
789
|
}
|
|
790
790
|
}
|
|
791
|
+
// `fn.call(thisArg, …)` / `fn.apply(thisArg, args)` INVOKE the receiver function reference, and
|
|
792
|
+
// `Reflect.apply(fn, …)` / `Reflect.construct(Ctor, …)` invoke their FIRST ARGUMENT. The resolved
|
|
793
|
+
// signature lands on the es-lib `CallableFunction.call/apply` / `Reflect.apply` member, so the
|
|
794
|
+
// function actually invoked (the receiver, or arg0) was never followed → the caller read
|
|
795
|
+
// silent-pure (HIGH: a common reflective-invoke shape). Edge to the referenced unit, mirroring the
|
|
796
|
+
// HOF-ref arm: a pure ref edges to a pure unit (no fabrication); a non-fn receiver/arg resolves to
|
|
797
|
+
// no minted unit (`nodeName` miss) and adds nothing; an unresolvable ref stays opaque/Unknown.
|
|
798
|
+
if (ts.isPropertyAccessExpression(node.expression)) {
|
|
799
|
+
const m = node.expression.name.text;
|
|
800
|
+
const recv = node.expression.expression;
|
|
801
|
+
const recvText = recv.getText().replace(/\s+/g, "");
|
|
802
|
+
let invokedRef = null;
|
|
803
|
+
if ((m === "call" || m === "apply") && recvText !== "Reflect") invokedRef = recv;
|
|
804
|
+
else if (recvText === "Reflect" && (m === "apply" || m === "construct"))
|
|
805
|
+
invokedRef = (node.arguments ?? [])[0] ?? null;
|
|
806
|
+
if (invokedRef && (ts.isIdentifier(invokedRef) || ts.isPropertyAccessExpression(invokedRef))) {
|
|
807
|
+
const d2 = realDecl(checker.getSymbolAtLocation(invokedRef));
|
|
808
|
+
const t = d2 && nodeName.get(d2);
|
|
809
|
+
if (t) rec.edges.add(t);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
791
812
|
if (mod === "<local>") {
|
|
792
813
|
const targetName = nodeName.get(decl);
|
|
793
814
|
if (targetName) {
|
|
@@ -933,6 +954,19 @@ function visitCalls(node) {
|
|
|
933
954
|
if (ts.isNewExpression(node) && (node.arguments ?? []).length === 0
|
|
934
955
|
&& checker.getTypeAtLocation(node.expression)?.symbol?.name === "DateConstructor")
|
|
935
956
|
rec.direct.add("Clock");
|
|
957
|
+
// Browser/runtime NETWORK globals declared in lib.dom — no importable module for the κ table to
|
|
958
|
+
// key on, so they read SILENT-PURE. `XMLHttpRequest.send`/`.open` issue the HTTP request; the
|
|
959
|
+
// `EventSource`/`WebSocket` constructors open a connection on construction. Net. (Found by a
|
|
960
|
+
// Net-deep sweep. The npm `ws` package is already κ-covered; this is the bare browser global.)
|
|
961
|
+
if (parent === "XMLHttpRequest" && (name === "send" || name === "open")) rec.direct.add("Net");
|
|
962
|
+
// `new EventSource(url)` / `new WebSocket(url)`: the constructor is declared on an anonymous
|
|
963
|
+
// `declare var` object type (symbol `__type`, no usable parent name), but reaching the es-lib
|
|
964
|
+
// branch already proves the ctor resolved to lib.dom (not a project class shadowing the name),
|
|
965
|
+
// so the constructed identifier is the real browser global.
|
|
966
|
+
if (ts.isNewExpression(node)) {
|
|
967
|
+
const ctorName = node.expression.getText();
|
|
968
|
+
if (ctorName === "EventSource" || ctorName === "WebSocket") rec.direct.add("Net");
|
|
969
|
+
}
|
|
936
970
|
} else {
|
|
937
971
|
// The member token κ matches: the resolved declaration's name, EXCEPT a `new X()` call,
|
|
938
972
|
// whose declaration is a Constructor (empty name) — synthesize "new" so a rule can exempt
|
|
@@ -1087,6 +1121,11 @@ function visitCalls(node) {
|
|
|
1087
1121
|
&& !(checker.getSymbolAtLocation(callee)?.declarations ?? [])
|
|
1088
1122
|
.some((d) => projectFiles.has(path.resolve(d.getSourceFile().fileName))))
|
|
1089
1123
|
geff = "Net";
|
|
1124
|
+
// the fully-qualified global fetch — `globalThis.fetch`/`window.fetch`/`self.fetch` — is a
|
|
1125
|
+
// PropertyAccess callee the bare-identifier guard above misses, so it read silent-pure. Mirror the
|
|
1126
|
+
// `eval` global-qualifier handling (a runtime global a project would not shadow).
|
|
1127
|
+
else if (ctext === "globalThis.fetch" || ctext === "window.fetch" || ctext === "self.fetch")
|
|
1128
|
+
geff = "Net";
|
|
1090
1129
|
if (geff) {
|
|
1091
1130
|
const owner = enclosing(node);
|
|
1092
1131
|
if (owner) fns.get(owner).direct.add(geff);
|