diff --git a/buf.gen.yaml b/buf.gen.yaml
index 15e71d5a..74863384 100644
--- a/buf.gen.yaml
+++ b/buf.gen.yaml
@@ -9,16 +9,15 @@ plugins:
out: src/shared/pyroscope-api
opt: target=ts
inputs:
- # Build a subset of the Pyroscope protobuf API
+ # Build a subset of the Pyroscope protobuf API
- git_repo: https://github.com/grafana/pyroscope.git
# Update this to any commit, which is merged in Pyroscope main
ref: weekly-f105-886b418af
subdir: api
paths:
- - adhocprofiles/
- - querier/
- - settings/
- - types/
- - vcs/
- - google/
-
+ - adhocprofiles/
+ - querier/
+ - settings/
+ - types/
+ - vcs/
+ - google/
diff --git a/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/CodeContainer.tsx b/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/CodeContainer.tsx
index f3539772..07ab5880 100644
--- a/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/CodeContainer.tsx
+++ b/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/CodeContainer.tsx
@@ -22,7 +22,7 @@ export function CodeContainer({ dataSourceUid, functionDetails }: CodeContainerP
return (
<>
) : null}
diff --git a/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/__tests__/annotateLines.spec.ts b/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/__tests__/annotateLines.spec.ts
new file mode 100644
index 00000000..e7baf144
--- /dev/null
+++ b/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/__tests__/annotateLines.spec.ts
@@ -0,0 +1,703 @@
+import { annotateLines, annotatePlaceholderLines } from '../annotateLines';
+
+describe('buildPlaceholderLineProfiles(callSitesMap)', () => {
+ describe('if callSitesMap is empty', () => {
+ it('returns an empty snippet and empty allLines array', () => {
+ const result = annotatePlaceholderLines(new Map());
+ expect(result).toEqual({
+ snippetLines: [],
+ allLines: [],
+ });
+ });
+ });
+
+ describe('if callSitesMap is not empty', () => {
+ it('returns a snippet of annotated code lines', () => {
+ const { snippetLines, allLines } = annotatePlaceholderLines(
+ new Map([
+ [12, { line: 12, flat: 0, cum: 40000000 }],
+ [15, { line: 15, flat: 0, cum: 710000000 }],
+ [11, { line: 11, flat: 0, cum: 30000000 }],
+ ])
+ );
+
+ expect(snippetLines).toEqual([
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 6,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 7,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 8,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 9,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 10,
+ },
+ {
+ cum: 30000000,
+ flat: 0,
+ line: undefined,
+ number: 11,
+ },
+ {
+ cum: 40000000,
+ flat: 0,
+ line: undefined,
+ number: 12,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 13,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 14,
+ },
+ {
+ cum: 710000000,
+ flat: 0,
+ line: undefined,
+ number: 15,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 16,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 17,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 18,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 19,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 20,
+ },
+ ]);
+
+ expect(allLines).toEqual([]);
+ });
+
+ describe('when the lines contained in callSitesMap are smaller than the number of padded lines', () => {
+ it('returns an array cropped properly', () => {
+ const { snippetLines, allLines } = annotatePlaceholderLines(
+ new Map([
+ [2, { line: 2, flat: 0, cum: 40000000 }],
+ [4, { line: 4, flat: 0, cum: 710000000 }],
+ [1, { line: 1, flat: 0, cum: 30000000 }],
+ ])
+ );
+
+ expect(snippetLines).toEqual([
+ {
+ cum: 30000000,
+ flat: 0,
+ line: undefined,
+ number: 1,
+ },
+ {
+ cum: 40000000,
+ flat: 0,
+ line: undefined,
+ number: 2,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 3,
+ },
+ {
+ cum: 710000000,
+ flat: 0,
+ line: undefined,
+ number: 4,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 5,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 6,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 7,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 8,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: undefined,
+ number: 9,
+ },
+ ]);
+
+ expect(allLines).toEqual([]);
+ });
+ });
+ });
+});
+
+describe('buildLineProfiles(fileContent, callSitesMap', () => {
+ describe('if callSitesMap is empty', () => {
+ it('returns an empty snippet array', () => {
+ const { snippetLines, allLines } = annotateLines('// this file is empty', new Map());
+ expect(snippetLines).toEqual([]);
+ expect(allLines).toEqual([
+ {
+ cum: 0,
+ flat: 0,
+ line: '// this file is empty',
+ number: 1,
+ },
+ ]);
+ });
+ });
+
+ describe('if callSitesMap is not empty', () => {
+ const fileContent = `import { buildLineProfiles, buildPlaceholderLineProfiles } from '../buildLineProfiles';
+
+describe('buildPlaceholderLineProfiles(callSitesMap)', () => {
+ describe('if callSitesMap is empty', () => {
+ it('returns an empty array', () => {
+ const result = buildPlaceholderLineProfiles(new Map());
+ expect(result).toEqual([]);
+ });
+ });
+
+ describe('if callSitesMap is not empty', () => {
+ it('returns an array containing samples/line info, sorted by line number and padded with extra lines', () => {
+ const result = buildPlaceholderLineProfiles(
+ new Map([
+ [12, { line: 12, flat: 0, cum: 40000000 }],
+ [15, { line: 15, flat: 0, cum: 710000000 }],
+ [11, { line: 11, flat: 0, cum: 30000000 }],
+ ])
+ );
+
+ expect(result).toMatchInlineSnapshot();
+ });
+ });
+});`;
+
+ it('returns an array containing samples/line info, sorted by line number and padded with extra lines', () => {
+ const { snippetLines, allLines } = annotateLines(
+ fileContent,
+ new Map([
+ [12, { line: 12, flat: 0, cum: 40000000 }],
+ [15, { line: 15, flat: 0, cum: 710000000 }],
+ [11, { line: 11, flat: 0, cum: 30000000 }],
+ ])
+ );
+
+ expect(snippetLines).toEqual([
+ {
+ cum: 0,
+ flat: 0,
+ line: ' const result = buildPlaceholderLineProfiles(new Map());',
+ number: 6,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' expect(result).toEqual([]);',
+ number: 7,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' });',
+ number: 8,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' });',
+ number: 9,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: '',
+ number: 10,
+ },
+ {
+ cum: 30000000,
+ flat: 0,
+ line: " describe('if callSitesMap is not empty', () => {",
+ number: 11,
+ },
+ {
+ cum: 40000000,
+ flat: 0,
+ line: " it('returns an array containing samples/line info, sorted by line number and padded with extra lines', () => {",
+ number: 12,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' const result = buildPlaceholderLineProfiles(',
+ number: 13,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' new Map([',
+ number: 14,
+ },
+ {
+ cum: 710000000,
+ flat: 0,
+ line: ' [12, { line: 12, flat: 0, cum: 40000000 }],',
+ number: 15,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' [15, { line: 15, flat: 0, cum: 710000000 }],',
+ number: 16,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' [11, { line: 11, flat: 0, cum: 30000000 }],',
+ number: 17,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' ])',
+ number: 18,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' );',
+ number: 19,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: '',
+ number: 20,
+ },
+ ]);
+
+ expect(allLines).toEqual([
+ {
+ cum: 0,
+ flat: 0,
+ line: "import { buildLineProfiles, buildPlaceholderLineProfiles } from '../buildLineProfiles';",
+ number: 1,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: '',
+ number: 2,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: "describe('buildPlaceholderLineProfiles(callSitesMap)', () => {",
+ number: 3,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: " describe('if callSitesMap is empty', () => {",
+ number: 4,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: " it('returns an empty array', () => {",
+ number: 5,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' const result = buildPlaceholderLineProfiles(new Map());',
+ number: 6,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' expect(result).toEqual([]);',
+ number: 7,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' });',
+ number: 8,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' });',
+ number: 9,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: '',
+ number: 10,
+ },
+ {
+ cum: 30000000,
+ flat: 0,
+ line: " describe('if callSitesMap is not empty', () => {",
+ number: 11,
+ },
+ {
+ cum: 40000000,
+ flat: 0,
+ line: " it('returns an array containing samples/line info, sorted by line number and padded with extra lines', () => {",
+ number: 12,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' const result = buildPlaceholderLineProfiles(',
+ number: 13,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' new Map([',
+ number: 14,
+ },
+ {
+ cum: 710000000,
+ flat: 0,
+ line: ' [12, { line: 12, flat: 0, cum: 40000000 }],',
+ number: 15,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' [15, { line: 15, flat: 0, cum: 710000000 }],',
+ number: 16,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' [11, { line: 11, flat: 0, cum: 30000000 }],',
+ number: 17,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' ])',
+ number: 18,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' );',
+ number: 19,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: '',
+ number: 20,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' expect(result).toMatchInlineSnapshot();',
+ number: 21,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' });',
+ number: 22,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' });',
+ number: 23,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: '});',
+ number: 24,
+ },
+ ]);
+ });
+
+ describe('when the lines contained in callSitesMap are smaller than the number of padded lines', () => {
+ it('returns an array cropped properly', () => {
+ const { snippetLines, allLines } = annotateLines(
+ fileContent,
+ new Map([
+ [2, { line: 2, flat: 0, cum: 40000000 }],
+ [4, { line: 4, flat: 0, cum: 710000000 }],
+ [1, { line: 1, flat: 0, cum: 30000000 }],
+ ])
+ );
+
+ expect(snippetLines).toEqual([
+ {
+ cum: 30000000,
+ flat: 0,
+ line: "import { buildLineProfiles, buildPlaceholderLineProfiles } from '../buildLineProfiles';",
+ number: 1,
+ },
+ {
+ cum: 40000000,
+ flat: 0,
+ line: '',
+ number: 2,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: "describe('buildPlaceholderLineProfiles(callSitesMap)', () => {",
+ number: 3,
+ },
+ {
+ cum: 710000000,
+ flat: 0,
+ line: " describe('if callSitesMap is empty', () => {",
+ number: 4,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: " it('returns an empty array', () => {",
+ number: 5,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' const result = buildPlaceholderLineProfiles(new Map());',
+ number: 6,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' expect(result).toEqual([]);',
+ number: 7,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' });',
+ number: 8,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' });',
+ number: 9,
+ },
+ ]);
+
+ expect(allLines).toEqual([
+ {
+ cum: 30000000,
+ flat: 0,
+ line: "import { buildLineProfiles, buildPlaceholderLineProfiles } from '../buildLineProfiles';",
+ number: 1,
+ },
+ {
+ cum: 40000000,
+ flat: 0,
+ line: '',
+ number: 2,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: "describe('buildPlaceholderLineProfiles(callSitesMap)', () => {",
+ number: 3,
+ },
+ {
+ cum: 710000000,
+ flat: 0,
+ line: " describe('if callSitesMap is empty', () => {",
+ number: 4,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: " it('returns an empty array', () => {",
+ number: 5,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' const result = buildPlaceholderLineProfiles(new Map());',
+ number: 6,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' expect(result).toEqual([]);',
+ number: 7,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' });',
+ number: 8,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' });',
+ number: 9,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: '',
+ number: 10,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: " describe('if callSitesMap is not empty', () => {",
+ number: 11,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: " it('returns an array containing samples/line info, sorted by line number and padded with extra lines', () => {",
+ number: 12,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' const result = buildPlaceholderLineProfiles(',
+ number: 13,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' new Map([',
+ number: 14,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' [12, { line: 12, flat: 0, cum: 40000000 }],',
+ number: 15,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' [15, { line: 15, flat: 0, cum: 710000000 }],',
+ number: 16,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' [11, { line: 11, flat: 0, cum: 30000000 }],',
+ number: 17,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' ])',
+ number: 18,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' );',
+ number: 19,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: '',
+ number: 20,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' expect(result).toMatchInlineSnapshot();',
+ number: 21,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' });',
+ number: 22,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: ' });',
+ number: 23,
+ },
+ {
+ cum: 0,
+ flat: 0,
+ line: '});',
+ number: 24,
+ },
+ ]);
+ });
+ });
+ });
+});
diff --git a/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/__tests__/buildLineProfiles.spec.ts b/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/__tests__/buildLineProfiles.spec.ts
deleted file mode 100644
index 6f14a465..00000000
--- a/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/__tests__/buildLineProfiles.spec.ts
+++ /dev/null
@@ -1,402 +0,0 @@
-import { buildLineProfiles, buildPlaceholderLineProfiles } from '../buildLineProfiles';
-
-describe('buildPlaceholderLineProfiles(callSitesMap)', () => {
- describe('if callSitesMap is empty', () => {
- it('returns an empty array', () => {
- const result = buildPlaceholderLineProfiles(new Map());
- expect(result).toEqual([]);
- });
- });
-
- describe('if callSitesMap is not empty', () => {
- it('returns an array containing samples/line info, sorted by line number and padded with extra lines', () => {
- const result = buildPlaceholderLineProfiles(
- new Map([
- [12, { line: 12, flat: 0, cum: 40000000 }],
- [15, { line: 15, flat: 0, cum: 710000000 }],
- [11, { line: 11, flat: 0, cum: 30000000 }],
- ])
- );
-
- expect(result).toMatchInlineSnapshot(`
- [
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 6,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 7,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 8,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 9,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 10,
- },
- {
- "cum": 30000000,
- "flat": 0,
- "line": undefined,
- "number": 11,
- },
- {
- "cum": 40000000,
- "flat": 0,
- "line": undefined,
- "number": 12,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 13,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 14,
- },
- {
- "cum": 710000000,
- "flat": 0,
- "line": undefined,
- "number": 15,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 16,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 17,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 18,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 19,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 20,
- },
- ]
- `);
- });
-
- describe('when the lines contained in callSitesMap are smaller than the number of padded lines', () => {
- it('returns an array cropped properly', () => {
- const result = buildPlaceholderLineProfiles(
- new Map([
- [2, { line: 2, flat: 0, cum: 40000000 }],
- [4, { line: 4, flat: 0, cum: 710000000 }],
- [1, { line: 1, flat: 0, cum: 30000000 }],
- ])
- );
-
- expect(result).toMatchInlineSnapshot(`
- [
- {
- "cum": 30000000,
- "flat": 0,
- "line": undefined,
- "number": 1,
- },
- {
- "cum": 40000000,
- "flat": 0,
- "line": undefined,
- "number": 2,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 3,
- },
- {
- "cum": 710000000,
- "flat": 0,
- "line": undefined,
- "number": 4,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 5,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 6,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 7,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 8,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": undefined,
- "number": 9,
- },
- ]
- `);
- });
- });
- });
-});
-
-describe('buildLineProfiles(fileContent, callSitesMap', () => {
- describe('if callSitesMap is empty', () => {
- it('returns an empty array', () => {
- const result = buildLineProfiles('// this file is empty', new Map());
- expect(result).toEqual([]);
- });
- });
-
- describe('if callSitesMap is not empty', () => {
- const fileContent = `import { buildLineProfiles, buildPlaceholderLineProfiles } from '../buildLineProfiles';
-
-describe('buildPlaceholderLineProfiles(callSitesMap)', () => {
- describe('if callSitesMap is empty', () => {
- it('returns an empty array', () => {
- const result = buildPlaceholderLineProfiles(new Map());
- expect(result).toEqual([]);
- });
- });
-
- describe('if callSitesMap is not empty', () => {
- it('returns an array containing samples/line info, sorted by line number and padded with extra lines', () => {
- const result = buildPlaceholderLineProfiles(
- new Map([
- [12, { line: 12, flat: 0, cum: 40000000 }],
- [15, { line: 15, flat: 0, cum: 710000000 }],
- [11, { line: 11, flat: 0, cum: 30000000 }],
- ])
- );
-
- expect(result).toMatchInlineSnapshot();
- });
- });
-});`;
-
- it('returns an array containing samples/line info, sorted by line number and padded with extra lines', () => {
- const result = buildLineProfiles(
- fileContent,
- new Map([
- [12, { line: 12, flat: 0, cum: 40000000 }],
- [15, { line: 15, flat: 0, cum: 710000000 }],
- [11, { line: 11, flat: 0, cum: 30000000 }],
- ])
- );
-
- expect(result).toMatchInlineSnapshot(`
- [
- {
- "cum": 0,
- "flat": 0,
- "line": " const result = buildPlaceholderLineProfiles(new Map());",
- "number": 6,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": " expect(result).toEqual([]);",
- "number": 7,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": " });",
- "number": 8,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": " });",
- "number": 9,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": "",
- "number": 10,
- },
- {
- "cum": 30000000,
- "flat": 0,
- "line": " describe('if callSitesMap is not empty', () => {",
- "number": 11,
- },
- {
- "cum": 40000000,
- "flat": 0,
- "line": " it('returns an array containing samples/line info, sorted by line number and padded with extra lines', () => {",
- "number": 12,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": " const result = buildPlaceholderLineProfiles(",
- "number": 13,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": " new Map([",
- "number": 14,
- },
- {
- "cum": 710000000,
- "flat": 0,
- "line": " [12, { line: 12, flat: 0, cum: 40000000 }],",
- "number": 15,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": " [15, { line: 15, flat: 0, cum: 710000000 }],",
- "number": 16,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": " [11, { line: 11, flat: 0, cum: 30000000 }],",
- "number": 17,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": " ])",
- "number": 18,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": " );",
- "number": 19,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": "",
- "number": 20,
- },
- ]
- `);
- });
-
- describe('when the lines contained in callSitesMap are smaller than the number of padded lines', () => {
- it('returns an array cropped properly', () => {
- const result = buildLineProfiles(
- fileContent,
- new Map([
- [2, { line: 2, flat: 0, cum: 40000000 }],
- [4, { line: 4, flat: 0, cum: 710000000 }],
- [1, { line: 1, flat: 0, cum: 30000000 }],
- ])
- );
-
- expect(result).toMatchInlineSnapshot(`
- [
- {
- "cum": 30000000,
- "flat": 0,
- "line": "import { buildLineProfiles, buildPlaceholderLineProfiles } from '../buildLineProfiles';",
- "number": 1,
- },
- {
- "cum": 40000000,
- "flat": 0,
- "line": "",
- "number": 2,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": "describe('buildPlaceholderLineProfiles(callSitesMap)', () => {",
- "number": 3,
- },
- {
- "cum": 710000000,
- "flat": 0,
- "line": " describe('if callSitesMap is empty', () => {",
- "number": 4,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": " it('returns an empty array', () => {",
- "number": 5,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": " const result = buildPlaceholderLineProfiles(new Map());",
- "number": 6,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": " expect(result).toEqual([]);",
- "number": 7,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": " });",
- "number": 8,
- },
- {
- "cum": 0,
- "flat": 0,
- "line": " });",
- "number": 9,
- },
- ]
- `);
- });
- });
- });
-});
diff --git a/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/annotateLines.ts b/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/annotateLines.ts
new file mode 100644
index 00000000..f3d4217f
--- /dev/null
+++ b/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/annotateLines.ts
@@ -0,0 +1,77 @@
+import { CallSiteProps, LineProfile } from '../../../domain/types/FunctionDetails';
+
+const VERTICAL_LINES_PADDING = 5;
+
+type CallSitesMap = Map;
+
+interface AnnotatedLines {
+ snippetLines: LineProfile[];
+ allLines: LineProfile[];
+}
+
+export function annotatePlaceholderLines(callSitesMap: CallSitesMap): AnnotatedLines {
+ if (!callSitesMap.size) {
+ return {
+ snippetLines: [],
+ allLines: [],
+ };
+ }
+
+ const callSites = Array.from(callSitesMap.values()).sort((a, b) => a.line - b.line);
+
+ const firstLineIndex = Math.max(0, callSites[0].line - VERTICAL_LINES_PADDING - 1);
+ const lastLineIndex = callSites[callSites.length - 1].line + VERTICAL_LINES_PADDING + 1;
+
+ const annotatedSnippet = [];
+ for (let lineNumber = firstLineIndex + 1; lineNumber < lastLineIndex; lineNumber++) {
+ const callSite = callSitesMap.get(lineNumber);
+
+ annotatedSnippet.push({
+ line: undefined,
+ number: lineNumber,
+ cum: callSite?.cum ?? 0,
+ flat: callSite?.flat ?? 0,
+ });
+ }
+
+ // With no file contents, we return only a dummy annotated snippet which shows
+ // the appropriate line numbers, but no content.
+ return {
+ snippetLines: annotatedSnippet,
+ allLines: [],
+ };
+}
+
+export function annotateLines(fileContent: string, callSitesMap: CallSitesMap): AnnotatedLines {
+ const callSites = Array.from(callSitesMap.values()).sort((a, b) => a.line - b.line);
+ const lines = fileContent.split('\n');
+
+ const annotatedLines = lines.map((line, index) => {
+ const lineNumber = index + 1;
+ const callSite = callSitesMap.get(lineNumber);
+
+ return {
+ line,
+ number: lineNumber,
+ cum: callSite?.cum ?? 0,
+ flat: callSite?.flat ?? 0,
+ };
+ });
+
+ if (callSitesMap.size === 0) {
+ // If the call site map is empty, there's no snippet to render.
+ return {
+ snippetLines: [],
+ allLines: annotatedLines,
+ };
+ }
+
+ const firstLineIndex = Math.max(0, callSites[0].line - VERTICAL_LINES_PADDING - 1);
+ const lastLineIndex = Math.min(lines.length, callSites[callSites.length - 1].line + VERTICAL_LINES_PADDING);
+ const annotatedSnippet = annotatedLines.slice(firstLineIndex, lastLineIndex);
+
+ return {
+ snippetLines: annotatedSnippet,
+ allLines: annotatedLines,
+ };
+}
diff --git a/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/buildLineProfiles.ts b/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/buildLineProfiles.ts
deleted file mode 100644
index d9ef03bf..00000000
--- a/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/buildLineProfiles.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import { CallSiteProps, LineProfile } from '../../../domain/types/FunctionDetails';
-
-const VERTICAL_LINES_PADDING = 5;
-
-type CallSitesMap = Map;
-
-export function buildPlaceholderLineProfiles(callSitesMap: CallSitesMap) {
- if (!callSitesMap.size) {
- return [];
- }
-
- const callSites = Array.from(callSitesMap.values()).sort((a, b) => a.line - b.line);
-
- const firstLineIndex = Math.max(0, callSites[0].line - VERTICAL_LINES_PADDING - 1);
- const lastLineIndex = callSites[callSites.length - 1].line + VERTICAL_LINES_PADDING + 1;
-
- const lines = [];
-
- for (let lineNumber = firstLineIndex + 1; lineNumber < lastLineIndex; lineNumber++) {
- const callSite = callSitesMap.get(lineNumber);
-
- lines.push({
- line: undefined,
- number: lineNumber,
- cum: callSite?.cum ?? 0,
- flat: callSite?.flat ?? 0,
- });
- }
-
- return lines;
-}
-
-export function buildLineProfiles(fileContent: string, callSitesMap: CallSitesMap): LineProfile[] {
- if (!callSitesMap.size) {
- return [];
- }
-
- const callSites = Array.from(callSitesMap.values()).sort((a, b) => a.line - b.line);
- const allLines = fileContent.split('\n');
-
- const firstLineIndex = Math.max(0, callSites[0].line - VERTICAL_LINES_PADDING - 1);
- const lastLineIndex = Math.min(allLines.length, callSites[callSites.length - 1].line + VERTICAL_LINES_PADDING);
-
- return allLines.slice(firstLineIndex, lastLineIndex).map((line, index) => {
- const lineNumber = index + firstLineIndex + 1;
- const callSite = callSitesMap.get(lineNumber);
-
- return {
- line,
- number: lineNumber,
- cum: callSite?.cum ?? 0,
- flat: callSite?.flat ?? 0,
- };
- });
-}
diff --git a/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/useCodeContainer.ts b/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/useCodeContainer.ts
index ff1bb401..9becf12a 100644
--- a/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/useCodeContainer.ts
+++ b/src/pages/ProfilesExplorerView/components/SceneExploreServiceFlameGraph/components/SceneFunctionDetailsPanel/components/CodeContainer/domain/useCodeContainer.ts
@@ -4,16 +4,17 @@ import { useMemo, useState } from 'react';
import { FunctionDetails, LineProfile } from '../../../domain/types/FunctionDetails';
import { useGitHubContext } from '../../GitHubContextProvider/useGitHubContext';
import { useFetchVCSFile } from '../infrastructure/useFetchVCSFile';
+import { annotateLines, annotatePlaceholderLines } from './annotateLines';
import { buildGithubUrlForFunction } from './buildGithubUrlForFunction';
-import { buildLineProfiles, buildPlaceholderLineProfiles } from './buildLineProfiles';
/**
* View model for Code component
*/
export type CodeLine = LineProfile & { line: string };
-type CodeContainerDomainValue = DomainHookReturnValue & { data: { lines: CodeLine[] } };
+type CodeContainerDomainValue = DomainHookReturnValue & { data: { snippetLines: CodeLine[]; allLines: CodeLine[] } };
+// eslint-disable-next-line sonarjs/cognitive-complexity
export function useCodeContainer(dataSourceUid: string, functionDetails: FunctionDetails): CodeContainerDomainValue {
const { isLoggedIn } = useGitHubContext();
const { version } = functionDetails;
@@ -34,11 +35,11 @@ export function useCodeContainer(dataSourceUid: string, functionDetails: Functio
});
// might be a bit costly so we memoize it
- const lines = useMemo(
+ const { snippetLines, allLines } = useMemo(
() =>
fileInfo?.content
- ? buildLineProfiles(fileInfo.content, functionDetails.callSites)
- : buildPlaceholderLineProfiles(functionDetails.callSites),
+ ? annotateLines(fileInfo.content, functionDetails.callSites)
+ : annotatePlaceholderLines(functionDetails.callSites),
[fileInfo?.content, functionDetails.callSites]
);
@@ -49,8 +50,9 @@ export function useCodeContainer(dataSourceUid: string, functionDetails: Functio
isLoadingCode: isFetching,
unit: functionDetails.unit,
githubUrl: fileInfo?.URL ? buildGithubUrlForFunction(fileInfo.URL, functionDetails.startLine) : undefined,
- lines: lines.map((line) => ({ ...line, line: line.line ?? '???' })),
- noCodeAvailable: Boolean(fetchError) || !lines.some((line) => line.line),
+ snippetLines: snippetLines.map((annotatedLine) => ({ ...annotatedLine, line: annotatedLine.line ?? '???' })),
+ allLines: allLines.map((annotateLine) => ({ ...annotateLine, line: annotateLine.line ?? '???' })),
+ noCodeAvailable: Boolean(fetchError) || !allLines.some((line) => line.line),
},
actions: {
setOpenAiSuggestions,