knodin 0.13.1 → 0.14.0
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/bin/cli.js +48 -5
- package/dist/src/class-consumer-cursor.js +2 -0
- package/dist/src/compact-structural.js +7 -2
- package/dist/src/engine/apex-class-uses.js +54 -8
- package/dist/src/engine/apex-dead-chains.js +368 -0
- package/dist/src/engine/apex-entry-points.js +44 -8
- package/dist/src/engine/index.js +368 -21
- package/dist/src/engine/seal.js +28 -4
- package/dist/src/init.js +14 -2
- package/dist/src/response-budget.js +14 -2
- package/dist/src/tools/knodin-tools.js +1 -0
- package/dist/src/worktree-seed.js +28 -1
- package/docs/CLI.md +6 -3
- package/docs/DEAD-CODE-AND-IMPACT.md +41 -0
- package/docs/MCP.md +7 -3
- package/docs/SALESFORCE-BINDINGS.md +26 -8
- package/docs/releases/0.14.0.md +78 -0
- package/package.json +3 -2
|
@@ -35,9 +35,26 @@ function callbackSignature(contract, declaration) {
|
|
|
35
35
|
}
|
|
36
36
|
return false;
|
|
37
37
|
}
|
|
38
|
+
const contractNames = new Map([
|
|
39
|
+
["queueable", "Queueable"],
|
|
40
|
+
["system.queueable", "System.Queueable"],
|
|
41
|
+
["database.batchable", "Database.Batchable"],
|
|
42
|
+
["schedulable", "Schedulable"],
|
|
43
|
+
["system.schedulable", "System.Schedulable"],
|
|
44
|
+
["messaging.inboundemailhandler", "Messaging.InboundEmailHandler"],
|
|
45
|
+
]);
|
|
46
|
+
const contractName = (name) => contractNames.get(normalized(name)) ?? name;
|
|
38
47
|
/** Static org-facing declarations, never a claim that an org actually invokes them. */
|
|
39
|
-
export function
|
|
48
|
+
export function apexPlatformEntryPoints(rows) {
|
|
40
49
|
const protectedSymbols = new Map();
|
|
50
|
+
const protect = (key, reason, contracts, owner) => {
|
|
51
|
+
const previous = protectedSymbols.get(key);
|
|
52
|
+
protectedSymbols.set(key, {
|
|
53
|
+
reason,
|
|
54
|
+
contracts: [...new Set([...(previous?.contracts ?? []), ...contracts])],
|
|
55
|
+
...(owner ? { ownerKey: owner } : {}),
|
|
56
|
+
});
|
|
57
|
+
};
|
|
41
58
|
const classes = new Map();
|
|
42
59
|
for (const row of rows) {
|
|
43
60
|
const decl = row.declaration;
|
|
@@ -46,9 +63,9 @@ export function apexOrgEntryPoints(rows) {
|
|
|
46
63
|
const key = ownerKey(row);
|
|
47
64
|
classes.set(key, [...(classes.get(key) ?? []), row]);
|
|
48
65
|
if (decl.annotations.some((name) => normalized(name) === "restresource"))
|
|
49
|
-
|
|
66
|
+
protect(row.key, "REST resource declaration", ["@RestResource"]);
|
|
50
67
|
if (decl.implements.some((name) => callbacks.has(normalized(name))))
|
|
51
|
-
|
|
68
|
+
protect(row.key, "Salesforce platform callback contract", decl.implements.filter((name) => callbacks.has(normalized(name))).map(contractName));
|
|
52
69
|
}
|
|
53
70
|
for (const row of rows) {
|
|
54
71
|
const decl = row.declaration;
|
|
@@ -62,6 +79,15 @@ export function apexOrgEntryPoints(rows) {
|
|
|
62
79
|
const annotations = new Set(decl.annotations.map(normalized));
|
|
63
80
|
const modifiers = new Set(decl.modifiers.map(normalized));
|
|
64
81
|
let reason;
|
|
82
|
+
const contracts = [];
|
|
83
|
+
if (annotations.has("invocablemethod") && decl.static)
|
|
84
|
+
contracts.push("@InvocableMethod");
|
|
85
|
+
if (annotations.has("auraenabled") && decl.static)
|
|
86
|
+
contracts.push("@AuraEnabled");
|
|
87
|
+
if (annotations.has("future") && decl.static)
|
|
88
|
+
contracts.push("@future");
|
|
89
|
+
if (modifiers.has("webservice") && decl.static)
|
|
90
|
+
contracts.push("webservice");
|
|
65
91
|
if (annotations.has("invocablemethod") && decl.static)
|
|
66
92
|
reason = "Invocable Apex declaration";
|
|
67
93
|
if (annotations.has("auraenabled") && decl.static)
|
|
@@ -72,15 +98,21 @@ export function apexOrgEntryPoints(rows) {
|
|
|
72
98
|
reason = "SOAP Apex declaration";
|
|
73
99
|
if (decl.static &&
|
|
74
100
|
owner.declaration.annotations.some((name) => normalized(name) === "restresource") &&
|
|
75
|
-
["httpget", "httppost", "httpput", "httppatch", "httpdelete"].some((name) => annotations.has(name)))
|
|
101
|
+
["httpget", "httppost", "httpput", "httppatch", "httpdelete"].some((name) => annotations.has(name))) {
|
|
76
102
|
reason = "REST Apex method declaration";
|
|
103
|
+
contracts.push("@RestResource");
|
|
104
|
+
}
|
|
77
105
|
if (!decl.static &&
|
|
78
106
|
(modifiers.has("public") || modifiers.has("global")) &&
|
|
79
|
-
owner.declaration.implements.some((name) => callbackSignature(normalized(name), decl)))
|
|
107
|
+
owner.declaration.implements.some((name) => callbackSignature(normalized(name), decl))) {
|
|
80
108
|
reason = "Salesforce platform callback method";
|
|
109
|
+
contracts.push(...owner.declaration.implements
|
|
110
|
+
.filter((name) => callbackSignature(normalized(name), decl))
|
|
111
|
+
.map(contractName));
|
|
112
|
+
}
|
|
81
113
|
if (reason) {
|
|
82
|
-
|
|
83
|
-
|
|
114
|
+
protect(row.key, reason, contracts, owner.key);
|
|
115
|
+
protect(owner.key, "Owner of an org-facing Apex declaration", contracts);
|
|
84
116
|
}
|
|
85
117
|
}
|
|
86
118
|
// A constructor of an org-facing class is a boundary, not an ordinary helper.
|
|
@@ -92,7 +124,11 @@ export function apexOrgEntryPoints(rows) {
|
|
|
92
124
|
if (owners.length === 1 &&
|
|
93
125
|
protectedSymbols.has(owners[0].key) &&
|
|
94
126
|
normalized(decl.name) === normalized(owners[0].declaration.name))
|
|
95
|
-
|
|
127
|
+
protect(row.key, "Constructor of an org-facing Apex class", protectedSymbols.get(owners[0].key)?.contracts ?? [], owners[0].key);
|
|
96
128
|
}
|
|
97
129
|
return protectedSymbols;
|
|
98
130
|
}
|
|
131
|
+
/** Compatibility projection used by dead-code exclusion; reasons retain their original precedence. */
|
|
132
|
+
export function apexOrgEntryPoints(rows) {
|
|
133
|
+
return new Map([...apexPlatformEntryPoints(rows)].map(([key, entry]) => [key, entry.reason]));
|
|
134
|
+
}
|