@ryanstark24/sfgraph-core 1.1.0 → 1.1.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.
Files changed (112) hide show
  1. package/dist/analyze/__tests__/audit-graph.test.d.ts +2 -0
  2. package/dist/analyze/__tests__/audit-graph.test.d.ts.map +1 -0
  3. package/dist/analyze/__tests__/audit-graph.test.js +122 -0
  4. package/dist/analyze/__tests__/audit-graph.test.js.map +1 -0
  5. package/dist/analyze/audit-graph.d.ts +48 -0
  6. package/dist/analyze/audit-graph.d.ts.map +1 -0
  7. package/dist/analyze/audit-graph.js +50 -0
  8. package/dist/analyze/audit-graph.js.map +1 -0
  9. package/dist/analyze/index.d.ts +1 -0
  10. package/dist/analyze/index.d.ts.map +1 -1
  11. package/dist/analyze/index.js +1 -0
  12. package/dist/analyze/index.js.map +1 -1
  13. package/dist/domain/rel-types.d.ts +7 -0
  14. package/dist/domain/rel-types.d.ts.map +1 -1
  15. package/dist/domain/rel-types.js +7 -0
  16. package/dist/domain/rel-types.js.map +1 -1
  17. package/dist/extractors/live-org/__tests__/rate-limit.test.js +46 -1
  18. package/dist/extractors/live-org/__tests__/rate-limit.test.js.map +1 -1
  19. package/dist/extractors/live-org/capabilities.d.ts.map +1 -1
  20. package/dist/extractors/live-org/capabilities.js +21 -3
  21. package/dist/extractors/live-org/capabilities.js.map +1 -1
  22. package/dist/extractors/live-org/discovery.d.ts.map +1 -1
  23. package/dist/extractors/live-org/discovery.js +2 -4
  24. package/dist/extractors/live-org/discovery.js.map +1 -1
  25. package/dist/extractors/live-org/extractors/apex.d.ts.map +1 -1
  26. package/dist/extractors/live-org/extractors/apex.js +4 -4
  27. package/dist/extractors/live-org/extractors/apex.js.map +1 -1
  28. package/dist/extractors/live-org/extractors/generic-sobject.d.ts.map +1 -1
  29. package/dist/extractors/live-org/extractors/generic-sobject.js +2 -2
  30. package/dist/extractors/live-org/extractors/generic-sobject.js.map +1 -1
  31. package/dist/extractors/live-org/extractors/lwc.d.ts.map +1 -1
  32. package/dist/extractors/live-org/extractors/lwc.js +3 -3
  33. package/dist/extractors/live-org/extractors/lwc.js.map +1 -1
  34. package/dist/extractors/live-org/extractors/object.d.ts.map +1 -1
  35. package/dist/extractors/live-org/extractors/object.js +4 -4
  36. package/dist/extractors/live-org/extractors/object.js.map +1 -1
  37. package/dist/extractors/live-org/extractors/omnistudio.d.ts.map +1 -1
  38. package/dist/extractors/live-org/extractors/omnistudio.js +3 -3
  39. package/dist/extractors/live-org/extractors/omnistudio.js.map +1 -1
  40. package/dist/extractors/live-org/rate-limit.d.ts +18 -11
  41. package/dist/extractors/live-org/rate-limit.d.ts.map +1 -1
  42. package/dist/extractors/live-org/rate-limit.js +51 -19
  43. package/dist/extractors/live-org/rate-limit.js.map +1 -1
  44. package/dist/extractors/live-org/source-member.d.ts.map +1 -1
  45. package/dist/extractors/live-org/source-member.js +3 -3
  46. package/dist/extractors/live-org/source-member.js.map +1 -1
  47. package/dist/extractors/live-org/vlocity/runner.d.ts.map +1 -1
  48. package/dist/extractors/live-org/vlocity/runner.js +71 -38
  49. package/dist/extractors/live-org/vlocity/runner.js.map +1 -1
  50. package/dist/index.d.ts +1 -0
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +2 -0
  53. package/dist/index.js.map +1 -1
  54. package/dist/ingest/__tests__/multi-org-orchestrator.test.js +4 -0
  55. package/dist/ingest/__tests__/multi-org-orchestrator.test.js.map +1 -1
  56. package/dist/ingest/live-ingest.d.ts +16 -0
  57. package/dist/ingest/live-ingest.d.ts.map +1 -1
  58. package/dist/ingest/live-ingest.js +93 -0
  59. package/dist/ingest/live-ingest.js.map +1 -1
  60. package/dist/parsers/__tests__/lwc-bindings.test.d.ts +2 -0
  61. package/dist/parsers/__tests__/lwc-bindings.test.d.ts.map +1 -0
  62. package/dist/parsers/__tests__/lwc-bindings.test.js +74 -0
  63. package/dist/parsers/__tests__/lwc-bindings.test.js.map +1 -0
  64. package/dist/parsers/apex/__tests__/arity-resolver.test.d.ts +2 -0
  65. package/dist/parsers/apex/__tests__/arity-resolver.test.d.ts.map +1 -0
  66. package/dist/parsers/apex/__tests__/arity-resolver.test.js +135 -0
  67. package/dist/parsers/apex/__tests__/arity-resolver.test.js.map +1 -0
  68. package/dist/parsers/apex/__tests__/ast-extractor.test.d.ts +2 -0
  69. package/dist/parsers/apex/__tests__/ast-extractor.test.d.ts.map +1 -0
  70. package/dist/parsers/apex/__tests__/ast-extractor.test.js +146 -0
  71. package/dist/parsers/apex/__tests__/ast-extractor.test.js.map +1 -0
  72. package/dist/parsers/apex/arity-resolver.d.ts +42 -0
  73. package/dist/parsers/apex/arity-resolver.d.ts.map +1 -0
  74. package/dist/parsers/apex/arity-resolver.js +111 -0
  75. package/dist/parsers/apex/arity-resolver.js.map +1 -0
  76. package/dist/parsers/apex/ast-extractor.d.ts +42 -0
  77. package/dist/parsers/apex/ast-extractor.d.ts.map +1 -0
  78. package/dist/parsers/apex/ast-extractor.js +402 -0
  79. package/dist/parsers/apex/ast-extractor.js.map +1 -0
  80. package/dist/parsers/apex/class.d.ts.map +1 -1
  81. package/dist/parsers/apex/class.js +56 -2
  82. package/dist/parsers/apex/class.js.map +1 -1
  83. package/dist/parsers/flow/__tests__/invocable-resolver.test.d.ts +2 -0
  84. package/dist/parsers/flow/__tests__/invocable-resolver.test.d.ts.map +1 -0
  85. package/dist/parsers/flow/__tests__/invocable-resolver.test.js +91 -0
  86. package/dist/parsers/flow/__tests__/invocable-resolver.test.js.map +1 -0
  87. package/dist/parsers/flow/invocable-resolver.d.ts +30 -0
  88. package/dist/parsers/flow/invocable-resolver.d.ts.map +1 -0
  89. package/dist/parsers/flow/invocable-resolver.js +67 -0
  90. package/dist/parsers/flow/invocable-resolver.js.map +1 -0
  91. package/dist/parsers/index.d.ts +2 -0
  92. package/dist/parsers/index.d.ts.map +1 -1
  93. package/dist/parsers/index.js +2 -0
  94. package/dist/parsers/index.js.map +1 -1
  95. package/dist/parsers/lwc/bundle.d.ts.map +1 -1
  96. package/dist/parsers/lwc/bundle.js +19 -4
  97. package/dist/parsers/lwc/bundle.js.map +1 -1
  98. package/dist/parsers/lwc/html-visitor.d.ts +2 -1
  99. package/dist/parsers/lwc/html-visitor.d.ts.map +1 -1
  100. package/dist/parsers/lwc/html-visitor.js +67 -3
  101. package/dist/parsers/lwc/html-visitor.js.map +1 -1
  102. package/dist/parsers/lwc/js-visitor.d.ts +22 -0
  103. package/dist/parsers/lwc/js-visitor.d.ts.map +1 -1
  104. package/dist/parsers/lwc/js-visitor.js +86 -2
  105. package/dist/parsers/lwc/js-visitor.js.map +1 -1
  106. package/dist/storage/interfaces.d.ts +9 -0
  107. package/dist/storage/interfaces.d.ts.map +1 -1
  108. package/dist/storage/sqlite/graph-store.d.ts +10 -0
  109. package/dist/storage/sqlite/graph-store.d.ts.map +1 -1
  110. package/dist/storage/sqlite/graph-store.js +56 -0
  111. package/dist/storage/sqlite/graph-store.js.map +1 -1
  112. package/package.json +4 -3
@@ -0,0 +1,91 @@
1
+ import { asOrgId, asQualifiedName, asSha256 } from "@ryanstark24/sfgraph-shared";
2
+ import { describe, expect, it } from "vitest";
3
+ import { REL_TYPES } from "../../../domain/index.js";
4
+ import { SqliteGraphStore } from "../../../storage/sqlite/graph-store.js";
5
+ import { makeTestCtx } from "../../__tests__/_harness.js";
6
+ import { resolveFlowApexMethods } from "../invocable-resolver.js";
7
+ async function seed() {
8
+ const store = new SqliteGraphStore({ dbPath: ":memory:" });
9
+ await store.init();
10
+ const orgId = asOrgId("org_test");
11
+ store.upsertOrg({
12
+ id: orgId,
13
+ alias: "test",
14
+ instanceUrl: "https://example.test",
15
+ apiVersion: "59.0",
16
+ createdAt: Date.now(),
17
+ });
18
+ return { store, orgId };
19
+ }
20
+ function node(orgId, qn, label, attrs = {}) {
21
+ const ts = Date.now();
22
+ return {
23
+ orgId,
24
+ qualifiedName: asQualifiedName(qn),
25
+ label,
26
+ attributes: attrs,
27
+ sourceHash: asSha256(qn),
28
+ firstSeenAt: ts,
29
+ lastSeenAt: ts,
30
+ lastModifiedAt: ts,
31
+ };
32
+ }
33
+ describe("resolveFlowApexMethods", () => {
34
+ it("emits FLOW_INVOKES_APEX_METHOD when the class has exactly one @InvocableMethod", async () => {
35
+ const { store, orgId } = await seed();
36
+ const ts = Date.now();
37
+ store.mergeNodes([
38
+ node(orgId, "FlowVersion:DoStuff/1", "FlowVersion"),
39
+ node(orgId, "ApexClass:DoStuffHandler", "ApexClass"),
40
+ node(orgId, "ApexMethod:DoStuffHandler.run(1)", "ApexMethod", { isInvocable: true }),
41
+ node(orgId, "ApexMethod:DoStuffHandler.helper(0)", "ApexMethod", { isInvocable: false }),
42
+ ]);
43
+ store.mergeEdges([
44
+ {
45
+ orgId,
46
+ srcQualifiedName: asQualifiedName("FlowVersion:DoStuff/1"),
47
+ dstQualifiedName: asQualifiedName("ApexClass:DoStuffHandler"),
48
+ relType: REL_TYPES.FLOW_INVOKES_APEX,
49
+ attributes: { actionName: "DoStuffHandler" },
50
+ firstSeenAt: ts,
51
+ lastSeenAt: ts,
52
+ },
53
+ ]);
54
+ const result = resolveFlowApexMethods(store, orgId, makeTestCtx());
55
+ expect(result).toMatchObject({ scanned: 1, resolved: 1, ambiguous: 0, missing: 0 });
56
+ const edges = store.listEdgesFrom(orgId, asQualifiedName("FlowVersion:DoStuff/1"), REL_TYPES.FLOW_INVOKES_APEX_METHOD);
57
+ expect(edges).toHaveLength(1);
58
+ expect(edges[0]?.dstQualifiedName).toBe("ApexMethod:DoStuffHandler.run(1)");
59
+ expect(edges[0]?.attributes.resolvedBy).toBe("flow-invocable-resolver");
60
+ // Class-level edge is left in place — additive resolution.
61
+ const classEdges = store.listEdgesFrom(orgId, asQualifiedName("FlowVersion:DoStuff/1"), REL_TYPES.FLOW_INVOKES_APEX);
62
+ expect(classEdges).toHaveLength(1);
63
+ await store.close();
64
+ });
65
+ it("reports missing when the target class has no invocable method", async () => {
66
+ const { store, orgId } = await seed();
67
+ const ts = Date.now();
68
+ store.mergeNodes([
69
+ node(orgId, "FlowVersion:Stale/1", "FlowVersion"),
70
+ node(orgId, "ApexClass:NotInvocable", "ApexClass"),
71
+ node(orgId, "ApexMethod:NotInvocable.run(0)", "ApexMethod", { isInvocable: false }),
72
+ ]);
73
+ store.mergeEdges([
74
+ {
75
+ orgId,
76
+ srcQualifiedName: asQualifiedName("FlowVersion:Stale/1"),
77
+ dstQualifiedName: asQualifiedName("ApexClass:NotInvocable"),
78
+ relType: REL_TYPES.FLOW_INVOKES_APEX,
79
+ attributes: {},
80
+ firstSeenAt: ts,
81
+ lastSeenAt: ts,
82
+ },
83
+ ]);
84
+ const result = resolveFlowApexMethods(store, orgId, makeTestCtx());
85
+ expect(result).toMatchObject({ scanned: 1, resolved: 0, missing: 1 });
86
+ const edges = store.listEdgesFrom(orgId, asQualifiedName("FlowVersion:Stale/1"), REL_TYPES.FLOW_INVOKES_APEX_METHOD);
87
+ expect(edges).toHaveLength(0);
88
+ await store.close();
89
+ });
90
+ });
91
+ //# sourceMappingURL=invocable-resolver.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invocable-resolver.test.js","sourceRoot":"","sources":["../../../../src/parsers/flow/__tests__/invocable-resolver.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { OrgId } from "@ryanstark24/sfgraph-shared";
2
+ import type { GraphStore } from "../../storage/interfaces.js";
3
+ import type { ParseContext } from "../contract.js";
4
+ /**
5
+ * Resolve `FLOW_INVOKES_APEX → ApexClass:Foo` edges to the specific
6
+ * `@InvocableMethod` defined on the class. Flow XML only exposes the class
7
+ * (and any input parameter mapping), not the method name — but because Apex
8
+ * allows at most one `@InvocableMethod` per class, we can pair them up
9
+ * unambiguously when there is exactly one such method.
10
+ *
11
+ * 0 invocable methods on the class → leave the class-level edge alone,
12
+ * count as `missing` (likely the class doesn't actually implement
13
+ * Invocable; could be a stale flow ref).
14
+ * 1 invocable method → emit a new FLOW_INVOKES_APEX_METHOD edge.
15
+ * >1 invocable methods → ambiguous (legal in Apex? technically the compiler
16
+ * forbids two `@InvocableMethod`s in one class, but we defend anyway).
17
+ */
18
+ export interface FlowInvocableResolveResult {
19
+ /** Flow→ApexClass edges scanned. */
20
+ scanned: number;
21
+ /** Edges that produced exactly one method-level edge. */
22
+ resolved: number;
23
+ /** Classes with multiple invocable methods — should never happen but
24
+ * tracked defensively. */
25
+ ambiguous: number;
26
+ /** Class qnames that didn't contain any `@InvocableMethod` annotation. */
27
+ missing: number;
28
+ }
29
+ export declare function resolveFlowApexMethods(store: GraphStore, orgIdIn: OrgId | string, ctx: ParseContext): FlowInvocableResolveResult;
30
+ //# sourceMappingURL=invocable-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invocable-resolver.d.ts","sourceRoot":"","sources":["../../../src/parsers/flow/invocable-resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAGzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,0BAA0B;IACzC,oCAAoC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB;+BAC2B;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,UAAU,EACjB,OAAO,EAAE,KAAK,GAAG,MAAM,EACvB,GAAG,EAAE,YAAY,GAChB,0BAA0B,CAyE5B"}
@@ -0,0 +1,67 @@
1
+ import { asOrgId, asQualifiedName } from "@ryanstark24/sfgraph-shared";
2
+ import { REL_TYPES } from "../../domain/index.js";
3
+ import { makeEdge } from "../common.js";
4
+ const METHOD_QNAME_RE = /^ApexMethod:(.+)\.([A-Za-z_][\w]*)\(\d+\)$/;
5
+ export function resolveFlowApexMethods(store, orgIdIn, ctx) {
6
+ const orgId = typeof orgIdIn === "string" ? asOrgId(orgIdIn) : orgIdIn;
7
+ const result = {
8
+ scanned: 0,
9
+ resolved: 0,
10
+ ambiguous: 0,
11
+ missing: 0,
12
+ };
13
+ // Build className → ApexMethod[] of invocable methods (one query, walked once).
14
+ const apexMethods = [
15
+ ...store.listNodesByLabel(orgId, "ApexMethod"),
16
+ ...store.listNodesByLabel(orgId, "TestMethod"),
17
+ ];
18
+ const invocableByClass = new Map();
19
+ for (const n of apexMethods) {
20
+ if (n.attributes?.isInvocable !== true)
21
+ continue;
22
+ const m = METHOD_QNAME_RE.exec(String(n.qualifiedName));
23
+ if (!m)
24
+ continue;
25
+ const cls = m[1] ?? "";
26
+ const bucket = invocableByClass.get(cls) ?? [];
27
+ bucket.push(n);
28
+ invocableByClass.set(cls, bucket);
29
+ }
30
+ // Find every FLOW_INVOKES_APEX edge and try to resolve it.
31
+ // listEdgesByDstLike("ApexClass:%") is cheap given how many ApexClass nodes
32
+ // exist in a typical org.
33
+ const flowEdges = store.listEdgesByDstLike(orgId, "ApexClass:%", REL_TYPES.FLOW_INVOKES_APEX);
34
+ const newEdges = [];
35
+ for (const edge of flowEdges) {
36
+ result.scanned += 1;
37
+ const className = String(edge.dstQualifiedName).slice("ApexClass:".length);
38
+ const candidates = invocableByClass.get(className) ?? [];
39
+ if (candidates.length === 0) {
40
+ result.missing += 1;
41
+ continue;
42
+ }
43
+ if (candidates.length > 1) {
44
+ result.ambiguous += 1;
45
+ // Still emit edges to all of them so downstream impact analysis sees both.
46
+ }
47
+ result.resolved += 1;
48
+ for (const m of candidates) {
49
+ const e = makeEdge(ctx, String(edge.srcQualifiedName), REL_TYPES.FLOW_INVOKES_APEX_METHOD, String(m.qualifiedName), {
50
+ ...edge.attributes,
51
+ resolvedBy: "flow-invocable-resolver",
52
+ ambiguous: candidates.length > 1,
53
+ });
54
+ newEdges.push({
55
+ ...e,
56
+ orgId: edge.orgId,
57
+ firstSeenAt: edge.firstSeenAt,
58
+ });
59
+ }
60
+ }
61
+ if (newEdges.length > 0)
62
+ store.mergeEdges(newEdges);
63
+ // Suppress an unused-import warning when asQualifiedName isn't directly used.
64
+ void asQualifiedName;
65
+ return result;
66
+ }
67
+ //# sourceMappingURL=invocable-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invocable-resolver.js","sourceRoot":"","sources":["../../../src/parsers/flow/invocable-resolver.ts"],"names":[],"mappings":"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"}
@@ -16,6 +16,8 @@ import "./generic/index.js";
16
16
  export * from "./contract.js";
17
17
  export { parserRegistry, resetRegistryForTests } from "./registry.js";
18
18
  export { resolveCrossFlavor, normalizeKey } from "./cross-flavor-resolver.js";
19
+ export { resolveApexMethodArity, type ArityResolveOpts, type ArityResolveResult, } from "./apex/arity-resolver.js";
20
+ export { resolveFlowApexMethods, type FlowInvocableResolveResult, } from "./flow/invocable-resolver.js";
19
21
  export { ParserWorkerPool } from "./worker-pool.js";
20
22
  export { loadAllRules } from "./rules/_loader.js";
21
23
  export { RuleBasedParser } from "./rules/_engine.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parsers/index.ts"],"names":[],"mappings":"AACA,OAAO,iBAAiB,CAAC;AACzB,OAAO,gBAAgB,CAAC;AACxB,OAAO,iBAAiB,CAAC;AACzB,OAAO,mBAAmB,CAAC;AAC3B,OAAO,qBAAqB,CAAC;AAC7B,OAAO,wBAAwB,CAAC;AAChC,OAAO,oBAAoB,CAAC;AAC5B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,eAAe,CAAC;AACvB,OAAO,yBAAyB,CAAC;AACjC,OAAO,sBAAsB,CAAC;AAC9B,OAAO,kBAAkB,CAAC;AAC1B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,oBAAoB,CAAC;AAE5B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parsers/index.ts"],"names":[],"mappings":"AACA,OAAO,iBAAiB,CAAC;AACzB,OAAO,gBAAgB,CAAC;AACxB,OAAO,iBAAiB,CAAC;AACzB,OAAO,mBAAmB,CAAC;AAC3B,OAAO,qBAAqB,CAAC;AAC7B,OAAO,wBAAwB,CAAC;AAChC,OAAO,oBAAoB,CAAC;AAC5B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,eAAe,CAAC;AACvB,OAAO,yBAAyB,CAAC;AACjC,OAAO,sBAAsB,CAAC;AAC9B,OAAO,kBAAkB,CAAC;AAC1B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,oBAAoB,CAAC;AAE5B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EACL,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,GACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,sBAAsB,EACtB,KAAK,0BAA0B,GAChC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
@@ -17,6 +17,8 @@ import "./generic/index.js";
17
17
  export * from "./contract.js";
18
18
  export { parserRegistry, resetRegistryForTests } from "./registry.js";
19
19
  export { resolveCrossFlavor, normalizeKey } from "./cross-flavor-resolver.js";
20
+ export { resolveApexMethodArity, } from "./apex/arity-resolver.js";
21
+ export { resolveFlowApexMethods, } from "./flow/invocable-resolver.js";
20
22
  export { ParserWorkerPool } from "./worker-pool.js";
21
23
  export { loadAllRules } from "./rules/_loader.js";
22
24
  export { RuleBasedParser } from "./rules/_engine.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parsers/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,iBAAiB,CAAC;AACzB,OAAO,gBAAgB,CAAC;AACxB,OAAO,iBAAiB,CAAC;AACzB,OAAO,mBAAmB,CAAC;AAC3B,OAAO,qBAAqB,CAAC;AAC7B,OAAO,wBAAwB,CAAC;AAChC,OAAO,oBAAoB,CAAC;AAC5B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,eAAe,CAAC;AACvB,OAAO,yBAAyB,CAAC;AACjC,OAAO,sBAAsB,CAAC;AAC9B,OAAO,kBAAkB,CAAC;AAC1B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,oBAAoB,CAAC;AAE5B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parsers/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,iBAAiB,CAAC;AACzB,OAAO,gBAAgB,CAAC;AACxB,OAAO,iBAAiB,CAAC;AACzB,OAAO,mBAAmB,CAAC;AAC3B,OAAO,qBAAqB,CAAC;AAC7B,OAAO,wBAAwB,CAAC;AAChC,OAAO,oBAAoB,CAAC;AAC5B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,eAAe,CAAC;AACvB,OAAO,yBAAyB,CAAC;AACjC,OAAO,sBAAsB,CAAC;AAC9B,OAAO,kBAAkB,CAAC;AAC1B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,oBAAoB,CAAC;AAC5B,OAAO,oBAAoB,CAAC;AAE5B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EACL,sBAAsB,GAGvB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,sBAAsB,GAEvB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../../../src/parsers/lwc/bundle.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAKxE,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAkBD,qBAAa,eAAgB,YAAW,MAAM,CAAC,cAAc,CAAC;IAC5D,QAAQ,CAAC,QAAQ,6BAAyB;IAC1C,QAAQ,CAAC,IAAI,8BAA8B;IAErC,KAAK,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;CAuC5E"}
1
+ {"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../../../src/parsers/lwc/bundle.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAKxE,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAkBD,qBAAa,eAAgB,YAAW,MAAM,CAAC,cAAc,CAAC;IAC5D,QAAQ,CAAC,QAAQ,6BAAyB;IAC1C,QAAQ,CAAC,IAAI,8BAA8B;IAErC,KAAK,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;CAoD5E"}
@@ -34,15 +34,30 @@ export class LwcBundleParser {
34
34
  nodes.push(makeNode(ctx, "LWC", lwcQname, { name: bundleName, ...meta }, hash));
35
35
  nodes.push(makeNode(ctx, "LWCBundle", bundleQname, { name: bundleName, files: Object.keys(input.files) }, hash));
36
36
  edges.push(makeEdge(ctx, bundleQname, REL_TYPES.CONTAINS_COMPONENT, lwcQname));
37
- // JS files
37
+ // Pass 1: walk the JS first so we know which template variables are
38
+ // wired to which sObjects before walking the HTML.
39
+ const mergedBindings = {
40
+ wireToSObject: new Map(),
41
+ schemaFieldImports: new Map(),
42
+ schemaObjectImports: new Map(),
43
+ };
38
44
  for (const [fname, source] of Object.entries(input.files)) {
39
45
  if (fname.endsWith(".js")) {
40
- const { extraEdges, extraNodes } = extractJsEdges(source, lwcQname, ctx);
46
+ const { extraEdges, extraNodes, bindings: b } = extractJsEdges(source, lwcQname, ctx);
41
47
  edges.push(...extraEdges);
42
48
  nodes.push(...extraNodes);
49
+ for (const [k, v] of b.wireToSObject)
50
+ mergedBindings.wireToSObject.set(k, v);
51
+ for (const [k, v] of b.schemaFieldImports)
52
+ mergedBindings.schemaFieldImports.set(k, v);
53
+ for (const [k, v] of b.schemaObjectImports)
54
+ mergedBindings.schemaObjectImports.set(k, v);
43
55
  }
44
- else if (fname.endsWith(".html")) {
45
- const { extraEdges, extraNodes } = extractHtmlEdges(source, lwcQname, ctx);
56
+ }
57
+ // Pass 2: HTML, with the merged bindings available.
58
+ for (const [fname, source] of Object.entries(input.files)) {
59
+ if (fname.endsWith(".html")) {
60
+ const { extraEdges, extraNodes } = extractHtmlEdges(source, lwcQname, ctx, mergedBindings);
46
61
  edges.push(...extraEdges);
47
62
  nodes.push(...extraNodes);
48
63
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bundle.js","sourceRoot":"","sources":["../../../src/parsers/lwc/bundle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bundle.js","sourceRoot":"","sources":["../../../src/parsers/lwc/bundle.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,9 @@
1
1
  import type { EdgeFact, NodeFact } from "../../domain/index.js";
2
2
  import type { ParseContext } from "../contract.js";
3
+ import type { LwcBindings } from "./js-visitor.js";
3
4
  export interface HtmlExtractResult {
4
5
  extraEdges: EdgeFact[];
5
6
  extraNodes: NodeFact[];
6
7
  }
7
- export declare function extractHtmlEdges(source: string, lwcQname: string, ctx: ParseContext): HtmlExtractResult;
8
+ export declare function extractHtmlEdges(source: string, lwcQname: string, ctx: ParseContext, bindings?: LwcBindings): HtmlExtractResult;
8
9
  //# sourceMappingURL=html-visitor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"html-visitor.d.ts","sourceRoot":"","sources":["../../../src/parsers/lwc/html-visitor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,QAAQ,EAAE,CAAC;IACvB,UAAU,EAAE,QAAQ,EAAE,CAAC;CACxB;AAWD,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,YAAY,GAChB,iBAAiB,CA4CnB"}
1
+ {"version":3,"file":"html-visitor.d.ts","sourceRoot":"","sources":["../../../src/parsers/lwc/html-visitor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEnD,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,QAAQ,EAAE,CAAC;IACvB,UAAU,EAAE,QAAQ,EAAE,CAAC;CACxB;AAaD,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,YAAY,EACjB,QAAQ,CAAC,EAAE,WAAW,GACrB,iBAAiB,CA2GnB"}
@@ -1,6 +1,6 @@
1
1
  import { parse as parseHtml } from "parse5";
2
2
  import { REL_TYPES } from "../../domain/index.js";
3
- import { makeEdge } from "../common.js";
3
+ import { makeEdge, stripNs } from "../common.js";
4
4
  function walk(node, visit) {
5
5
  visit(node);
6
6
  // <template> elements wrap their children in a `content` DocumentFragment per HTML spec.
@@ -11,13 +11,73 @@ function walk(node, visit) {
11
11
  for (const c of kids)
12
12
  walk(c, visit);
13
13
  }
14
- export function extractHtmlEdges(source, lwcQname, ctx) {
14
+ const BINDING_RE = /\{([A-Za-z_][\w]*(?:\.[A-Za-z_][\w]*)*)\}/g;
15
+ export function extractHtmlEdges(source, lwcQname, ctx, bindings) {
15
16
  const extraEdges = [];
16
17
  const extraNodes = [];
17
18
  const tree = parseHtml(source);
18
19
  const seenLwc = new Set();
19
20
  const seenEvt = new Set();
21
+ const seenField = new Set();
22
+ const seenProperty = new Set();
23
+ const emitBinding = (expr) => {
24
+ // `record.Name` → split into [record, Name]; `record.fields.Account.Name`
25
+ // is unusual in templates and falls through to property.
26
+ const parts = expr.split(".");
27
+ const head = parts[0] ?? "";
28
+ if (bindings && parts.length >= 2) {
29
+ const sObject = bindings.wireToSObject.get(head);
30
+ if (sObject) {
31
+ // Extract the field name from the binding, handling both adapter shapes:
32
+ // `record.Name` → tail = [Name] → field = Name
33
+ // `record.fields.Name` → tail = [fields, Name] → field = Name
34
+ // `record.fields.Name.value` → tail = [fields, Name, value] → field = Name
35
+ // (v53+ getRecord returns FieldValueRepresentation; templates
36
+ // access `.value` on the field proxy.)
37
+ // We deliberately *don't* concatenate intermediate segments — they're
38
+ // either the `fields` accessor or the proxy `.value`/`.displayValue`,
39
+ // neither of which are part of the CustomField qname.
40
+ const tail = parts.slice(1);
41
+ let field = "";
42
+ if (tail[0] === "fields") {
43
+ field = tail[1] ?? "";
44
+ }
45
+ else if (tail.length === 1) {
46
+ field = tail[0] ?? "";
47
+ }
48
+ if (field) {
49
+ const dst = `CustomField:${stripNs(sObject, ctx.namespace)}.${stripNs(field, ctx.namespace)}`;
50
+ if (!seenField.has(dst)) {
51
+ seenField.add(dst);
52
+ extraEdges.push(makeEdge(ctx, lwcQname, REL_TYPES.LWC_BINDS_FIELD, dst, { binding: expr }));
53
+ }
54
+ return;
55
+ }
56
+ }
57
+ }
58
+ const dst = `LWCProperty:${expr}`;
59
+ if (!seenProperty.has(dst)) {
60
+ seenProperty.add(dst);
61
+ extraEdges.push(makeEdge(ctx, lwcQname, REL_TYPES.LWC_BINDS_PROPERTY, dst, { binding: expr }));
62
+ }
63
+ };
64
+ const scanText = (text) => {
65
+ if (!text || text.indexOf("{") < 0)
66
+ return;
67
+ BINDING_RE.lastIndex = 0;
68
+ let m = BINDING_RE.exec(text);
69
+ while (m !== null) {
70
+ const expr = m[1];
71
+ if (expr)
72
+ emitBinding(expr);
73
+ m = BINDING_RE.exec(text);
74
+ }
75
+ };
20
76
  walk(tree, (n) => {
77
+ // Text nodes carry mustache bindings — `{record.Name}`, `{count}`, etc.
78
+ if (n?.nodeName === "#text" && typeof n?.value === "string") {
79
+ scanText(n.value);
80
+ }
21
81
  const tag = n?.tagName;
22
82
  if (!tag)
23
83
  return;
@@ -40,7 +100,8 @@ export function extractHtmlEdges(source, lwcQname, ctx) {
40
100
  extraEdges.push(makeEdge(ctx, lwcQname, REL_TYPES.EMBEDS_AURA, dst, { tag }));
41
101
  }
42
102
  }
43
- // Attributes that look like onevent listeners
103
+ // Attributes that look like onevent listeners + mustache bindings in
104
+ // attribute values (e.g. `<lightning-input value={record.Name}>`).
44
105
  for (const a of n?.attrs ?? []) {
45
106
  const name = a?.name ?? "";
46
107
  if (name.startsWith("on") && name.length > 2) {
@@ -50,6 +111,9 @@ export function extractHtmlEdges(source, lwcQname, ctx) {
50
111
  extraEdges.push(makeEdge(ctx, lwcQname, REL_TYPES.LISTENS_TO_EVENT, `LWCEvent:${evtName}`));
51
112
  }
52
113
  }
114
+ const val = a?.value;
115
+ if (typeof val === "string")
116
+ scanText(val);
53
117
  }
54
118
  });
55
119
  return { extraEdges, extraNodes };
@@ -1 +1 @@
1
- {"version":3,"file":"html-visitor.js","sourceRoot":"","sources":["../../../src/parsers/lwc/html-visitor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"html-visitor.js","sourceRoot":"","sources":["../../../src/parsers/lwc/html-visitor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,QAAQ,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AASjD,SAAS,IAAI,CAAC,IAAS,EAAE,KAAuB;IAC9C,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,yFAAyF;IACzF,MAAM,UAAU,GAAG,IAAI,EAAE,OAAO,EAAE,UAAU,IAAI,EAAE,CAAC;IACnD,KAAK,MAAM,CAAC,IAAI,UAAU;QAAE,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,IAAI,EAAE,UAAU,IAAI,EAAE,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,IAAI;QAAE,IAAI,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,GAAG,4CAA4C,CAAC;AAEhE,MAAM,UAAU,gBAAgB,CAC9B,MAAc,EACd,QAAgB,EAChB,GAAiB,EACjB,QAAsB;IAEtB,MAAM,UAAU,GAAe,EAAE,CAAC;IAClC,MAAM,UAAU,GAAe,EAAE,CAAC;IAClC,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAC/B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IACpC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;IAEvC,MAAM,WAAW,GAAG,CAAC,IAAY,EAAQ,EAAE;QACzC,0EAA0E;QAC1E,yDAAyD;QACzD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,QAAQ,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YAClC,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACjD,IAAI,OAAO,EAAE,CAAC;gBACZ,yEAAyE;gBACzE,4EAA4E;gBAC5E,4EAA4E;gBAC5E,6EAA6E;gBAC7E,kEAAkE;gBAClE,4CAA4C;gBAC5C,sEAAsE;gBACtE,sEAAsE;gBACtE,sDAAsD;gBACtD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC5B,IAAI,KAAK,GAAG,EAAE,CAAC;gBACf,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;oBACzB,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBACxB,CAAC;qBAAM,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC7B,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBACxB,CAAC;gBACD,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,GAAG,GAAG,eAAe,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;oBAC9F,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;wBACxB,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;wBACnB,UAAU,CAAC,IAAI,CACb,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,CAAC,eAAe,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAC3E,CAAC;oBACJ,CAAC;oBACD,OAAO;gBACT,CAAC;YACH,CAAC;QACH,CAAC;QACD,MAAM,GAAG,GAAG,eAAe,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACtB,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,CAAC,kBAAkB,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QACjG,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAQ,EAAE;QACtC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO;QAC3C,UAAU,CAAC,SAAS,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,GAA2B,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtD,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;YAClB,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAClB,IAAI,IAAI;gBAAE,WAAW,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CAAC;IAEF,IAAI,CAAC,IAAI,EAAE,CAAC,CAAM,EAAE,EAAE;QACpB,wEAAwE;QACxE,IAAI,CAAC,EAAE,QAAQ,KAAK,OAAO,IAAI,OAAO,CAAC,EAAE,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC5D,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC;QACD,MAAM,GAAG,GAAuB,CAAC,EAAE,OAAO,CAAC;QAC3C,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,mFAAmF;QACnF,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QACpD,IAAI,CAAC,EAAE,CAAC;YACN,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAChB,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACxB,4CAA4C;YAC5C,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YACpF,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,WAAW,EAAE,CAAC;gBACrC,MAAM,GAAG,GAAG,OAAO,UAAU,EAAE,CAAC;gBAChC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBACtB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBACjB,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,CAAC,UAAU,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;gBAC/E,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,GAAG,iBAAiB,EAAE,IAAI,IAAI,EAAE,CAAC;gBAC1C,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,CAAC,WAAW,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;YAChF,CAAC;QACH,CAAC;QACD,qEAAqE;QACrE,mEAAmE;QACnE,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE,EAAE,CAAC;YAC/B,MAAM,IAAI,GAAW,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;YACnC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC9B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC1B,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;oBACrB,UAAU,CAAC,IAAI,CACb,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,SAAS,CAAC,gBAAgB,EAAE,YAAY,OAAO,EAAE,CAAC,CAC3E,CAAC;gBACJ,CAAC;YACH,CAAC;YACD,MAAM,GAAG,GAAuB,CAAC,EAAE,KAAK,CAAC;YACzC,IAAI,OAAO,GAAG,KAAK,QAAQ;gBAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;AACpC,CAAC"}
@@ -3,6 +3,28 @@ import type { ParseContext } from "../contract.js";
3
3
  export interface JsExtractResult {
4
4
  extraEdges: EdgeFact[];
5
5
  extraNodes: NodeFact[];
6
+ /** Phase 5: bindings the HTML visitor needs to resolve `{var.field}`. */
7
+ bindings: LwcBindings;
8
+ }
9
+ /**
10
+ * LWC template bindings discovered through JS analysis. Consumed by
11
+ * html-visitor to resolve `{var.field}` expressions in markup to real
12
+ * CustomField qnames when possible.
13
+ */
14
+ export interface LwcBindings {
15
+ /** Map of wired property name → sObject API name. Populated from
16
+ * `@wire(getRecord, { fields: [...] })` and similar wire adapters whose
17
+ * result is bound to an instance property. */
18
+ wireToSObject: Map<string, string>;
19
+ /** Map of imported local name → CustomField qname. From
20
+ * `import NAME_FIELD from '@salesforce/schema/Account.Name'`. */
21
+ schemaFieldImports: Map<string, {
22
+ sObject: string;
23
+ field: string;
24
+ }>;
25
+ /** Map of imported local name → sObject API name. From
26
+ * `import ACCOUNT_OBJECT from '@salesforce/schema/Account'`. */
27
+ schemaObjectImports: Map<string, string>;
6
28
  }
7
29
  export declare function extractJsEdges(source: string, lwcQname: string, ctx: ParseContext): JsExtractResult;
8
30
  //# sourceMappingURL=js-visitor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"js-visitor.d.ts","sourceRoot":"","sources":["../../../src/parsers/lwc/js-visitor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAKnD,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,QAAQ,EAAE,CAAC;IACvB,UAAU,EAAE,QAAQ,EAAE,CAAC;CACxB;AAMD,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,YAAY,GAChB,eAAe,CAgIjB"}
1
+ {"version":3,"file":"js-visitor.d.ts","sourceRoot":"","sources":["../../../src/parsers/lwc/js-visitor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAKnD,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,QAAQ,EAAE,CAAC;IACvB,UAAU,EAAE,QAAQ,EAAE,CAAC;IACvB,yEAAyE;IACzE,QAAQ,EAAE,WAAW,CAAC;CACvB;AAQD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;mDAE+C;IAC/C,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC;sEACkE;IAClE,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpE;qEACiE;IACjE,mBAAmB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1C;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,YAAY,GAChB,eAAe,CAmOjB"}
@@ -7,11 +7,18 @@ const traverse = _traverse.default ?? _traverse;
7
7
  const APEX_IMPORT_RE = /^@salesforce\/apex\/([A-Za-z_]\w*)\.([A-Za-z_]\w*)$/;
8
8
  const SR_IMPORT_RE = /^@salesforce\/resourceUrl\/([A-Za-z_]\w*)$/;
9
9
  const LABEL_IMPORT_RE = /^@salesforce\/label\/c\.([A-Za-z_]\w*)$/;
10
+ const SCHEMA_OBJ_RE = /^@salesforce\/schema\/([A-Za-z_][\w]*)$/;
11
+ const SCHEMA_FIELD_RE = /^@salesforce\/schema\/([A-Za-z_][\w]*)\.([A-Za-z_][\w]*)$/;
10
12
  export function extractJsEdges(source, lwcQname, ctx) {
11
13
  const extraEdges = [];
12
14
  const extraNodes = [];
13
15
  // Map of localName -> { className, methodName } for apex imports.
14
16
  const apexImports = {};
17
+ const bindings = {
18
+ wireToSObject: new Map(),
19
+ schemaFieldImports: new Map(),
20
+ schemaObjectImports: new Map(),
21
+ };
15
22
  let ast;
16
23
  try {
17
24
  ast = parser.parse(source, {
@@ -23,7 +30,7 @@ export function extractJsEdges(source, lwcQname, ctx) {
23
30
  extraNodes.push(makeNode(ctx, "ParseError", `ParseError:LWC:${lwcQname}`, {
24
31
  message: err instanceof Error ? err.message : String(err),
25
32
  }));
26
- return { extraEdges, extraNodes };
33
+ return { extraEdges, extraNodes, bindings };
27
34
  }
28
35
  traverse(ast, {
29
36
  ImportDeclaration(path) {
@@ -50,6 +57,29 @@ export function extractJsEdges(source, lwcQname, ctx) {
50
57
  m = LABEL_IMPORT_RE.exec(src);
51
58
  if (m) {
52
59
  extraEdges.push(makeEdge(ctx, lwcQname, REL_TYPES.IMPORTS_CUSTOM_LABEL, `CustomLabel:${stripNs(m[1] ?? "", ctx.namespace)}`));
60
+ return;
61
+ }
62
+ // Schema field import: `import NAME_FIELD from '@salesforce/schema/Account.Name'`.
63
+ m = SCHEMA_FIELD_RE.exec(src);
64
+ if (m) {
65
+ const sObject = stripNs(m[1] ?? "", ctx.namespace);
66
+ const field = m[2] ?? "";
67
+ const localDefault = path.node.specifiers?.find((s) => s.type === "ImportDefaultSpecifier");
68
+ if (localDefault?.local?.name) {
69
+ bindings.schemaFieldImports.set(String(localDefault.local.name), { sObject, field });
70
+ }
71
+ extraEdges.push(makeEdge(ctx, lwcQname, REL_TYPES.READS_FIELD, `CustomField:${sObject}.${field}`, { via: "schema-import" }));
72
+ return;
73
+ }
74
+ // Schema object import: `import ACCOUNT_OBJECT from '@salesforce/schema/Account'`.
75
+ m = SCHEMA_OBJ_RE.exec(src);
76
+ if (m) {
77
+ const sObject = stripNs(m[1] ?? "", ctx.namespace);
78
+ const localDefault = path.node.specifiers?.find((s) => s.type === "ImportDefaultSpecifier");
79
+ if (localDefault?.local?.name) {
80
+ bindings.schemaObjectImports.set(String(localDefault.local.name), sObject);
81
+ }
82
+ extraEdges.push(makeEdge(ctx, lwcQname, REL_TYPES.REFERENCES_OBJECT, `CustomObject:${sObject}`, { via: "schema-import" }));
53
83
  }
54
84
  },
55
85
  Decorator(path) {
@@ -62,6 +92,60 @@ export function extractJsEdges(source, lwcQname, ctx) {
62
92
  extraEdges.push(makeEdge(ctx, lwcQname, REL_TYPES.USES_WIRE, `ApexMethod:${target.className}.${target.methodName}(?)`, { kind: "apex" }));
63
93
  }
64
94
  }
95
+ // For wire adapters that return a record/records of a known sObject
96
+ // (getRecord / getRecords / getRelatedListRecords), bind the wired
97
+ // property name to that sObject so the template visitor can resolve
98
+ // `{record.Name}` → CustomField:Account.Name.
99
+ const wireAdapter = arg0?.type === "Identifier" ? String(arg0.name) : "";
100
+ const RECORD_ADAPTERS = new Set([
101
+ "getRecord",
102
+ "getRecords",
103
+ "getRecordCreateDefaults",
104
+ "getRecordUi",
105
+ "getRelatedListRecords",
106
+ ]);
107
+ if (RECORD_ADAPTERS.has(wireAdapter)) {
108
+ // Pull `fields: [X, Y]` from the second arg if present, infer
109
+ // sObject from the first imported schema field.
110
+ const optsArg = expr.arguments?.[1];
111
+ let sObject = null;
112
+ if (optsArg?.type === "ObjectExpression") {
113
+ for (const prop of optsArg.properties) {
114
+ const keyName = prop?.key?.name ?? prop?.key?.value;
115
+ if (keyName === "fields" || keyName === "optionalFields") {
116
+ const elements = prop.value?.elements ?? [];
117
+ for (const el of elements) {
118
+ if (el?.type === "Identifier") {
119
+ const ref = bindings.schemaFieldImports.get(String(el.name));
120
+ if (ref) {
121
+ sObject = ref.sObject;
122
+ break;
123
+ }
124
+ }
125
+ }
126
+ }
127
+ else if (keyName === "objectApiName") {
128
+ const v = prop.value;
129
+ if (v?.type === "Identifier") {
130
+ const ref = bindings.schemaObjectImports.get(String(v.name));
131
+ if (ref)
132
+ sObject = ref;
133
+ }
134
+ }
135
+ if (sObject)
136
+ break;
137
+ }
138
+ }
139
+ // The decorated node is a ClassProperty / MethodDefinition; pull its name.
140
+ const decoratedName = (() => {
141
+ const parent = path.parentPath?.node;
142
+ const key = parent?.key;
143
+ return key?.name ?? key?.value;
144
+ })();
145
+ if (sObject && typeof decoratedName === "string") {
146
+ bindings.wireToSObject.set(decoratedName, sObject);
147
+ }
148
+ }
65
149
  }
66
150
  },
67
151
  CallExpression(path) {
@@ -85,7 +169,7 @@ export function extractJsEdges(source, lwcQname, ctx) {
85
169
  }
86
170
  },
87
171
  });
88
- return { extraEdges, extraNodes };
172
+ return { extraEdges, extraNodes, bindings };
89
173
  }
90
174
  function lwcCtx(ctx) {
91
175
  return ctx;