Skip to content

Commit 41aaf89

Browse files
amitjoshi438Amit Joshi
andauthored
[ServerLogic] Add Server Logic Debugger with CodeLens and Runtime Loader (#1385)
* Add Server Logic debugging: mock SDK, runtime loader, CodeLens, and run/debug commands - Implement local Server Logic debugger with mock Power Pages SDK (src/debugger/server-logic/ServerLogicMockSdk.ts) - Provide debug configuration provider, runtime loader generation, commands for Debug/Run/Generate Mock Data, and welcome notification (ServerLogicDebugger.ts, sample-server-logic.js, README.md, index.ts) - Add CodeLens provider to show inline "Debug" / "Run" actions (ServerLogicCodeLensProvider.ts) and register it on activation - Wire activation into extension (activateServerLogicDebugger in extension.ts) - Add package.json contributions: debug/run commands, snippets, editor/context entries - Add telemetry events for debug/run/mock-template actions - Enable generation of .vscode/mock-data.json and support loading custom mock data * Enhance server logic debugging support: refine CodeLens for standard functions, avoid loader overwrite * Refactor debug configuration to use internal console for server logic debugging * Refactor parameter names in CodeLens and DebugProvider to improve clarity * Remove function level debug * Remove unused command and telemetry for generating mock data template; localize debug/run titles and messages * Update comments in ServerLogicMockSdk for clarity and usage instructions * No code changes made; empty commit. * Remove implementation summary for Power Pages Server Logic Debugging * Remove unused command for debugging server logic in navigation * Refactor ServerLogicCodeLensProvider and ServerLogicDebugger for improved clarity and functionality; add isServerLogicFile method and register CodeLens provider * Enhance Server Logic Debugging: Refactor file checks and debug configuration creation for improved clarity and functionality * Enhance Server Logic Debugging: Add runtime loader file management and ensure global availability of Server API for debugging * Remove outdated README and sample server logic file for server logic debugging * Enhance Server Logic Debugging: Update exports in index.ts and add integration tests for ServerLogicDebugger * Remove UI Enhancement Summary document for Server Logic Debugging * Enhance Server Logic Debugging: Update enablement regex for server logic commands to support both forward and backward slashes * Add constants for Server Logic configuration, files, URLs, and strings * Update Server Logic documentation URL for 'Learn More' link * Enhance server logic debugging telemetry events and improve logging details * Refactor server logic commands and improve debugging support with new command structure * Update code lens provider patterns for server logic files --------- Co-authored-by: Amit Joshi <[email protected]>
1 parent 18b3b50 commit 41aaf89

File tree

10 files changed

+1735
-0
lines changed

10 files changed

+1735
-0
lines changed

package.json

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,20 @@
404404
"category": "Copilot In Power Pages",
405405
"title": "Explain"
406406
},
407+
{
408+
"command": "microsoft.powerplatform.pages.debugServerLogic",
409+
"category": "Power Pages",
410+
"title": "Debug Current Server Logic File",
411+
"icon": "$(debug-alt)",
412+
"enablement": "resourcePath =~ /server-logics?[/\\\\]/ && resourceExtname == .js"
413+
},
414+
{
415+
"command": "microsoft.powerplatform.pages.runServerLogic",
416+
"category": "Power Pages",
417+
"title": "Run Server Logic File",
418+
"icon": "$(run)",
419+
"enablement": "resourcePath =~ /server-logics?[/\\\\]/ && resourceExtname == .js"
420+
},
407421
{
408422
"command": "powerPlatform.previewCurrentActiveUsers",
409423
"title": "Current Active Users",
@@ -832,6 +846,45 @@
832846
}
833847
}
834848
}
849+
},
850+
{
851+
"type": "node",
852+
"label": "Power Pages Server Logic Debugger",
853+
"configurationSnippets": [
854+
{
855+
"label": "Power Pages: Debug Server Logic",
856+
"description": "Debug a Power Pages server logic file with mock SDK support",
857+
"body": {
858+
"type": "node",
859+
"request": "launch",
860+
"name": "Debug Power Pages Server Logic",
861+
"program": "^\"\\${workspaceFolder}/server-logics/\\${1:MyServerLogic.js}\"",
862+
"skipFiles": [
863+
"<node_internals>/**"
864+
],
865+
"console": "integratedTerminal",
866+
"internalConsoleOptions": "neverOpen"
867+
}
868+
},
869+
{
870+
"label": "Power Pages: Debug Server Logic with Custom Mock Data",
871+
"description": "Debug server logic with custom mock data from .vscode/mock-data.json",
872+
"body": {
873+
"type": "node",
874+
"request": "launch",
875+
"name": "Debug Server Logic with Custom Data",
876+
"program": "^\"\\${workspaceFolder}/server-logics/\\${1:MyServerLogic.js}\"",
877+
"env": {
878+
"MOCK_DATA_PATH": "^\"\\${workspaceFolder}/.vscode/mock-data.json\""
879+
},
880+
"skipFiles": [
881+
"<node_internals>/**"
882+
],
883+
"console": "integratedTerminal",
884+
"internalConsoleOptions": "neverOpen"
885+
}
886+
}
887+
]
835888
}
836889
],
837890
"snippets": [

src/client/extension.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ import { PROVIDER_ID } from "../common/services/Constants";
5454
import { activateServerApiAutocomplete } from "../common/intellisense";
5555
import { EnableServerLogicChanges } from "../common/ecs-features/ecsFeatureGates";
5656
import { setServerApiTelemetryContext } from "../common/intellisense/ServerApiTelemetryContext";
57+
import { activateServerLogicDebugger } from "../debugger/server-logic/ServerLogicDebugger";
5758

5859
let client: LanguageClient;
5960
let _context: vscode.ExtensionContext;
@@ -183,6 +184,9 @@ export async function activate(
183184
const basicPanels = RegisterBasicPanels(pacWrapper);
184185
_context.subscriptions.push(...basicPanels);
185186

187+
// Activate Server Logic debugger (always available, doesn't require authentication)
188+
activateServerLogicDebugger(_context);
189+
186190
let copilotNotificationShown = false;
187191

188192
const workspaceFolders = getWorkspaceFolders();
@@ -246,6 +250,7 @@ export async function activate(
246250
activateServerApiAutocomplete(_context, [
247251
{ languageId: 'javascript', triggerCharacters: ['.'] }
248252
]);
253+
249254
serverApiAutocompleteInitialized = true;
250255
}
251256
}

src/common/OneDSLoggerTelemetry/client/desktopExtensionTelemetryEventNames.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,13 @@
55

66
export enum desktopTelemetryEventNames {
77
DESKTOP_EXTENSION_INIT_CONTEXT = "DesktopExtensionInitContext",
8+
9+
// Server Logic Debugger Events
10+
SERVER_LOGIC_DEBUG_STARTED = "ServerLogicDebugStarted",
11+
SERVER_LOGIC_DEBUG_COMMAND_EXECUTED = "ServerLogicDebugCommandExecuted",
12+
SERVER_LOGIC_RUN_COMMAND_EXECUTED = "ServerLogicRunCommandExecuted",
13+
SERVER_LOGIC_DEBUG_ERROR = "ServerLogicDebugError",
14+
SERVER_LOGIC_WELCOME_NOTIFICATION_SHOWN = "ServerLogicWelcomeNotificationShown",
15+
SERVER_LOGIC_WELCOME_NOTIFICATION_ACTION = "ServerLogicWelcomeNotificationAction",
16+
SERVER_LOGIC_RUNTIME_LOADER_CREATED = "ServerLogicRuntimeLoaderCreated",
817
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*/
5+
6+
import * as vscode from 'vscode';
7+
8+
/**
9+
* Command identifiers for Server Logic
10+
*/
11+
export const SERVER_LOGIC_COMMANDS = {
12+
DEBUG: 'microsoft.powerplatform.pages.debugServerLogic',
13+
RUN: 'microsoft.powerplatform.pages.runServerLogic'
14+
} as const;
15+
16+
/**
17+
* Configuration keys for Server Logic settings
18+
*/
19+
export const SERVER_LOGIC_CONFIG_KEYS = {
20+
DONT_SHOW_WELCOME: 'microsoft.powerplatform.pages.serverLogic.dontShowWelcome'
21+
} as const;
22+
23+
/**
24+
* File and folder names used by Server Logic debugger
25+
*/
26+
export const SERVER_LOGIC_FILES = {
27+
RUNTIME_LOADER: 'server-logic-runtime-loader.js',
28+
SERVER_LOGICS_FOLDER: 'server-logics',
29+
VSCODE_FOLDER: '.vscode',
30+
GITIGNORE: '.gitignore'
31+
} as const;
32+
33+
/**
34+
* URLs for Server Logic documentation
35+
*/
36+
export const SERVER_LOGIC_URLS = {
37+
LEARN_MORE: 'https://go.microsoft.com/fwlink/?linkid=2346212'
38+
} as const;
39+
40+
/**
41+
* Regex pattern for matching server-logics or server-logic folder in file paths.
42+
* Supports both plural (server-logics) and singular (server-logic) folder names
43+
* for future compatibility.
44+
*/
45+
export const SERVER_LOGICS_FOLDER_PATTERN = /[/\\]server-logics?[/\\]/;
46+
47+
/**
48+
* Checks if a file is a server logic file based on path and extension
49+
* @param filePath - The file path to check
50+
* @returns True if the file is in a server-logics (or server-logic) folder and has .js extension
51+
*/
52+
export function isServerLogicFile(filePath: string): boolean {
53+
return SERVER_LOGICS_FOLDER_PATTERN.test(filePath) && filePath.endsWith('.js');
54+
}
55+
56+
/**
57+
* User-facing localized strings for Server Logic debugger.
58+
* All strings are wrapped with vscode.l10n.t() for localization support.
59+
*/
60+
export const SERVER_LOGIC_STRINGS = {
61+
DEBUG_CONFIG_NAME: vscode.l10n.t('Debug Power Pages Server Logic'),
62+
DEBUG_CURRENT_CONFIG_NAME: vscode.l10n.t('Debug Current Server Logic'),
63+
RUN_CONFIG_NAME: vscode.l10n.t('Run Server Logic'),
64+
ERROR_OPEN_SERVER_LOGIC_FILE: vscode.l10n.t('Cannot debug: Please open a server logic file (.js) from the server-logics folder.'),
65+
ERROR_REQUIRES_WORKSPACE: vscode.l10n.t('Server Logic debugging requires an open workspace.'),
66+
ERROR_INIT_FAILED: (errorMessage: string) => vscode.l10n.t('Failed to initialize Server Logic debugger: {0}', errorMessage),
67+
ERROR_NO_ACTIVE_EDITOR: vscode.l10n.t('No active editor found.'),
68+
WARNING_OPEN_SERVER_LOGIC_FILE: vscode.l10n.t('Please open a server logic file (.js) from the server-logics folder.'),
69+
WARNING_NO_ACTIVE_EDITOR: vscode.l10n.t('No active editor. Please open a server logic file.'),
70+
WELCOME_MESSAGE: vscode.l10n.t('Power Pages Server Logic detected! You can now debug your server logic files with breakpoints and IntelliSense.'),
71+
BUTTON_DEBUG_CURRENT_FILE: vscode.l10n.t('Debug Current File'),
72+
BUTTON_LEARN_MORE: vscode.l10n.t('Learn More'),
73+
BUTTON_DONT_SHOW_AGAIN: vscode.l10n.t("Don't Show Again"),
74+
CODELENS_DEBUG: vscode.l10n.t('Debug'),
75+
CODELENS_DEBUG_TOOLTIP: vscode.l10n.t('Debug this server logic file'),
76+
CODELENS_RUN: vscode.l10n.t('Run'),
77+
CODELENS_RUN_TOOLTIP: vscode.l10n.t('Run this server logic file without debugging')
78+
} as const;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*/
5+
6+
import * as vscode from 'vscode';
7+
import { isServerLogicFile, SERVER_LOGIC_COMMANDS, SERVER_LOGIC_STRINGS } from './Constants';
8+
9+
/**
10+
* Provides CodeLens for server logic files showing debug/run actions.
11+
* Displays "Debug" and "Run" buttons at the top of .js files in server-logics folders.
12+
*/
13+
export class ServerLogicCodeLensProvider implements vscode.CodeLensProvider, vscode.Disposable {
14+
15+
private readonly _onDidChangeCodeLenses: vscode.EventEmitter<void> = new vscode.EventEmitter<void>();
16+
public readonly onDidChangeCodeLenses: vscode.Event<void> = this._onDidChangeCodeLenses.event;
17+
18+
/**
19+
* Disposes of the CodeLens provider resources
20+
*/
21+
public dispose(): void {
22+
this._onDidChangeCodeLenses.dispose();
23+
}
24+
25+
/**
26+
* Refreshes the CodeLens display by firing the change event
27+
*/
28+
public refresh(): void {
29+
this._onDidChangeCodeLenses.fire();
30+
}
31+
32+
/**
33+
* Provides CodeLens items for server logic documents
34+
* @param document - The text document to provide CodeLens for
35+
* @param _ - Cancellation token (unused)
36+
* @returns Array of CodeLens items or empty array if not a server logic file
37+
*/
38+
public provideCodeLenses(
39+
document: vscode.TextDocument,
40+
_: vscode.CancellationToken
41+
): vscode.CodeLens[] | Thenable<vscode.CodeLens[]> {
42+
43+
// Only provide CodeLens for server logic files
44+
if (!isServerLogicFile(document.fileName)) {
45+
return [];
46+
}
47+
48+
const codeLenses: vscode.CodeLens[] = [];
49+
50+
// Add single CodeLens at the top of the file (line 0)
51+
const range = new vscode.Range(0, 0, 0, 0);
52+
53+
// Add "Debug" CodeLens
54+
const debugLens = new vscode.CodeLens(range, {
55+
title: `$(debug-alt) ${SERVER_LOGIC_STRINGS.CODELENS_DEBUG}`,
56+
tooltip: SERVER_LOGIC_STRINGS.CODELENS_DEBUG_TOOLTIP,
57+
command: SERVER_LOGIC_COMMANDS.DEBUG,
58+
arguments: []
59+
});
60+
codeLenses.push(debugLens);
61+
62+
// Add "Run" CodeLens
63+
const runLens = new vscode.CodeLens(range, {
64+
title: `$(run) ${SERVER_LOGIC_STRINGS.CODELENS_RUN}`,
65+
tooltip: SERVER_LOGIC_STRINGS.CODELENS_RUN_TOOLTIP,
66+
command: SERVER_LOGIC_COMMANDS.RUN,
67+
arguments: []
68+
});
69+
codeLenses.push(runLens);
70+
71+
return codeLenses;
72+
}
73+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*/
5+
6+
import * as vscode from 'vscode';
7+
import * as path from 'path';
8+
import { oneDSLoggerWrapper } from '../../common/OneDSLoggerTelemetry/oneDSLoggerWrapper';
9+
import { desktopTelemetryEventNames } from '../../common/OneDSLoggerTelemetry/client/desktopExtensionTelemetryEventNames';
10+
import {
11+
SERVER_LOGIC_STRINGS,
12+
isServerLogicFile
13+
} from './Constants';
14+
import { createServerLogicDebugConfig, ensureRuntimeLoader } from './ServerLogicDebugger';
15+
16+
/**
17+
* Provided debug configuration template for Server Logic debugging
18+
*/
19+
export const providedServerLogicDebugConfig: vscode.DebugConfiguration = {
20+
type: 'node',
21+
request: 'launch',
22+
name: SERVER_LOGIC_STRINGS.DEBUG_CONFIG_NAME,
23+
program: '${file}',
24+
skipFiles: ['<node_internals>/**'],
25+
console: 'internalConsole'
26+
};
27+
28+
/**
29+
* Debug configuration provider for Power Pages Server Logic
30+
*/
31+
export class ServerLogicDebugProvider implements vscode.DebugConfigurationProvider {
32+
33+
/**
34+
* Provides initial debug configurations
35+
*/
36+
provideDebugConfigurations(
37+
_: vscode.WorkspaceFolder | undefined
38+
): vscode.ProviderResult<vscode.DebugConfiguration[]> {
39+
return [providedServerLogicDebugConfig];
40+
}
41+
42+
/**
43+
* Resolves the debug configuration before starting the debug session
44+
*/
45+
async resolveDebugConfiguration(
46+
folder: vscode.WorkspaceFolder | undefined,
47+
config: vscode.DebugConfiguration,
48+
_: vscode.CancellationToken
49+
): Promise<vscode.DebugConfiguration | undefined> {
50+
51+
if (!config.type && !config.request && !config.name) {
52+
const editor = vscode.window.activeTextEditor;
53+
if (editor && isServerLogicFile(editor.document.uri.fsPath)) {
54+
config = createServerLogicDebugConfig(editor.document.uri.fsPath);
55+
} else {
56+
vscode.window.showErrorMessage(SERVER_LOGIC_STRINGS.ERROR_OPEN_SERVER_LOGIC_FILE);
57+
return undefined;
58+
}
59+
}
60+
61+
if (!folder) {
62+
vscode.window.showErrorMessage(SERVER_LOGIC_STRINGS.ERROR_REQUIRES_WORKSPACE);
63+
return undefined;
64+
}
65+
66+
try {
67+
const loaderPath = await ensureRuntimeLoader(folder);
68+
69+
config.runtimeArgs = config.runtimeArgs || [];
70+
config.runtimeArgs.unshift('--require', loaderPath);
71+
72+
if (config.mockDataPath) {
73+
config.env = config.env || {};
74+
config.env.MOCK_DATA_PATH = config.mockDataPath;
75+
}
76+
77+
oneDSLoggerWrapper.getLogger().traceInfo(
78+
desktopTelemetryEventNames.SERVER_LOGIC_DEBUG_STARTED,
79+
{
80+
hasCustomMockData: String(!!config.mockDataPath),
81+
workspaceFolder: folder.name,
82+
programFile: config.program ? path.basename(config.program) : 'unknown'
83+
}
84+
);
85+
86+
return config;
87+
} catch (error) {
88+
const errorMessage = error instanceof Error ? error.message : String(error);
89+
90+
oneDSLoggerWrapper.getLogger().traceError(
91+
desktopTelemetryEventNames.SERVER_LOGIC_DEBUG_ERROR,
92+
errorMessage,
93+
error instanceof Error ? error : new Error(errorMessage),
94+
{
95+
phase: 'resolveDebugConfiguration',
96+
workspaceFolder: folder.name
97+
}
98+
);
99+
100+
vscode.window.showErrorMessage(SERVER_LOGIC_STRINGS.ERROR_INIT_FAILED(errorMessage));
101+
return undefined;
102+
}
103+
}
104+
}

0 commit comments

Comments
 (0)