Skip to content

Commit e09e2ba

Browse files
authored
[W-21538387] refactor: code cleanup from suggestions in PR #6957 (#7015)
* refactor: remove unnecessary class in htmlUtils.ts * refactor: remove unnecessary class in validatorFactory.ts * refactor: remove incorrect Effect.Effect<void> return type in queryViewDataService.ts * refactor: same removal of Effect.Effect<void> in soqlEditorInstance.ts * refactor: move saveRecordsEffect() out of the QueryDataViewService class * refactor: move getWebViewContent() out too * refactor: inline QUERY_DATA_VIEW_TYPE * refactor: use autoFetchQuery from sfdx-core instead of maxFetch in dataQuery.ts
1 parent e0fd06d commit e09e2ba

11 files changed

Lines changed: 130 additions & 233 deletions

File tree

packages/salesforcedx-vscode-soql/src/commands/dataQuery.ts

Lines changed: 5 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -139,36 +139,6 @@ export const dataQuery = Effect.fn('sf.data.query')(function* () {
139139
yield* Effect.promise(() => commandlet.run());
140140
});
141141

142-
/**
143-
* Retrieves the maximum fetch limit from user configuration.
144-
* Checks SF CLI config first, then environment variable, then returns undefined if no limit is set.
145-
*
146-
* @returns Promise resolving to the configured limit number, or undefined if no limit is set.
147-
*/
148-
const getMaxFetch = async (): Promise<number | undefined> => {
149-
try {
150-
// Priority 1: Check SF CLI config value (org-max-query-limit)
151-
const configAggregator = await getSoqlRuntime().runPromise(
152-
Effect.gen(function* () {
153-
const api = yield* getServicesApi;
154-
return yield* api.services.ConfigService.getConfigAggregator();
155-
})
156-
);
157-
const configValue = configAggregator.getPropertyValue<string>('org-max-query-limit');
158-
if (configValue) {
159-
const parsed = parseInt(configValue, 10);
160-
if (!isNaN(parsed) && parsed > 0) {
161-
return parsed;
162-
}
163-
}
164-
} catch {
165-
// If config reading fails, fall back to no limit
166-
}
167-
168-
// No limit configured - return undefined to allow default amount of queries
169-
return undefined;
170-
};
171-
172142
/** Generates table output from query records */
173143
export const generateTableOutput = (records: QueryResult['records'], title: string): string => {
174144
// Ensure the first record exists and is an object
@@ -366,23 +336,6 @@ export const formatFieldValueForDisplay = (value: unknown): string => {
366336
return stringValue.length > 50 ? `${stringValue.substring(0, 47)}...` : stringValue;
367337
};
368338

369-
/**
370-
* Builds query options for the Salesforce connection query method.
371-
* Supports optional maxFetch limit when user has configured query limits.
372-
*
373-
* @param maxFetch - Optional maximum number of records to fetch. If undefined, no limit is applied.
374-
* @returns Query options object with autoFetch and scanAll settings, plus maxFetch if specified.
375-
*/
376-
export const buildQueryOptions = (maxFetch?: number) => {
377-
const baseOptions = {
378-
autoFetch: true,
379-
scanAll: false
380-
};
381-
382-
// Conditionally add maxFetch if user has configured a limit (including 0)
383-
return maxFetch !== undefined ? { ...baseOptions, maxFetch } : baseOptions;
384-
};
385-
386339
/** Displays query results in table format */
387340
export const displayTableResults = (queryResult: QueryResult): void => {
388341
if (!queryResult.records?.length) {
@@ -458,29 +411,14 @@ export const formatErrorMessage = (error: unknown): string => {
458411
};
459412

460413
/**
461-
* Executes a SOQL query using the provided connection (REST or Tooling API).
462-
* Applies user-configured query limits if set, otherwise allows results under Salesforce limits.
414+
* Executes a SOQL query, auto-fetching all pages of results up to the user-configured
415+
* `org-max-query-limit` (default 10,000). Emits a lifecycle warning if results are truncated.
463416
*
464-
* @param connection - Salesforce connection (REST or Tooling API)
417+
* @param connection - Salesforce connection
465418
* @param query - SOQL query string to execute
466-
* @returns Promise resolving to query results with records and metadata
419+
* @param useTooling - Whether to use the Tooling API instead of REST
467420
*/
468421
const runSoqlQuery = async (connection: Connection, query: string, useTooling = false): Promise<QueryResult> => {
469422
channelService.appendLine(nls.localize('data_query_running_query'));
470-
471-
// Get user-configured query limit (if any)
472-
const maxFetch = await getMaxFetch();
473-
474-
// Execute query with appropriate options (with or without maxFetch limit)
475-
const result = await (useTooling ? connection.tooling : connection).query(query, buildQueryOptions(maxFetch));
476-
477-
// Show warning if user-configured limit caused records to be truncated
478-
if (maxFetch !== undefined && result.records.length > 0 && result.totalSize > result.records.length) {
479-
const missingRecords = result.totalSize - result.records.length;
480-
channelService.appendLine(
481-
nls.localize('data_query_warning_limit', missingRecords, maxFetch, result.totalSize, maxFetch)
482-
);
483-
}
484-
485-
return result;
423+
return connection.autoFetchQuery(query, { tooling: useTooling });
486424
};

packages/salesforcedx-vscode-soql/src/editor/htmlUtils.ts

Lines changed: 38 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -9,72 +9,53 @@ import * as vscode from 'vscode';
99
import { URI, Utils } from 'vscode-uri';
1010

1111
/**
12-
* The index.html file in the dist folder of the @salesforce/soql-builder-ui
13-
* is built by webpack to be displayed in a normal web context. however, vscode
14-
* uses a custom protocol ( vscode-webview-resource instead of http ) to load resources
15-
* so the html needs to be manipulated dynamcially to run inside of vscode.
12+
* Matches webpack-generated script tags like:
13+
* <script defer="defer" src="./0.app.js"></script>
14+
* Captures the filename as group[1].
1615
*/
17-
export class HtmlUtils {
18-
/**
19-
* This regex will match tags in a string like this
20-
* <script defer="defer" src="./0.app.js"></script><script defer="defer" src="./app.js"></script>
21-
* And store just the filename section of the script tag as group[1]
22-
*/
23-
protected static readonly scriptRegex = /script defer="defer"\ssrc="\.\/(?<app>[^"]*app.js)"/g;
16+
const scriptRegex = /script defer="defer"\ssrc="\.\/(?<app>[^"]*app.js)"/g;
2417

25-
/**
26-
*
27-
* @param html
28-
* @param pathToLwcDist
29-
* @param webview
30-
*/
31-
public static transformHtml(html: string, lwcDistUri: URI, webview: vscode.Webview): string {
32-
return HtmlUtils.replaceCspMetaTag(HtmlUtils.transformScriptTags(html, lwcDistUri, webview), webview);
33-
}
18+
/**
19+
* Transforms index.html from @salesforce/soql-builder-ui (built for normal web context)
20+
* to work inside VS Code, which uses vscode-webview-resource instead of http to load resources.
21+
*/
22+
export const transformHtml = (html: string, lwcDistUri: URI, webview: vscode.Webview): string =>
23+
replaceCspMetaTag(transformScriptTags(html, lwcDistUri, webview), webview);
3424

35-
/**
36-
* This section replaces the relative file paths that are produced by
37-
* webpack in the build in the dist folder with the protocol that
38-
* vscode uses internally.
39-
*
40-
* Initial html script tags look like this
41-
* <script defer="defer" src="./0.app.js"></script><script defer="defer" src="./app.js"></script>
42-
*
43-
* Each matched script tag gets transformed into into a vscode specific url
44-
* <script src="vscode-webview-resource:0.app.js"><script src="vscode-webview-resource:app.js">
45-
*
46-
* Since we don't know how many bundles webpack will produce in the dist directory, we regex match and
47-
* replace them in a while loop.
48-
*
49-
* @param html
50-
* @param pathToLwcDist
51-
* @param webview
52-
*/
53-
public static transformScriptTags(html: string, lwcDistUri: URI, webview: vscode.Webview): string {
54-
let matches: string[] | null;
55-
let newScriptSrc: URI;
56-
while ((matches = HtmlUtils.scriptRegex.exec(html)) !== null) {
57-
newScriptSrc = webview.asWebviewUri(Utils.joinPath(lwcDistUri, matches[1]));
58-
// eslint-disable-next-line no-param-reassign
59-
html = html.replace(`./${matches[1]}`, newScriptSrc.toString());
60-
}
61-
return html;
25+
/**
26+
* Replaces relative webpack script paths with vscode-webview-resource URIs.
27+
*
28+
* Initial html script tags look like this
29+
* <script defer="defer" src="./0.app.js"></script><script defer="defer" src="./app.js"></script>
30+
*
31+
* Each matched script tag gets transformed into a vscode specific url
32+
* <script src="vscode-webview-resource:0.app.js"><script src="vscode-webview-resource:app.js">
33+
*
34+
* Since we don't know how many bundles webpack will produce in the dist directory, we regex match and
35+
* replace them in a while loop.
36+
*/
37+
const transformScriptTags = (html: string, lwcDistUri: URI, webview: vscode.Webview): string => {
38+
let matches: string[] | null;
39+
let newScriptSrc: URI;
40+
while ((matches = scriptRegex.exec(html)) !== null) {
41+
newScriptSrc = webview.asWebviewUri(Utils.joinPath(lwcDistUri, matches[1]));
42+
// eslint-disable-next-line no-param-reassign
43+
html = html.replace(`./${matches[1]}`, newScriptSrc.toString());
6244
}
45+
return html;
46+
};
6347

64-
/**
65-
* This method adds stricter CSP for displaying this webview inside of VSCode
66-
* @param html
67-
* @param webview
68-
*/
69-
public static replaceCspMetaTag(html: string, webview: vscode.Webview): string {
70-
const cspMetaTag = `<meta
48+
/**
49+
* Adds stricter CSP for displaying this webview inside of VSCode.
50+
*/
51+
export const replaceCspMetaTag = (html: string, webview: vscode.Webview): string => {
52+
const cspMetaTag = `<meta
7153
http-equiv="Content-Security-Policy"
7254
content="default-src 'self';
7355
img-src ${webview.cspSource};
7456
script-src ${webview.cspSource};
7557
style-src 'unsafe-inline' ${webview.cspSource};"
7658
/>`;
7759

78-
return html.replace('<!-- CSP TAG -->', cspMetaTag);
79-
}
80-
}
60+
return html.replace('<!-- CSP TAG -->', cspMetaTag);
61+
};

packages/salesforcedx-vscode-soql/src/editor/soqlEditorInstance.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export class SOQLEditorInstance {
135135
protected sendMessageToUi(
136136
type: MessageType,
137137
payload?: string | string[] | DescribeSObjectResult
138-
): Effect.Effect<void> {
138+
) {
139139
return Effect.promise<boolean>(
140140
() => this.webviewPanel.webview.postMessage({ type, payload })
141141
).pipe(
@@ -149,7 +149,7 @@ export class SOQLEditorInstance {
149149
);
150150
}
151151

152-
protected updateWebview(document: vscode.TextDocument): Effect.Effect<void> {
152+
protected updateWebview(document: vscode.TextDocument) {
153153
const self = this;
154154
return Effect.gen(function* () {
155155
if (self.pendingWebviewUpdate) {
@@ -160,11 +160,11 @@ export class SOQLEditorInstance {
160160
});
161161
}
162162

163-
protected updateSObjects(sobjectNames: string[]): Effect.Effect<void> {
163+
protected updateSObjects(sobjectNames: string[]) {
164164
return this.sendMessageToUi('sobjects_response', sobjectNames);
165165
}
166166

167-
protected updateSObjectMetadata(sobject: DescribeSObjectResult): Effect.Effect<void> {
167+
protected updateSObjectMetadata(sobject: DescribeSObjectResult) {
168168
return this.sendMessageToUi('sobject_metadata_response', sobject);
169169
}
170170

@@ -266,7 +266,7 @@ export class SOQLEditorInstance {
266266
}
267267
};
268268

269-
protected runQueryDone(): Effect.Effect<void> {
269+
protected runQueryDone() {
270270
return Effect.promise<boolean>(() =>
271271
this.webviewPanel.webview.postMessage({ type: 'run_query_done' satisfies MessageType })
272272
).pipe(Effect.asVoid);
@@ -294,5 +294,5 @@ export class SOQLEditorInstance {
294294
this.disposedCallback = callback;
295295
}
296296

297-
public onConnectionChanged = (): Effect.Effect<void> => this.sendMessageToUi('connection_changed');
297+
public onConnectionChanged = () => this.sendMessageToUi('connection_changed');
298298
}

packages/salesforcedx-vscode-soql/src/editor/soqlEditorProvider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { nls } from '../messages';
1414
import { channelService } from '../services/channel';
1515
import { getSoqlRuntime } from '../services/extensionProvider';
1616
import { isDefaultOrgSet } from '../services/org';
17-
import { HtmlUtils } from './htmlUtils';
17+
import { transformHtml } from './htmlUtils';
1818
import { SOQLEditorInstance } from './soqlEditorInstance';
1919

2020
export class SOQLEditorProvider implements vscode.CustomTextEditorProvider {
@@ -60,7 +60,7 @@ export class SOQLEditorProvider implements vscode.CustomTextEditorProvider {
6060
return yield* api.services.FsService.readFile(Utils.joinPath(soqlBuilderUri, HTML_FILE));
6161
})
6262
);
63-
return HtmlUtils.transformHtml(htmlContent, soqlBuilderUri, webview);
63+
return transformHtml(htmlContent, soqlBuilderUri, webview);
6464
}
6565

6666
private disposeInstance(instance: SOQLEditorInstance) {

packages/salesforcedx-vscode-soql/src/queryDataView/queryDataHtml.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import * as Effect from 'effect/Effect';
1010
import * as vscode from 'vscode';
1111
import { Utils } from 'vscode-uri';
1212
import { DATA_VIEW_PATH, HTML_FILE } from '../constants';
13-
import { HtmlUtils } from '../editor/htmlUtils';
13+
import { replaceCspMetaTag } from '../editor/htmlUtils';
1414
import { getSoqlRuntime } from '../services/extensionProvider';
1515

1616
export const getHtml = async (
@@ -31,7 +31,7 @@ export const getHtml = async (
3131
We need to replace the hrefs with webviewUris,
3232
this will need to change once we need a standalone data view.
3333
*/
34-
html = HtmlUtils.replaceCspMetaTag(html, webview);
34+
html = replaceCspMetaTag(html, webview);
3535
html = html.replace('${tabulatorStyleUri}', tabulatorStyleUri.toString());
3636
html = html.replace('${baseStyleUri}', baseStyleUri.toString());
3737
html = html.replace('${tabulatorUri}', tabulatorUri.toString());

0 commit comments

Comments
 (0)