From 99f3361487ad95e779fff15fd10cb682769c2b2f Mon Sep 17 00:00:00 2001 From: I743583 Date: Tue, 10 Sep 2024 11:56:19 +0100 Subject: [PATCH 01/14] remove fs node module --- .../src/launch-config-crud/create.ts | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/packages/launch-config/src/launch-config-crud/create.ts b/packages/launch-config/src/launch-config-crud/create.ts index 626da87ef3..c752c55a6a 100644 --- a/packages/launch-config/src/launch-config-crud/create.ts +++ b/packages/launch-config/src/launch-config-crud/create.ts @@ -14,7 +14,6 @@ import { getFioriToolsDirectory } from '@sap-ux/store'; import type { Logger } from '@sap-ux/logger'; import { DatasourceType } from '@sap-ux/odata-service-inquirer'; import { t } from '../i18n'; -import fs from 'fs'; /** * Enhance or create the launch.json file with new launch config. @@ -57,16 +56,17 @@ export async function createLaunchConfig(rootFolder: string, fioriOptions: Fiori * Adds the specified path to the latestGeneratedFiles array. * * @param {string} path - The project file path to add. + * @param fs - The memfs editor instance. * @param log - The logger instance. */ -export function writeApplicationInfoSettings(path: string, log?: Logger): void { +export function writeApplicationInfoSettings(path: string, fs: Editor, log?: Logger): void { const appInfoFilePath: string = getFioriToolsDirectory(); - const appInfoContents = fs.existsSync(appInfoFilePath) - ? JSON.parse(fs.readFileSync(appInfoFilePath, 'utf-8')) + const appInfoContents = fs.exists(appInfoFilePath) + ? JSON.parse(fs.read(appInfoFilePath)) : { latestGeneratedFiles: [] }; appInfoContents.latestGeneratedFiles.push(path); try { - fs.writeFileSync(appInfoFilePath, JSON.stringify(appInfoContents, null, 2)); + fs.write(appInfoFilePath, JSON.stringify(appInfoContents, null, 2)); } catch (error) { log?.error(t('errorAppInfoFile', { error: error })); } @@ -77,16 +77,18 @@ export function writeApplicationInfoSettings(path: string, log?: Logger): void { * * @param {UpdateWorkspaceFolderOptions} updateWorkspaceFolders - The options for updating workspace folders. * @param {string} rootFolderPath - The root folder path of the project. + * @param fs - The memfs editor instance. * @param log - The logger instance. */ export function updateWorkspaceFoldersIfNeeded( updateWorkspaceFolders: UpdateWorkspaceFolderOptions | undefined, rootFolderPath: string, + fs: Editor, log?: Logger ): void { if (updateWorkspaceFolders) { const { uri, vscode, projectName } = updateWorkspaceFolders; - writeApplicationInfoSettings(rootFolderPath, log); + //writeApplicationInfoSettings(rootFolderPath, fs, log); if (uri && vscode) { const currentWorkspaceFolders = vscode.workspace.workspaceFolders || []; @@ -105,6 +107,7 @@ export function updateWorkspaceFoldersIfNeeded( * @param {LaunchJSON} launchJsonFile - The launch.json configuration to write. * @param {UpdateWorkspaceFolderOptions} [updateWorkspaceFolders] - Optional workspace folder update options. * @param {boolean} appNotInWorkspace - Indicates if the app is not in the workspace. + * @param fs - The memfs editor instance. * @param log - The logger instance. */ export function createOrUpdateLaunchConfigJSON( @@ -112,38 +115,42 @@ export function createOrUpdateLaunchConfigJSON( launchJsonFile?: LaunchJSON, updateWorkspaceFolders?: UpdateWorkspaceFolderOptions, appNotInWorkspace: boolean = false, + fs?: Editor, log?: Logger ): void { + if (!fs) { + fs = create(createStorage()); + } try { const launchJSONPath = join(rootFolderPath, DirName.VSCode, LAUNCH_JSON_FILE); - if (fs.existsSync(launchJSONPath) && !appNotInWorkspace) { - const existingLaunchConfig = parse(fs.readFileSync(launchJSONPath, 'utf-8')) as LaunchJSON; + if (fs.exists(launchJSONPath) && !appNotInWorkspace) { + const existingLaunchConfig = parse(fs.read(launchJSONPath)) as LaunchJSON; const updatedConfigurations = existingLaunchConfig.configurations.concat( launchJsonFile?.configurations ?? [] ); - fs.writeFileSync( + fs.write( launchJSONPath, JSON.stringify({ ...existingLaunchConfig, configurations: updatedConfigurations }, null, 4) ); } else { const dotVscodePath = join(rootFolderPath, DirName.VSCode); - fs.mkdirSync(dotVscodePath, { recursive: true }); const path = join(dotVscodePath, 'launch.json'); - fs.writeFileSync(path, JSON.stringify(launchJsonFile ?? {}, null, 4), 'utf8'); + fs.write(path, JSON.stringify(launchJsonFile ?? {}, null, 4)); } } catch (error) { log?.error(t('errorLaunchFile', { error: error })); } - updateWorkspaceFoldersIfNeeded(updateWorkspaceFolders, rootFolderPath, log); + updateWorkspaceFoldersIfNeeded(updateWorkspaceFolders, rootFolderPath, fs, log); } /** * Generates and creates launch configuration for the project based on debug options. * * @param {DebugOptions} options - The options for configuring the debug setup. + * @param fs - The memfs editor instance. * @param log - The logger instance. */ -export function configureLaunchConfig(options: DebugOptions, log?: Logger): void { +export function configureLaunchConfig(options: DebugOptions, fs?: Editor, log?: Logger): void { const { datasourceType, projectPath, vscode } = options; if (datasourceType === DatasourceType.capProject) { log?.info(t('startApp', { npmStart: '`npm start`', cdsRun: '`cds run --in-memory`' })); @@ -164,7 +171,7 @@ export function configureLaunchConfig(options: DebugOptions, log?: Logger): void } : undefined; - createOrUpdateLaunchConfigJSON(launchJsonPath, launchJsonFile, updateWorkspaceFolders, appNotInWorkspace, log); + createOrUpdateLaunchConfigJSON(launchJsonPath, launchJsonFile, updateWorkspaceFolders, appNotInWorkspace, fs, log); const npmCommand = datasourceType === DatasourceType.metadataFile ? 'run start-mock' : 'start'; const projectName = basename(projectPath); From d23cda9a5ea06a149d043344b1d1fe6a68a084a0 Mon Sep 17 00:00:00 2001 From: I743583 Date: Tue, 10 Sep 2024 17:39:27 +0100 Subject: [PATCH 02/14] removing write application info logic --- packages/launch-config/package.json | 1 - .../src/launch-config-crud/create.ts | 38 +------ .../configureLaunchConfig.test.ts | 104 +++++------------- 3 files changed, 32 insertions(+), 111 deletions(-) diff --git a/packages/launch-config/package.json b/packages/launch-config/package.json index 9a7a96a3d6..9c3839134e 100644 --- a/packages/launch-config/package.json +++ b/packages/launch-config/package.json @@ -35,7 +35,6 @@ "@sap-ux/ui5-config": "workspace:*", "@sap-ux/ui5-info": "workspace:*", "@sap-ux/odata-service-inquirer": "workspace:*", - "@sap-ux/store": "workspace:*", "i18next": "23.5.1", "jsonc-parser": "3.2.0", "mem-fs": "2.1.0", diff --git a/packages/launch-config/src/launch-config-crud/create.ts b/packages/launch-config/src/launch-config-crud/create.ts index c752c55a6a..cc56ee4c54 100644 --- a/packages/launch-config/src/launch-config-crud/create.ts +++ b/packages/launch-config/src/launch-config-crud/create.ts @@ -10,7 +10,6 @@ import { updateLaunchJSON } from './writer'; import { parse } from 'jsonc-parser'; import { handleWorkspaceConfig } from '../debug-config/workspaceManager'; import { configureLaunchJsonFile } from '../debug-config/config'; -import { getFioriToolsDirectory } from '@sap-ux/store'; import type { Logger } from '@sap-ux/logger'; import { DatasourceType } from '@sap-ux/odata-service-inquirer'; import { t } from '../i18n'; @@ -51,45 +50,16 @@ export async function createLaunchConfig(rootFolder: string, fioriOptions: Fiori return fs; } -/** - * Writes the application info settings to the appInfo.json file. - * Adds the specified path to the latestGeneratedFiles array. - * - * @param {string} path - The project file path to add. - * @param fs - The memfs editor instance. - * @param log - The logger instance. - */ -export function writeApplicationInfoSettings(path: string, fs: Editor, log?: Logger): void { - const appInfoFilePath: string = getFioriToolsDirectory(); - const appInfoContents = fs.exists(appInfoFilePath) - ? JSON.parse(fs.read(appInfoFilePath)) - : { latestGeneratedFiles: [] }; - appInfoContents.latestGeneratedFiles.push(path); - try { - fs.write(appInfoFilePath, JSON.stringify(appInfoContents, null, 2)); - } catch (error) { - log?.error(t('errorAppInfoFile', { error: error })); - } -} - /** * Updates the workspace folders in VSCode if the update options are provided. * * @param {UpdateWorkspaceFolderOptions} updateWorkspaceFolders - The options for updating workspace folders. - * @param {string} rootFolderPath - The root folder path of the project. - * @param fs - The memfs editor instance. - * @param log - The logger instance. */ export function updateWorkspaceFoldersIfNeeded( - updateWorkspaceFolders: UpdateWorkspaceFolderOptions | undefined, - rootFolderPath: string, - fs: Editor, - log?: Logger + updateWorkspaceFolders: UpdateWorkspaceFolderOptions | undefined ): void { if (updateWorkspaceFolders) { const { uri, vscode, projectName } = updateWorkspaceFolders; - //writeApplicationInfoSettings(rootFolderPath, fs, log); - if (uri && vscode) { const currentWorkspaceFolders = vscode.workspace.workspaceFolders || []; vscode.workspace.updateWorkspaceFolders(currentWorkspaceFolders.length, undefined, { @@ -140,7 +110,7 @@ export function createOrUpdateLaunchConfigJSON( } catch (error) { log?.error(t('errorLaunchFile', { error: error })); } - updateWorkspaceFoldersIfNeeded(updateWorkspaceFolders, rootFolderPath, fs, log); + updateWorkspaceFoldersIfNeeded(updateWorkspaceFolders); } /** @@ -149,8 +119,9 @@ export function createOrUpdateLaunchConfigJSON( * @param {DebugOptions} options - The options for configuring the debug setup. * @param fs - The memfs editor instance. * @param log - The logger instance. + * @returns {string | undefined} The path to the launch.json file. Returns undefined if the datasource type is CAP project or no vscode is available. */ -export function configureLaunchConfig(options: DebugOptions, fs?: Editor, log?: Logger): void { +export function configureLaunchConfig(options: DebugOptions, fs?: Editor, log?: Logger): string | undefined { const { datasourceType, projectPath, vscode } = options; if (datasourceType === DatasourceType.capProject) { log?.info(t('startApp', { npmStart: '`npm start`', cdsRun: '`cds run --in-memory`' })); @@ -181,4 +152,5 @@ export function configureLaunchConfig(options: DebugOptions, fs?: Editor, log?: npmCommand }) ); + return launchJsonPath; } diff --git a/packages/launch-config/test/debug-config/configureLaunchConfig.test.ts b/packages/launch-config/test/debug-config/configureLaunchConfig.test.ts index 0a4f12249a..16bf98c1dd 100644 --- a/packages/launch-config/test/debug-config/configureLaunchConfig.test.ts +++ b/packages/launch-config/test/debug-config/configureLaunchConfig.test.ts @@ -3,7 +3,6 @@ import { handleWorkspaceConfig } from '../../src/debug-config/workspaceManager'; import type { DebugOptions, UpdateWorkspaceFolderOptions, LaunchJSON } from '../../src/types'; import { LAUNCH_JSON_FILE } from '../../src/types'; import { - writeApplicationInfoSettings, updateWorkspaceFoldersIfNeeded, createOrUpdateLaunchConfigJSON, configureLaunchConfig @@ -12,14 +11,9 @@ import { t } from '../../src/i18n'; import { DatasourceType } from '@sap-ux/odata-service-inquirer'; import type { Editor } from 'mem-fs-editor'; import { DirName } from '@sap-ux/project-access'; -import { getFioriToolsDirectory } from '@sap-ux/store'; import type { Logger } from '@sap-ux/logger'; -import { existsSync, mkdir } from 'fs'; -import fs from 'fs'; // Mock dependencies -jest.mock('mem-fs'); -jest.mock('mem-fs-editor'); jest.mock('jsonc-parser', () => ({ parse: jest.fn().mockReturnValue({ configurations: [{ name: 'Existing Config', type: 'node' }] @@ -32,6 +26,7 @@ jest.mock('../../src/debug-config/config', () => ({ configureLaunchJsonFile: jest.fn(), writeApplicationInfoSettings: jest.requireActual('../../src/debug-config/config').writeApplicationInfoSettings })); + const mockLog = { error: jest.fn(), info: jest.fn() @@ -42,39 +37,6 @@ const mockEditor = { read: jest.fn(), write: jest.fn() } as unknown as Editor; -const mockPath = '/mock/project/path'; -// Define a variable to control the behavior of writeFileSync -let writeFileSyncMockBehavior: 'success' | 'error'; - -jest.mock('fs', () => ({ - ...jest.requireActual('fs'), - //mkdirSync: jest.fn(), - existsSync: jest.fn().mockReturnValue(true), - readFileSync: jest.fn((path: string, encoding: string) => { - // Mock different behaviors based on the path - if (path) { - return JSON.stringify({ latestGeneratedFiles: [] }); // Mock file content - } - throw new Error('Simulated read error'); - }), - writeFileSync: jest.fn().mockImplementation(() => { - if (writeFileSyncMockBehavior === 'error') { - throw new Error('Simulated write error'); // Throw an error for `writeFileSync` when behavior is 'error' - } - // Otherwise, assume it succeeds - }) -})); - -// Function to set the behavior for writeFileSync -const setWriteFileSyncBehavior = (behavior: 'success' | 'error') => { - writeFileSyncMockBehavior = behavior; - // Reinitialize the mock to apply the new behavior - fs.writeFileSync = jest.fn().mockImplementation(() => { - if (writeFileSyncMockBehavior === 'error') { - throw new Error(); - } - }); -}; describe('Config Functions', () => { const launchJson = { @@ -89,22 +51,6 @@ describe('Config Functions', () => { jest.clearAllMocks(); }); - describe('writeApplicationInfoSettings', () => { - it('should write application info settings to appInfo.json', () => { - writeApplicationInfoSettings(mockPath, mockLog); - expect(fs.writeFileSync).toHaveBeenCalledWith( - getFioriToolsDirectory(), - JSON.stringify({ latestGeneratedFiles: [mockPath] }, null, 2) - ); - }); - - it('should handle error while writing to appInfo.json', () => { - setWriteFileSyncBehavior('error'); - writeApplicationInfoSettings(mockPath, mockLog); - expect(mockLog.error).toHaveBeenCalledWith(t('errorAppInfoFile')); - }); - }); - describe('updateWorkspaceFoldersIfNeeded', () => { it('should update workspace folders if options are provided', () => { const updateOptions = { @@ -117,7 +63,7 @@ describe('Config Functions', () => { }, projectName: 'Test Project' } as UpdateWorkspaceFolderOptions; - updateWorkspaceFoldersIfNeeded(updateOptions, '/root/folder/path', mockLog); + updateWorkspaceFoldersIfNeeded(updateOptions); expect(updateOptions.vscode.workspace.updateWorkspaceFolders).toHaveBeenCalledWith(0, undefined, { name: 'Test Project', uri: '/mock/uri' @@ -126,9 +72,9 @@ describe('Config Functions', () => { it('should not update workspace folders if no options are provided', () => { const updateOptions: UpdateWorkspaceFolderOptions | undefined = undefined; - updateWorkspaceFoldersIfNeeded(updateOptions, '/root/folder/path', mockLog); + updateWorkspaceFoldersIfNeeded(updateOptions); // No updateWorkspaceFolders call expected hence no app info json written - expect(fs.writeFileSync).not.toHaveBeenCalled(); + expect(mockEditor.write).not.toHaveBeenCalled(); }); }); @@ -136,23 +82,22 @@ describe('Config Functions', () => { it('should create a new launch.json file if it does not exist', () => { const rootFolderPath = '/root/folder'; const appNotInWorkspace = false; - fs.mkdirSync = jest.fn().mockReturnValue(rootFolderPath); - fs.existsSync = jest.fn().mockReturnValue(false); - createOrUpdateLaunchConfigJSON(rootFolderPath, launchJson, undefined, appNotInWorkspace, mockLog); - expect(fs.writeFileSync).toHaveBeenCalledWith( + //fs.mkdirSync = jest.fn().mockReturnValue(rootFolderPath); + mockEditor.exists = jest.fn().mockReturnValue(false); + createOrUpdateLaunchConfigJSON(rootFolderPath, launchJson, undefined, appNotInWorkspace, mockEditor, mockLog); + expect(mockEditor.write).toHaveBeenCalledWith( join(rootFolderPath, DirName.VSCode, LAUNCH_JSON_FILE), - JSON.stringify(launchJson, null, 4), - 'utf8' + JSON.stringify(launchJson, null, 4) ); }); it('should update an existing launch.json file', () => { const rootFolderPath = '/root/folder'; const appNotInWorkspace = false; - fs.existsSync = jest.fn().mockReturnValue(true); - createOrUpdateLaunchConfigJSON(rootFolderPath, launchJson, undefined, appNotInWorkspace, mockLog); + mockEditor.exists = jest.fn().mockReturnValue(true); + createOrUpdateLaunchConfigJSON(rootFolderPath, launchJson, undefined, appNotInWorkspace, mockEditor, mockLog); - expect(fs.writeFileSync).toHaveBeenCalledWith( + expect(mockEditor.write).toHaveBeenCalledWith( join(rootFolderPath, DirName.VSCode, LAUNCH_JSON_FILE), JSON.stringify( { @@ -167,20 +112,25 @@ describe('Config Functions', () => { it('should not update an existing launch.json file when app not in workspace', () => { const rootFolderPath = '/root/folder'; const appNotInWorkspace = true; - fs.existsSync = jest.fn().mockReturnValue(true); - createOrUpdateLaunchConfigJSON(rootFolderPath, launchJson, undefined, appNotInWorkspace, mockLog); - expect(fs.writeFileSync).toHaveBeenCalledWith( + mockEditor.exists = jest.fn().mockReturnValue(true); + createOrUpdateLaunchConfigJSON(rootFolderPath, launchJson, undefined, appNotInWorkspace, mockEditor, mockLog); + expect(mockEditor.write).toHaveBeenCalledWith( join(rootFolderPath, DirName.VSCode, LAUNCH_JSON_FILE), - JSON.stringify(launchJson, null, 4), - 'utf8' + JSON.stringify(launchJson, null, 4) ); }); it('should handle errors while writing launch.json file', () => { const rootFolderPath = '/root/folder'; const appNotInWorkspace = false; - setWriteFileSyncBehavior('error'); - createOrUpdateLaunchConfigJSON(rootFolderPath, launchJson, undefined, appNotInWorkspace, mockLog); + const mockEditorWithError = { + exists: jest.fn().mockReturnValue(false), + read: jest.fn(), + write: jest.fn().mockImplementation(() => { + throw new Error(); + }) + } as unknown as Editor; + createOrUpdateLaunchConfigJSON(rootFolderPath, launchJson, undefined, appNotInWorkspace, mockEditorWithError, mockLog); expect(mockLog.error).toHaveBeenCalledWith(t('errorLaunchFile')); }); }); @@ -211,7 +161,7 @@ describe('Config Functions', () => { }); // Call the function under test - configureLaunchConfig(mockOptions, mockLog); + configureLaunchConfig(mockOptions, mockEditor, mockLog); // Expectations to ensure that workspace folders are updated correctly expect(mockOptions.vscode.workspace.updateWorkspaceFolders).toHaveBeenCalledWith(0, undefined, { @@ -225,7 +175,7 @@ describe('Config Functions', () => { datasourceType: DatasourceType.capProject, projectPath: 'some/path' } as DebugOptions; - configureLaunchConfig(options, mockLog); + configureLaunchConfig(options, mockEditor, mockLog); expect(mockLog.info).toHaveBeenCalledWith( t('startApp', { npmStart: '`npm start`', cdsRun: '`cds run --in-memory`' }) ); @@ -237,7 +187,7 @@ describe('Config Functions', () => { projectPath: 'some/path', vscode: false } as DebugOptions; - configureLaunchConfig(options, mockLog); + configureLaunchConfig(options, mockEditor, mockLog); expect(mockLog.info).not.toHaveBeenCalled(); }); }); From 73a20fe1c72576f44ce356d48a9e300747c80a74 Mon Sep 17 00:00:00 2001 From: I743583 Date: Tue, 10 Sep 2024 18:13:52 +0100 Subject: [PATCH 03/14] return file editor --- .../src/launch-config-crud/create.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/launch-config/src/launch-config-crud/create.ts b/packages/launch-config/src/launch-config-crud/create.ts index cc56ee4c54..770eef3420 100644 --- a/packages/launch-config/src/launch-config-crud/create.ts +++ b/packages/launch-config/src/launch-config-crud/create.ts @@ -75,22 +75,19 @@ export function updateWorkspaceFoldersIfNeeded( * * @param {string} rootFolderPath - The root folder path of the project. * @param {LaunchJSON} launchJsonFile - The launch.json configuration to write. + * @param fs - The memfs editor instance. * @param {UpdateWorkspaceFolderOptions} [updateWorkspaceFolders] - Optional workspace folder update options. * @param {boolean} appNotInWorkspace - Indicates if the app is not in the workspace. - * @param fs - The memfs editor instance. * @param log - The logger instance. */ export function createOrUpdateLaunchConfigJSON( rootFolderPath: string, - launchJsonFile?: LaunchJSON, + launchJsonFile: LaunchJSON, + fs: Editor, updateWorkspaceFolders?: UpdateWorkspaceFolderOptions, appNotInWorkspace: boolean = false, - fs?: Editor, log?: Logger ): void { - if (!fs) { - fs = create(createStorage()); - } try { const launchJSONPath = join(rootFolderPath, DirName.VSCode, LAUNCH_JSON_FILE); if (fs.exists(launchJSONPath) && !appNotInWorkspace) { @@ -119,9 +116,9 @@ export function createOrUpdateLaunchConfigJSON( * @param {DebugOptions} options - The options for configuring the debug setup. * @param fs - The memfs editor instance. * @param log - The logger instance. - * @returns {string | undefined} The path to the launch.json file. Returns undefined if the datasource type is CAP project or no vscode is available. + * @returns {Editor | undefined} memfs editor instance. Returns undefined if the datasource type is CAP project or no vscode is available. */ -export function configureLaunchConfig(options: DebugOptions, fs?: Editor, log?: Logger): string | undefined { +export function configureLaunchConfig(options: DebugOptions, fs?: Editor, log?: Logger): Editor | undefined { const { datasourceType, projectPath, vscode } = options; if (datasourceType === DatasourceType.capProject) { log?.info(t('startApp', { npmStart: '`npm start`', cdsRun: '`cds run --in-memory`' })); @@ -141,8 +138,11 @@ export function configureLaunchConfig(options: DebugOptions, fs?: Editor, log?: vscode } : undefined; - - createOrUpdateLaunchConfigJSON(launchJsonPath, launchJsonFile, updateWorkspaceFolders, appNotInWorkspace, fs, log); + + if (!fs) { + fs = create(createStorage()); + } + createOrUpdateLaunchConfigJSON(launchJsonPath, launchJsonFile, fs, updateWorkspaceFolders, appNotInWorkspace, log); const npmCommand = datasourceType === DatasourceType.metadataFile ? 'run start-mock' : 'start'; const projectName = basename(projectPath); @@ -152,5 +152,5 @@ export function configureLaunchConfig(options: DebugOptions, fs?: Editor, log?: npmCommand }) ); - return launchJsonPath; + return fs; } From 7190795186f2cccbacb78c84cd0b0f8421dc2935 Mon Sep 17 00:00:00 2001 From: I743583 Date: Tue, 10 Sep 2024 18:21:05 +0100 Subject: [PATCH 04/14] fix launch config tests --- .../src/launch-config-crud/create.ts | 6 +-- .../configureLaunchConfig.test.ts | 37 ++++++++++++++++--- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/packages/launch-config/src/launch-config-crud/create.ts b/packages/launch-config/src/launch-config-crud/create.ts index 770eef3420..dfdb5827d7 100644 --- a/packages/launch-config/src/launch-config-crud/create.ts +++ b/packages/launch-config/src/launch-config-crud/create.ts @@ -55,9 +55,7 @@ export async function createLaunchConfig(rootFolder: string, fioriOptions: Fiori * * @param {UpdateWorkspaceFolderOptions} updateWorkspaceFolders - The options for updating workspace folders. */ -export function updateWorkspaceFoldersIfNeeded( - updateWorkspaceFolders: UpdateWorkspaceFolderOptions | undefined -): void { +export function updateWorkspaceFoldersIfNeeded(updateWorkspaceFolders: UpdateWorkspaceFolderOptions | undefined): void { if (updateWorkspaceFolders) { const { uri, vscode, projectName } = updateWorkspaceFolders; if (uri && vscode) { @@ -138,7 +136,7 @@ export function configureLaunchConfig(options: DebugOptions, fs?: Editor, log?: vscode } : undefined; - + if (!fs) { fs = create(createStorage()); } diff --git a/packages/launch-config/test/debug-config/configureLaunchConfig.test.ts b/packages/launch-config/test/debug-config/configureLaunchConfig.test.ts index 16bf98c1dd..988ac51a35 100644 --- a/packages/launch-config/test/debug-config/configureLaunchConfig.test.ts +++ b/packages/launch-config/test/debug-config/configureLaunchConfig.test.ts @@ -82,9 +82,15 @@ describe('Config Functions', () => { it('should create a new launch.json file if it does not exist', () => { const rootFolderPath = '/root/folder'; const appNotInWorkspace = false; - //fs.mkdirSync = jest.fn().mockReturnValue(rootFolderPath); mockEditor.exists = jest.fn().mockReturnValue(false); - createOrUpdateLaunchConfigJSON(rootFolderPath, launchJson, undefined, appNotInWorkspace, mockEditor, mockLog); + createOrUpdateLaunchConfigJSON( + rootFolderPath, + launchJson, + mockEditor, + undefined, + appNotInWorkspace, + mockLog + ); expect(mockEditor.write).toHaveBeenCalledWith( join(rootFolderPath, DirName.VSCode, LAUNCH_JSON_FILE), JSON.stringify(launchJson, null, 4) @@ -95,7 +101,14 @@ describe('Config Functions', () => { const rootFolderPath = '/root/folder'; const appNotInWorkspace = false; mockEditor.exists = jest.fn().mockReturnValue(true); - createOrUpdateLaunchConfigJSON(rootFolderPath, launchJson, undefined, appNotInWorkspace, mockEditor, mockLog); + createOrUpdateLaunchConfigJSON( + rootFolderPath, + launchJson, + mockEditor, + undefined, + appNotInWorkspace, + mockLog + ); expect(mockEditor.write).toHaveBeenCalledWith( join(rootFolderPath, DirName.VSCode, LAUNCH_JSON_FILE), @@ -113,7 +126,14 @@ describe('Config Functions', () => { const rootFolderPath = '/root/folder'; const appNotInWorkspace = true; mockEditor.exists = jest.fn().mockReturnValue(true); - createOrUpdateLaunchConfigJSON(rootFolderPath, launchJson, undefined, appNotInWorkspace, mockEditor, mockLog); + createOrUpdateLaunchConfigJSON( + rootFolderPath, + launchJson, + mockEditor, + undefined, + appNotInWorkspace, + mockLog + ); expect(mockEditor.write).toHaveBeenCalledWith( join(rootFolderPath, DirName.VSCode, LAUNCH_JSON_FILE), JSON.stringify(launchJson, null, 4) @@ -130,7 +150,14 @@ describe('Config Functions', () => { throw new Error(); }) } as unknown as Editor; - createOrUpdateLaunchConfigJSON(rootFolderPath, launchJson, undefined, appNotInWorkspace, mockEditorWithError, mockLog); + createOrUpdateLaunchConfigJSON( + rootFolderPath, + launchJson, + mockEditorWithError, + undefined, + appNotInWorkspace, + mockLog + ); expect(mockLog.error).toHaveBeenCalledWith(t('errorLaunchFile')); }); }); From 057d3f46b432703b37c6d807b6cab0f47d8b40c4 Mon Sep 17 00:00:00 2001 From: I743583 Date: Wed, 11 Sep 2024 08:35:08 +0100 Subject: [PATCH 05/14] pnpm recursive install --- packages/launch-config/tsconfig.json | 3 --- pnpm-lock.yaml | 3 --- 2 files changed, 6 deletions(-) diff --git a/packages/launch-config/tsconfig.json b/packages/launch-config/tsconfig.json index d03f1afd91..4effa8f7dd 100644 --- a/packages/launch-config/tsconfig.json +++ b/packages/launch-config/tsconfig.json @@ -19,9 +19,6 @@ { "path": "../project-access" }, - { - "path": "../store" - }, { "path": "../ui5-config" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2bedd5464a..73194af42e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1643,9 +1643,6 @@ importers: '@sap-ux/project-access': specifier: workspace:* version: link:../project-access - '@sap-ux/store': - specifier: workspace:* - version: link:../store '@sap-ux/ui5-config': specifier: workspace:* version: link:../ui5-config From 79871c05abcdcba722ba453a9c3cd6bf277ab836 Mon Sep 17 00:00:00 2001 From: I743583 Date: Wed, 11 Sep 2024 10:37:25 +0100 Subject: [PATCH 06/14] add changeset --- .changeset/tidy-papayas-film.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/tidy-papayas-film.md diff --git a/.changeset/tidy-papayas-film.md b/.changeset/tidy-papayas-film.md new file mode 100644 index 0000000000..5ece385196 --- /dev/null +++ b/.changeset/tidy-papayas-film.md @@ -0,0 +1,5 @@ +--- +'@sap-ux/launch-config': minor +--- + +Reverted the use of Node.js `fs` modules and replaced them with `mem-fs` for writing launch config files & Removed `writeApplicationInfoSettings()` from `@sap-ux/launch-config` From 38ce5ed1a0a7fbacc49545754ce1ba213dfe5051 Mon Sep 17 00:00:00 2001 From: I743583 Date: Thu, 12 Sep 2024 11:17:41 +0100 Subject: [PATCH 07/14] remove exports of ftns from workspace manager to test --- .../src/debug-config/workspaceManager.ts | 6 +- .../debug-config/workspaceManager.test.ts | 117 ++++++++---------- 2 files changed, 58 insertions(+), 65 deletions(-) diff --git a/packages/launch-config/src/debug-config/workspaceManager.ts b/packages/launch-config/src/debug-config/workspaceManager.ts index 6dd8d0b17a..7c223a5f24 100644 --- a/packages/launch-config/src/debug-config/workspaceManager.ts +++ b/packages/launch-config/src/debug-config/workspaceManager.ts @@ -10,7 +10,7 @@ import { formatCwd, getLaunchJsonPath, isFolderInWorkspace, handleAppsNotInWorks * @param {any} vscode - The VS Code API object. * @returns {WorkspaceHandlerInfo} An object containing the path to the `launch.json` configuration file and the cwd for the launch configuration. */ -export function handleUnsavedWorkspace(projectPath: string, vscode: any): WorkspaceHandlerInfo { +function handleUnsavedWorkspace(projectPath: string, vscode: any): WorkspaceHandlerInfo { const workspace = vscode.workspace; const wsFolder = workspace.getWorkspaceFolder(vscode.Uri.file(projectPath))?.uri?.fsPath; const nestedFolder = relative(wsFolder ?? projectPath, projectPath); @@ -31,7 +31,7 @@ export function handleUnsavedWorkspace(projectPath: string, vscode: any): Worksp * @param {any} vscode - The VS Code API object. * @returns {WorkspaceHandlerInfo} An object containing the path to the `launch.json` configuration file and the cwd for the launch configuration. */ -export function handleSavedWorkspace( +function handleSavedWorkspace( projectPath: string, projectName: string, targetFolder: string, @@ -58,7 +58,7 @@ export function handleSavedWorkspace( * @param {any} vscode - The VS Code API object. * @returns {WorkspaceHandlerInfo} An object containing the path to the `launch.json` configuration file and the cwd for the launch configuration. */ -export function handleOpenFolderButNoWorkspaceFile( +function handleOpenFolderButNoWorkspaceFile( projectPath: string, targetFolder: string, isAppStudio: boolean, diff --git a/packages/launch-config/test/debug-config/workspaceManager.test.ts b/packages/launch-config/test/debug-config/workspaceManager.test.ts index 03888f0df0..7a81106844 100644 --- a/packages/launch-config/test/debug-config/workspaceManager.test.ts +++ b/packages/launch-config/test/debug-config/workspaceManager.test.ts @@ -1,9 +1,4 @@ -import { - handleWorkspaceConfig, - handleUnsavedWorkspace, - handleSavedWorkspace, - handleOpenFolderButNoWorkspaceFile -} from '../../src/debug-config/workspaceManager'; +import { handleWorkspaceConfig } from '../../src/debug-config/workspaceManager'; import { formatCwd, getLaunchJsonPath, @@ -44,18 +39,47 @@ describe('launchConfig Unit Tests', () => { jest.clearAllMocks(); }); - describe('handleUnsavedWorkspace', () => { - it('should update paths for nested folders inside a workspace', () => { + describe('handleOpenFolderButNoWorkspaceFile', () => { + it('should create a launch config for non-workspace apps if folder is not in workspace', () => { + const mockProjectPath = '/mock/project/path'; + (isFolderInWorkspace as jest.Mock).mockReturnValue(false); + (handleAppsNotInWorkspace as jest.Mock).mockReturnValue({ + launchJsonPath: mockProjectPath, + cwd: '${workspaceFolder}' + }); + + const options = { + projectPath: mockProjectPath, + isAppStudio, + vscode: mockVscode + } as DebugOptions; + + const result = handleWorkspaceConfig(options); + expect(result).toEqual({ + launchJsonPath: mockProjectPath, + cwd: '${workspaceFolder}' + }); + }); + + it('should update paths for nested folders inside an open folder', () => { const mockProjectPath = '/mock/project/nestedFolder'; - const mockWsFolder = '/mock/workspace/folder'; + const mockTargetFolder = '/target/folder'; const mockNestedFolder = 'nestedFolder'; - mockVscode.workspace.getWorkspaceFolder.mockReturnValue({ uri: { fsPath: mockWsFolder } }); + + (isFolderInWorkspace as jest.Mock).mockReturnValue(true); (path.relative as jest.Mock).mockReturnValue(mockNestedFolder); (formatCwd as jest.Mock).mockReturnValue('${workspaceFolder}/nestedFolder'); + (getLaunchJsonPath as jest.Mock).mockReturnValue(mockTargetFolder); - const result = handleUnsavedWorkspace(mockProjectPath, mockVscode); + const options = { + projectPath: mockProjectPath, + isAppStudio, + vscode: mockVscode + } as DebugOptions; + + const result = handleWorkspaceConfig(options); expect(result).toEqual({ - launchJsonPath: mockWsFolder, + launchJsonPath: mockTargetFolder, cwd: '${workspaceFolder}/nestedFolder' }); }); @@ -64,19 +88,17 @@ describe('launchConfig Unit Tests', () => { describe('handleSavedWorkspace', () => { it('should handle projects inside the workspace', () => { const mockProjectPath = '/mock/project/path'; - const mockProjectName = 'project'; const mockTargetFolder = '/target/folder'; (isFolderInWorkspace as jest.Mock).mockReturnValue(true); (formatCwd as jest.Mock).mockReturnValue('${workspaceFolder}/project'); (getLaunchJsonPath as jest.Mock).mockReturnValue(mockTargetFolder); - const result = handleSavedWorkspace( - mockProjectPath, - mockProjectName, - mockTargetFolder, + const options = { + projectPath: mockProjectPath, isAppStudio, - mockVscode - ); + vscode: mockVscode + } as DebugOptions; + const result = handleWorkspaceConfig(options); expect(result).toEqual({ launchJsonPath: mockTargetFolder, cwd: '${workspaceFolder}/project' @@ -85,21 +107,18 @@ describe('launchConfig Unit Tests', () => { it('should create a launch config for non-workspace apps', () => { const mockProjectPath = '/mock/project/path'; - const mockProjectName = 'project'; - const mockTargetFolder = '/target/folder'; (isFolderInWorkspace as jest.Mock).mockReturnValue(false); (handleAppsNotInWorkspace as jest.Mock).mockReturnValue({ launchJsonPath: mockProjectPath, cwd: '${workspaceFolder}' }); - const result = handleSavedWorkspace( - mockProjectPath, - mockProjectName, - mockTargetFolder, + const options = { + projectPath: mockProjectPath, isAppStudio, - mockVscode - ); + vscode: mockVscode + } as DebugOptions; + const result = handleWorkspaceConfig(options); expect(result).toEqual({ launchJsonPath: mockProjectPath, cwd: '${workspaceFolder}' @@ -107,48 +126,22 @@ describe('launchConfig Unit Tests', () => { }); }); - describe('handleOpenFolderButNoWorkspaceFile', () => { - it('should create a launch config for non-workspace apps if folder is not in workspace', () => { - const mockProjectPath = '/mock/project/path'; - const mockTargetFolder = '/target/folder'; - (isFolderInWorkspace as jest.Mock).mockReturnValue(false); - (handleAppsNotInWorkspace as jest.Mock).mockReturnValue({ - launchJsonPath: mockProjectPath, - cwd: '${workspaceFolder}' - }); - - const result = handleOpenFolderButNoWorkspaceFile( - mockProjectPath, - mockTargetFolder, - isAppStudio, - mockVscode - ); - expect(result).toEqual({ - launchJsonPath: mockProjectPath, - cwd: '${workspaceFolder}' - }); - }); - - it('should update paths for nested folders inside an open folder', () => { + describe('handleUnsavedWorkspace', () => { + it('should update paths for nested folders inside a workspace', () => { const mockProjectPath = '/mock/project/nestedFolder'; - const mockTargetFolder = '/target/folder'; const mockWsFolder = '/mock/workspace/folder'; const mockNestedFolder = 'nestedFolder'; - - (isFolderInWorkspace as jest.Mock).mockReturnValue(true); mockVscode.workspace.getWorkspaceFolder.mockReturnValue({ uri: { fsPath: mockWsFolder } }); + mockVscode.workspace.workspaceFile.scheme = 'folder'; (path.relative as jest.Mock).mockReturnValue(mockNestedFolder); (formatCwd as jest.Mock).mockReturnValue('${workspaceFolder}/nestedFolder'); - (getLaunchJsonPath as jest.Mock).mockReturnValue(mockTargetFolder); - - const result = handleOpenFolderButNoWorkspaceFile( - mockProjectPath, - mockTargetFolder, - isAppStudio, - mockVscode - ); + const options = { + projectPath: mockProjectPath, + vscode: mockVscode + } as DebugOptions; + const result = handleWorkspaceConfig(options); expect(result).toEqual({ - launchJsonPath: mockTargetFolder, + launchJsonPath: mockWsFolder, cwd: '${workspaceFolder}/nestedFolder' }); }); From 837698f9913749970272a5c2bd5b637f789c5290 Mon Sep 17 00:00:00 2001 From: I743583 Date: Fri, 13 Sep 2024 10:06:57 +0100 Subject: [PATCH 08/14] refactor createLaunchConfig --- packages/launch-config/src/index.ts | 2 +- .../src/launch-config-crud/create.ts | 232 +++++++++++------- packages/launch-config/src/types/types.ts | 1 + .../test/launch-config-crud/create.test.ts | 6 +- .../test/launch-config-crud/update.test.ts | 2 +- 5 files changed, 151 insertions(+), 92 deletions(-) diff --git a/packages/launch-config/src/index.ts b/packages/launch-config/src/index.ts index d38fecfed7..fae4f11272 100644 --- a/packages/launch-config/src/index.ts +++ b/packages/launch-config/src/index.ts @@ -1,5 +1,5 @@ export * from './types'; -export { createLaunchConfig, configureLaunchConfig } from './launch-config-crud/create'; +export { createLaunchConfig } from './launch-config-crud/create'; export { deleteLaunchConfig } from './launch-config-crud/delete'; export { convertOldLaunchConfigToFioriRun } from './launch-config-crud/modify'; export { getLaunchConfigs, getLaunchConfigByName } from './launch-config-crud/read'; diff --git a/packages/launch-config/src/launch-config-crud/create.ts b/packages/launch-config/src/launch-config-crud/create.ts index dfdb5827d7..a5a3e45876 100644 --- a/packages/launch-config/src/launch-config-crud/create.ts +++ b/packages/launch-config/src/launch-config-crud/create.ts @@ -3,7 +3,7 @@ import { create } from 'mem-fs-editor'; import { join, basename } from 'path'; import { DirName } from '@sap-ux/project-access'; import { LAUNCH_JSON_FILE } from '../types'; -import type { FioriOptions, LaunchJSON, UpdateWorkspaceFolderOptions, DebugOptions } from '../types'; +import type { FioriOptions, LaunchJSON, UpdateWorkspaceFolderOptions, DebugOptions, LaunchConfig } from '../types'; import type { Editor } from 'mem-fs-editor'; import { generateNewFioriLaunchConfig } from './utils'; import { updateLaunchJSON } from './writer'; @@ -15,41 +15,105 @@ import { DatasourceType } from '@sap-ux/odata-service-inquirer'; import { t } from '../i18n'; /** - * Enhance or create the launch.json file with new launch config. + * Writes the `launch.json` file with the specified configurations. If the file already exists, it will be overwritten. * - * @param rootFolder - workspace root folder. - * @param fioriOptions - options for the new launch config. - * @param fs - optional, the memfs editor instance. - * @returns memfs editor instance. + * @param {Editor} fs - The file system editor used to write the `launch.json` file. + * @param {string} launchJSONPath - The full path to the `launch.json` file. + * @param {LaunchConfig[]} configurations - An array of launch configurations to be included in the `launch.json` file. + * @returns {Promise} - A promise that resolves once the `launch.json` file has been written. */ -export async function createLaunchConfig(rootFolder: string, fioriOptions: FioriOptions, fs?: Editor): Promise { - if (!fs) { - fs = create(createStorage()); - } - const launchJSONPath = join(rootFolder, DirName.VSCode, LAUNCH_JSON_FILE); - if (fs.exists(launchJSONPath)) { +async function writeLaunchJsonFile(fs: Editor, launchJSONPath: string, configurations: LaunchConfig[]): Promise { + const newLaunchJSONContent = { version: '0.2.0', configurations }; + fs.write(launchJSONPath, JSON.stringify(newLaunchJSONContent, null, 4)); +} + +/** + * Constructs the full path to the `launch.json` file based on the provided root folder. + * + * @param {string} rootFolder - The root directory where the `.vscode` folder is located. + * @returns {string} - The full path to the `launch.json` file. + */ +function getLaunchJsonPath(rootFolder: string): string { + return join(rootFolder, DirName.VSCode, LAUNCH_JSON_FILE); +} + +/** + * Handles the case where there are no debug options provided. It either enhances an existing `launch.json` + * file with a new launch configuration or creates a new `launch.json` file with the initial configuration. + * + * @param {string} rootFolder - The root directory where the `launch.json` file is located or will be created. + * @param {FioriOptions} fioriOptions - The options used to generate the new launch configuration for the `launch.json` file. + * @param {Editor} fs - The file system editor used to read and write the `launch.json` file. + * @returns {Promise} - A promise that resolves with the file system editor after the `launch.json` file has been + * updated or created. + */ +async function handleNoDebugOptions(rootFolder: string, fioriOptions: FioriOptions, fs: Editor): Promise { + const launchJsonWritePath = getLaunchJsonPath(rootFolder); + if (fs.exists(launchJsonWritePath)) { // launch.json exists, enhance existing file with new config const launchConfig = generateNewFioriLaunchConfig(rootFolder, fioriOptions); - const launchJsonString = fs.read(launchJSONPath); + const launchJsonString = fs.read(launchJsonWritePath); const launchJson = parse(launchJsonString) as LaunchJSON; await updateLaunchJSON( launchConfig, - launchJSONPath, + launchJsonWritePath, ['configurations', launchJson.configurations.length + 1], { isArrayInsertion: true }, fs ); - } else { - // launch.json is missing, new file with new config - const configurations = generateNewFioriLaunchConfig(rootFolder, fioriOptions); - const newLaunchJSONContent = { version: '0.2.0', configurations: [configurations] }; - fs.write(launchJSONPath, JSON.stringify(newLaunchJSONContent, null, 4)); + return fs; } + // launch.json is missing, new file with new config + const configurations = [generateNewFioriLaunchConfig(rootFolder, fioriOptions)]; + await writeLaunchJsonFile(fs, launchJsonWritePath, configurations); return fs; } +/** + * Updates or replaces the `launch.json` file depending on whether the file should be replaced + * or enhanced with additional configurations. If `replaceWithNew` is true, the entire file + * content is replaced with the new configurations. Otherwise, the configurations are added + * to the existing `launch.json`. + * + * @param {Editor} fs - The file system editor to read and write the `launch.json` file. + * @param {string} launchJSONPath - The path to the existing `launch.json` file. + * @param {LaunchConfig[]} configurations - An array of new launch configurations to be added or replaced. + * @param {boolean | undefined} replaceWithNew - A flag indicating whether to replace the existing `launch.json` + * with new configurations (`true`) or append to the existing ones (`false`). + * @returns {Promise} - A promise that resolves once the `launch.json` file has been updated or replaced. + */ +async function handleExistingLaunchJson( + fs: Editor, + launchJSONPath: string, + configurations: LaunchConfig[], + replaceWithNew: boolean | undefined +): Promise { + const launchJsonString = fs.read(launchJSONPath); + const launchJson = parse(launchJsonString) as LaunchJSON; + + if (replaceWithNew) { + // replaceWithNew is needed in cases where launch config exists in + // `.vscode` but isn't added to the workspace. If `replaceWithNew` is `true`, it indicates that the app is not + // in the workspace, so the entire `launch.json` and replaced since launch config is then generated in app folder. + const newLaunchJSONContent = { version: '0.2.0', configurations }; + fs.write(launchJSONPath, JSON.stringify(newLaunchJSONContent, null, 4)); + } else { + for (const config of configurations) { + await updateLaunchJSON( + config, + launchJSONPath, + ['configurations', launchJson.configurations.length + 1], + { + isArrayInsertion: true + }, + fs + ); + } + } +} + /** * Updates the workspace folders in VSCode if the update options are provided. * @@ -69,86 +133,80 @@ export function updateWorkspaceFoldersIfNeeded(updateWorkspaceFolders: UpdateWor } /** - * Creates or updates the launch.json file with the provided configurations. + * Handles the creation and configuration of the `launch.json` file based on debug options. + * This function processes workspace configuration, updates the `launch.json` file if it exists, + * and creates it if it does not. Additionally, it updates workspace folders if applicable. * - * @param {string} rootFolderPath - The root folder path of the project. - * @param {LaunchJSON} launchJsonFile - The launch.json configuration to write. - * @param fs - The memfs editor instance. - * @param {UpdateWorkspaceFolderOptions} [updateWorkspaceFolders] - Optional workspace folder update options. - * @param {boolean} appNotInWorkspace - Indicates if the app is not in the workspace. - * @param log - The logger instance. + * @param {Editor} fs - The file system editor to read and write the `launch.json` file. + * @param {DebugOptions} debugOptions - Debug configuration options that dictate how the `launch.json` + * should be generated and what commands should be logged. + * @param {Logger} log - Logger instance for logging information or warnings. + * @returns {Promise} - Returns the file system editor after potentially modifying the workspace + * and updating or creating the `launch.json` file. */ -export function createOrUpdateLaunchConfigJSON( - rootFolderPath: string, - launchJsonFile: LaunchJSON, - fs: Editor, - updateWorkspaceFolders?: UpdateWorkspaceFolderOptions, - appNotInWorkspace: boolean = false, - log?: Logger -): void { - try { - const launchJSONPath = join(rootFolderPath, DirName.VSCode, LAUNCH_JSON_FILE); - if (fs.exists(launchJSONPath) && !appNotInWorkspace) { - const existingLaunchConfig = parse(fs.read(launchJSONPath)) as LaunchJSON; - const updatedConfigurations = existingLaunchConfig.configurations.concat( - launchJsonFile?.configurations ?? [] - ); - fs.write( - launchJSONPath, - JSON.stringify({ ...existingLaunchConfig, configurations: updatedConfigurations }, null, 4) - ); - } else { - const dotVscodePath = join(rootFolderPath, DirName.VSCode); - const path = join(dotVscodePath, 'launch.json'); - fs.write(path, JSON.stringify(launchJsonFile ?? {}, null, 4)); - } - } catch (error) { - log?.error(t('errorLaunchFile', { error: error })); +async function handleDebugOptions(fs: Editor, debugOptions: DebugOptions, log?: Logger): Promise { + const { launchJsonPath, workspaceFolderUri, cwd, appNotInWorkspace } = handleWorkspaceConfig(debugOptions); + const configurations = configureLaunchJsonFile(cwd, debugOptions).configurations; + + const npmCommand = debugOptions.datasourceType === DatasourceType.metadataFile ? 'run start-mock' : 'start'; + log?.info( + t('startServerMessage', { + folder: basename(debugOptions.projectPath), + npmCommand + }) + ); + const launchJsonWritePath = getLaunchJsonPath(launchJsonPath); + if (fs.exists(launchJsonPath)) { + await handleExistingLaunchJson(fs, launchJsonWritePath, configurations, appNotInWorkspace); + } else { + await writeLaunchJsonFile(fs, launchJsonWritePath, configurations); } + + // The `workspaceFolderUri` is a URI obtained from VS Code that specifies the path to the workspace folder. + // This URI is populated when a reload of the workspace is required. It allows us to identify and update + // the workspace folder correctly within VS Code. + const updateWorkspaceFolders = workspaceFolderUri + ? ({ + uri: workspaceFolderUri, + projectName: basename(debugOptions.projectPath), + vscode: debugOptions.vscode + } as UpdateWorkspaceFolderOptions) + : undefined; + updateWorkspaceFoldersIfNeeded(updateWorkspaceFolders); + return fs; } /** - * Generates and creates launch configuration for the project based on debug options. + * Enhance or create the launch.json file with new launch config. * - * @param {DebugOptions} options - The options for configuring the debug setup. - * @param fs - The memfs editor instance. - * @param log - The logger instance. - * @returns {Editor | undefined} memfs editor instance. Returns undefined if the datasource type is CAP project or no vscode is available. + * @param rootFolder - workspace root folder. + * @param fioriOptions - options for the new launch config. + * @param fs - optional, the memfs editor instance. + * @param log + * @returns memfs editor instance. */ -export function configureLaunchConfig(options: DebugOptions, fs?: Editor, log?: Logger): Editor | undefined { - const { datasourceType, projectPath, vscode } = options; - if (datasourceType === DatasourceType.capProject) { - log?.info(t('startApp', { npmStart: '`npm start`', cdsRun: '`cds run --in-memory`' })); - return; +export async function createLaunchConfig( + rootFolder: string, + fioriOptions: FioriOptions, + fs?: Editor, + log?: Logger +): Promise { + fs = fs ?? create(createStorage()); + + const debugOptions = fioriOptions.debugOptions; + + if (!debugOptions) { + return await handleNoDebugOptions(rootFolder, fioriOptions, fs); } - if (!vscode) { + + if (debugOptions.datasourceType === DatasourceType.capProject) { + log?.info(t('startApp', { npmStart: '`npm start`', cdsRun: '`cds run --in-memory`' })); return; } - const { launchJsonPath, workspaceFolderUri, cwd, appNotInWorkspace } = handleWorkspaceConfig(options); - // construct launch.json file - const launchJsonFile = configureLaunchJsonFile(cwd, options); - // update workspace folders if workspaceFolderUri is available - const updateWorkspaceFolders = workspaceFolderUri - ? { - uri: workspaceFolderUri, - projectName: basename(options.projectPath), - vscode - } - : undefined; - if (!fs) { - fs = create(createStorage()); + if (!debugOptions.vscode) { + return; } - createOrUpdateLaunchConfigJSON(launchJsonPath, launchJsonFile, fs, updateWorkspaceFolders, appNotInWorkspace, log); - - const npmCommand = datasourceType === DatasourceType.metadataFile ? 'run start-mock' : 'start'; - const projectName = basename(projectPath); - log?.info( - t('startServerMessage', { - folder: projectName, - npmCommand - }) - ); - return fs; + return await handleDebugOptions(fs, debugOptions, log); } diff --git a/packages/launch-config/src/types/types.ts b/packages/launch-config/src/types/types.ts index 8cf24216be..d48abdedb4 100644 --- a/packages/launch-config/src/types/types.ts +++ b/packages/launch-config/src/types/types.ts @@ -21,6 +21,7 @@ export interface FioriOptions { backendConfigs?: FioriToolsProxyConfigBackend[]; urlParameters?: string; visible?: boolean; + debugOptions?: DebugOptions; } export interface LaunchJSON { diff --git a/packages/launch-config/test/launch-config-crud/create.test.ts b/packages/launch-config/test/launch-config-crud/create.test.ts index e6c9b19e78..55957a7813 100644 --- a/packages/launch-config/test/launch-config-crud/create.test.ts +++ b/packages/launch-config/test/launch-config-crud/create.test.ts @@ -19,7 +19,7 @@ describe('create', () => { }); test('launch.json file is missing, create new file with new config', async () => { - const result = await createLaunchConfig( + const result: any = await createLaunchConfig( TestPaths.tmpDir, { name: 'LaunchConfig_One', projectRoot: join(TestPaths.tmpDir, 'fe-projects') }, memFs @@ -64,7 +64,7 @@ describe('create', () => { const ui5VersionUri = 'DUMMY_UI5_URI'; // Select destination const backendConfigs = [{ path: 'TEST_PATH', name: 'TEST_DESTINAME', url: 'dummy' }]; - const result = await createLaunchConfig( + const result: any = await createLaunchConfig( TestPaths.tmpDir, { name: 'LaunchConfig_One', @@ -117,7 +117,7 @@ describe('create', () => { } ] }); - const result = await createLaunchConfig( + const result: any = await createLaunchConfig( TestPaths.tmpDir, { name: 'LaunchConfig_Two', projectRoot: join(TestPaths.tmpDir, 'fe-projects') }, memFs diff --git a/packages/launch-config/test/launch-config-crud/update.test.ts b/packages/launch-config/test/launch-config-crud/update.test.ts index 53a0ec8cd3..8eb1ab12da 100644 --- a/packages/launch-config/test/launch-config-crud/update.test.ts +++ b/packages/launch-config/test/launch-config-crud/update.test.ts @@ -34,7 +34,7 @@ describe('update', () => { test('Create and then update existing launch config in launch.json', async (): Promise => { // create a new const launchJSONPath = join(TestPaths.feProjectsLaunchConfig); - let result = await createLaunchConfig( + let result: any = await createLaunchConfig( TestPaths.feProjects, { name: 'LaunchConfig_One', From 59d974d3b8058653de4e297d7429e54c5499d7ed Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 13 Sep 2024 09:12:33 +0000 Subject: [PATCH 09/14] Linting auto fix commit --- packages/launch-config/src/launch-config-crud/create.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/launch-config/src/launch-config-crud/create.ts b/packages/launch-config/src/launch-config-crud/create.ts index a5a3e45876..0e45118ab9 100644 --- a/packages/launch-config/src/launch-config-crud/create.ts +++ b/packages/launch-config/src/launch-config-crud/create.ts @@ -96,7 +96,7 @@ async function handleExistingLaunchJson( if (replaceWithNew) { // replaceWithNew is needed in cases where launch config exists in // `.vscode` but isn't added to the workspace. If `replaceWithNew` is `true`, it indicates that the app is not - // in the workspace, so the entire `launch.json` and replaced since launch config is then generated in app folder. + // in the workspace, so the entire `launch.json` and replaced since launch config is then generated in app folder. const newLaunchJSONContent = { version: '0.2.0', configurations }; fs.write(launchJSONPath, JSON.stringify(newLaunchJSONContent, null, 4)); } else { From d402236d28b0634c4af34fe6c3f2bf0291ecfcab Mon Sep 17 00:00:00 2001 From: I743583 Date: Fri, 13 Sep 2024 16:45:22 +0100 Subject: [PATCH 10/14] reuse createLaunchConfig --- .../launch-config/src/debug-config/config.ts | 9 +- .../src/debug-config/workspaceManager.ts | 19 +- .../src/launch-config-crud/create.ts | 54 ++-- packages/launch-config/src/types/types.ts | 2 - .../test/debug-config/config.test.ts | 16 +- .../configureLaunchConfig.test.ts | 221 ------------- .../debug-config/workspaceManager.test.ts | 30 +- .../test/launch-config-crud/create.test.ts | 305 +++++++++++++++++- 8 files changed, 362 insertions(+), 294 deletions(-) delete mode 100644 packages/launch-config/test/debug-config/configureLaunchConfig.test.ts diff --git a/packages/launch-config/src/debug-config/config.ts b/packages/launch-config/src/debug-config/config.ts index f130269fb6..6a772b5fd9 100644 --- a/packages/launch-config/src/debug-config/config.ts +++ b/packages/launch-config/src/debug-config/config.ts @@ -56,13 +56,13 @@ function createLaunchConfig( /** * Configures the launch.json file based on provided options. * + * @param rootFolder * @param {string} cwd - The current working directory. * @param {DebugOptions} configOpts - Configuration options for the launch.json file. * @returns {LaunchJSON} The configured launch.json object. */ -export function configureLaunchJsonFile(cwd: string, configOpts: DebugOptions): LaunchJSON { +export function configureLaunchJsonFile(rootFolder: string, cwd: string, configOpts: DebugOptions): LaunchJSON { const { - projectPath, isAppStudio, datasourceType, flpAppId, @@ -73,14 +73,13 @@ export function configureLaunchJsonFile(cwd: string, configOpts: DebugOptions): isFioriElement, migratorMockIntent } = configOpts; - - const projectName = basename(projectPath); + const projectName = basename(rootFolder); const flpAppIdWithHash = flpAppId && !flpAppId.startsWith('#') ? `#${flpAppId}` : flpAppId; const startHtmlFile = flpSandboxAvailable ? testFlpSandboxHtml : indexHtml; const runConfig = isAppStudio ? JSON.stringify({ handlerId: FIORI_TOOLS_LAUNCH_CONFIG_HANDLER_ID, - runnableId: projectPath + runnableId: rootFolder }) : undefined; const envUrlParam = getEnvUrlParams(sapClientParam); diff --git a/packages/launch-config/src/debug-config/workspaceManager.ts b/packages/launch-config/src/debug-config/workspaceManager.ts index 7c223a5f24..4c28c771b1 100644 --- a/packages/launch-config/src/debug-config/workspaceManager.ts +++ b/packages/launch-config/src/debug-config/workspaceManager.ts @@ -83,6 +83,7 @@ function handleOpenFolderButNoWorkspaceFile( * This function handles different scenarios depending on whether a workspace is open, * whether the project is inside or outside of a workspace, and other factors. * + * @param rootFolder * @param {DebugOptions} options - The options used to determine how to manage the workspace configuration. * @param {string} options.projectPath -The project's path including project name. * @param {boolean} [options.isAppStudio] - A boolean indicating whether the current environment is BAS. @@ -90,30 +91,30 @@ function handleOpenFolderButNoWorkspaceFile( * @param {any} options.vscode - The VS Code API object. * @returns {WorkspaceHandlerInfo} An object containing the path to the `launch.json` configuration file, the cwd command, workspaceFolderUri if provided will enable reload. */ -export function handleWorkspaceConfig(options: DebugOptions): WorkspaceHandlerInfo { - const { projectPath, isAppStudio = false, writeToAppOnly = false, vscode } = options; +export function handleWorkspaceConfig(rootFolder: string, options: DebugOptions): WorkspaceHandlerInfo { + const { isAppStudio = false, writeToAppOnly = false, vscode } = options; - const projectName = basename(projectPath); - const targetFolder = dirname(projectPath); + const projectName = basename(rootFolder); + const targetFolder = dirname(rootFolder); // Directly handle the case where we ignore workspace settings if (writeToAppOnly) { - return handleAppsNotInWorkspace(projectPath, isAppStudio, vscode); + return handleAppsNotInWorkspace(rootFolder, isAppStudio, vscode); } const workspace = vscode.workspace; const workspaceFile = workspace?.workspaceFile; // Handles the scenario where no workspace or folder is open in VS Code. if (!workspace) { - return handleAppsNotInWorkspace(projectPath, isAppStudio, vscode); + return handleAppsNotInWorkspace(rootFolder, isAppStudio, vscode); } // Handle case where a folder is open, but not a workspace file if (!workspaceFile) { - return handleOpenFolderButNoWorkspaceFile(projectPath, targetFolder, isAppStudio, vscode); + return handleOpenFolderButNoWorkspaceFile(rootFolder, targetFolder, isAppStudio, vscode); } // Handles the case where a previously saved workspace is open if (workspaceFile.scheme === 'file') { - return handleSavedWorkspace(projectPath, projectName, targetFolder, isAppStudio, vscode); + return handleSavedWorkspace(rootFolder, projectName, targetFolder, isAppStudio, vscode); } // Handles the case where an unsaved workspace is open - return handleUnsavedWorkspace(projectPath, vscode); + return handleUnsavedWorkspace(rootFolder, vscode); } diff --git a/packages/launch-config/src/launch-config-crud/create.ts b/packages/launch-config/src/launch-config-crud/create.ts index a5a3e45876..2bfce0b4e3 100644 --- a/packages/launch-config/src/launch-config-crud/create.ts +++ b/packages/launch-config/src/launch-config-crud/create.ts @@ -20,9 +20,9 @@ import { t } from '../i18n'; * @param {Editor} fs - The file system editor used to write the `launch.json` file. * @param {string} launchJSONPath - The full path to the `launch.json` file. * @param {LaunchConfig[]} configurations - An array of launch configurations to be included in the `launch.json` file. - * @returns {Promise} - A promise that resolves once the `launch.json` file has been written. + * @returns {void} */ -async function writeLaunchJsonFile(fs: Editor, launchJSONPath: string, configurations: LaunchConfig[]): Promise { +function writeLaunchJsonFile(fs: Editor, launchJSONPath: string, configurations: LaunchConfig[]): void { const newLaunchJSONContent = { version: '0.2.0', configurations }; fs.write(launchJSONPath, JSON.stringify(newLaunchJSONContent, null, 4)); } @@ -67,7 +67,7 @@ async function handleNoDebugOptions(rootFolder: string, fioriOptions: FioriOptio } // launch.json is missing, new file with new config const configurations = [generateNewFioriLaunchConfig(rootFolder, fioriOptions)]; - await writeLaunchJsonFile(fs, launchJsonWritePath, configurations); + writeLaunchJsonFile(fs, launchJsonWritePath, configurations); return fs; } @@ -80,7 +80,7 @@ async function handleNoDebugOptions(rootFolder: string, fioriOptions: FioriOptio * @param {Editor} fs - The file system editor to read and write the `launch.json` file. * @param {string} launchJSONPath - The path to the existing `launch.json` file. * @param {LaunchConfig[]} configurations - An array of new launch configurations to be added or replaced. - * @param {boolean | undefined} replaceWithNew - A flag indicating whether to replace the existing `launch.json` + * @param {boolean} replaceWithNew - A flag indicating whether to replace the existing `launch.json` * with new configurations (`true`) or append to the existing ones (`false`). * @returns {Promise} - A promise that resolves once the `launch.json` file has been updated or replaced. */ @@ -88,15 +88,14 @@ async function handleExistingLaunchJson( fs: Editor, launchJSONPath: string, configurations: LaunchConfig[], - replaceWithNew: boolean | undefined + replaceWithNew: boolean = false ): Promise { const launchJsonString = fs.read(launchJSONPath); const launchJson = parse(launchJsonString) as LaunchJSON; - if (replaceWithNew) { // replaceWithNew is needed in cases where launch config exists in // `.vscode` but isn't added to the workspace. If `replaceWithNew` is `true`, it indicates that the app is not - // in the workspace, so the entire `launch.json` and replaced since launch config is then generated in app folder. + // in the workspace, so the entire `launch.json` and replaced since launch config is then generated in app folder. const newLaunchJSONContent = { version: '0.2.0', configurations }; fs.write(launchJSONPath, JSON.stringify(newLaunchJSONContent, null, 4)); } else { @@ -119,7 +118,7 @@ async function handleExistingLaunchJson( * * @param {UpdateWorkspaceFolderOptions} updateWorkspaceFolders - The options for updating workspace folders. */ -export function updateWorkspaceFoldersIfNeeded(updateWorkspaceFolders: UpdateWorkspaceFolderOptions | undefined): void { +function updateWorkspaceFoldersIfNeeded(updateWorkspaceFolders?: UpdateWorkspaceFolderOptions): void { if (updateWorkspaceFolders) { const { uri, vscode, projectName } = updateWorkspaceFolders; if (uri && vscode) { @@ -137,6 +136,7 @@ export function updateWorkspaceFoldersIfNeeded(updateWorkspaceFolders: UpdateWor * This function processes workspace configuration, updates the `launch.json` file if it exists, * and creates it if it does not. Additionally, it updates workspace folders if applicable. * + * @param rootFolder - root folder. * @param {Editor} fs - The file system editor to read and write the `launch.json` file. * @param {DebugOptions} debugOptions - Debug configuration options that dictate how the `launch.json` * should be generated and what commands should be logged. @@ -144,22 +144,30 @@ export function updateWorkspaceFoldersIfNeeded(updateWorkspaceFolders: UpdateWor * @returns {Promise} - Returns the file system editor after potentially modifying the workspace * and updating or creating the `launch.json` file. */ -async function handleDebugOptions(fs: Editor, debugOptions: DebugOptions, log?: Logger): Promise { - const { launchJsonPath, workspaceFolderUri, cwd, appNotInWorkspace } = handleWorkspaceConfig(debugOptions); - const configurations = configureLaunchJsonFile(cwd, debugOptions).configurations; +async function handleDebugOptions( + rootFolder: string, + fs: Editor, + debugOptions: DebugOptions, + log?: Logger +): Promise { + const { launchJsonPath, workspaceFolderUri, cwd, appNotInWorkspace } = handleWorkspaceConfig( + rootFolder, + debugOptions + ); + const configurations = configureLaunchJsonFile(rootFolder, cwd, debugOptions).configurations; const npmCommand = debugOptions.datasourceType === DatasourceType.metadataFile ? 'run start-mock' : 'start'; log?.info( t('startServerMessage', { - folder: basename(debugOptions.projectPath), + folder: basename(rootFolder), npmCommand }) ); const launchJsonWritePath = getLaunchJsonPath(launchJsonPath); - if (fs.exists(launchJsonPath)) { + if (fs.exists(launchJsonWritePath)) { await handleExistingLaunchJson(fs, launchJsonWritePath, configurations, appNotInWorkspace); } else { - await writeLaunchJsonFile(fs, launchJsonWritePath, configurations); + writeLaunchJsonFile(fs, launchJsonWritePath, configurations); } // The `workspaceFolderUri` is a URI obtained from VS Code that specifies the path to the workspace folder. @@ -168,7 +176,7 @@ async function handleDebugOptions(fs: Editor, debugOptions: DebugOptions, log?: const updateWorkspaceFolders = workspaceFolderUri ? ({ uri: workspaceFolderUri, - projectName: basename(debugOptions.projectPath), + projectName: basename(rootFolder), vscode: debugOptions.vscode } as UpdateWorkspaceFolderOptions) : undefined; @@ -191,22 +199,18 @@ export async function createLaunchConfig( fioriOptions: FioriOptions, fs?: Editor, log?: Logger -): Promise { +): Promise { fs = fs ?? create(createStorage()); - const debugOptions = fioriOptions.debugOptions; - if (!debugOptions) { return await handleNoDebugOptions(rootFolder, fioriOptions, fs); } - + if (!debugOptions.vscode) { + return fs; + } if (debugOptions.datasourceType === DatasourceType.capProject) { log?.info(t('startApp', { npmStart: '`npm start`', cdsRun: '`cds run --in-memory`' })); - return; - } - - if (!debugOptions.vscode) { - return; + return fs; } - return await handleDebugOptions(fs, debugOptions, log); + return await handleDebugOptions(rootFolder, fs, debugOptions, log); } diff --git a/packages/launch-config/src/types/types.ts b/packages/launch-config/src/types/types.ts index d48abdedb4..09f6b4dcb4 100644 --- a/packages/launch-config/src/types/types.ts +++ b/packages/launch-config/src/types/types.ts @@ -65,8 +65,6 @@ export interface LaunchConfigInfo { * Configuration options for debugging launch configurations. */ export interface DebugOptions { - /** Path to the project directory. */ - projectPath: string; /** Type of the data source used in the project. */ datasourceType: DatasourceType; /** SAP client parameter for the connection. */ diff --git a/packages/launch-config/test/debug-config/config.test.ts b/packages/launch-config/test/debug-config/config.test.ts index 7a0b31841b..30ff9f17b4 100644 --- a/packages/launch-config/test/debug-config/config.test.ts +++ b/packages/launch-config/test/debug-config/config.test.ts @@ -6,6 +6,7 @@ import { FIORI_TOOLS_LAUNCH_CONFIG_HANDLER_ID } from '../../src/types'; const projectName = 'project1'; const cwd = `\${workspaceFolder}`; +const projectPath = path.join(__dirname, projectName); // Base configuration template const baseConfigurationObj: Partial = { @@ -56,7 +57,6 @@ describe('debug config tests', () => { beforeEach(() => { configOptions = { vscode: vscodeMock, - projectPath: path.join(__dirname, projectName), odataVersion: OdataVersion.v2, sapClientParam: '', flpAppId: 'project1-tile', @@ -72,7 +72,7 @@ describe('debug config tests', () => { }); it('Should return the correct configuration for OData v2', () => { - const launchFile = configureLaunchJsonFile(cwd, configOptions); + const launchFile = configureLaunchJsonFile(projectPath, cwd, configOptions); expect(launchFile.configurations.length).toBe(3); expect(findConfiguration(launchFile, `Start ${projectName}`)).toEqual(liveConfigurationObj); @@ -82,7 +82,7 @@ describe('debug config tests', () => { it('Should return the correct configuration for OData v4', () => { configOptions.odataVersion = OdataVersion.v4; - const launchFile = configureLaunchJsonFile(cwd, configOptions); + const launchFile = configureLaunchJsonFile(projectPath, cwd, configOptions); expect(launchFile.configurations.length).toBe(3); expect(findConfiguration(launchFile, `Start ${projectName}`)).toEqual(liveConfigurationObj); @@ -92,7 +92,7 @@ describe('debug config tests', () => { it('Should return correct configuration for local metadata', () => { configOptions.datasourceType = DatasourceType.metadataFile; - const launchFile = configureLaunchJsonFile(cwd, configOptions); + const launchFile = configureLaunchJsonFile(projectPath, cwd, configOptions); expect(launchFile.configurations.length).toBe(2); expect(findConfiguration(launchFile, `Start ${projectName}`)).toBeUndefined(); @@ -102,7 +102,7 @@ describe('debug config tests', () => { it('Should return correct configuration when project is being migrated', () => { configOptions.isMigrator = true; - const launchFile = configureLaunchJsonFile(cwd, configOptions); + const launchFile = configureLaunchJsonFile(projectPath, cwd, configOptions); const mockConfigWithMigrator = { ...mockConfigurationObj, args: ['--open', 'test/flpSandboxMockServer.html#project1-tile'] @@ -114,7 +114,7 @@ describe('debug config tests', () => { configOptions.isFioriElement = false; configOptions.flpSandboxAvailable = false; configOptions.flpAppId = ''; - const launchFile = configureLaunchJsonFile(cwd, configOptions); + const launchFile = configureLaunchJsonFile(projectPath, cwd, configOptions); const localConfig = { ...localConfigurationObj, args: ['--config', './ui5-local.yaml', '--open', 'index.html'] @@ -124,7 +124,7 @@ describe('debug config tests', () => { it('Should return correct configuration when migrator mock intent is provided', () => { configOptions.migratorMockIntent = 'flpSandboxMockFlpIntent'; - const launchFile = configureLaunchJsonFile(cwd, configOptions); + const launchFile = configureLaunchJsonFile(projectPath, cwd, configOptions); const localConfig = { ...localConfigurationObj, args: ['--config', './ui5-local.yaml', '--open', 'test/flpSandbox.html#flpSandboxMockFlpIntent'] @@ -138,7 +138,7 @@ describe('debug config tests', () => { configOptions.sapClientParam = 'sapClientParam'; configOptions.isAppStudio = true; - const launchFile = configureLaunchJsonFile(cwd, configOptions); + const launchFile = configureLaunchJsonFile(path.join(__dirname, projectName), cwd, configOptions); expect(launchFile.configurations.length).toBe(3); const projectPath = path.join(__dirname, 'project1'); diff --git a/packages/launch-config/test/debug-config/configureLaunchConfig.test.ts b/packages/launch-config/test/debug-config/configureLaunchConfig.test.ts deleted file mode 100644 index 988ac51a35..0000000000 --- a/packages/launch-config/test/debug-config/configureLaunchConfig.test.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { join } from 'path'; -import { handleWorkspaceConfig } from '../../src/debug-config/workspaceManager'; -import type { DebugOptions, UpdateWorkspaceFolderOptions, LaunchJSON } from '../../src/types'; -import { LAUNCH_JSON_FILE } from '../../src/types'; -import { - updateWorkspaceFoldersIfNeeded, - createOrUpdateLaunchConfigJSON, - configureLaunchConfig -} from '../../src/launch-config-crud/create'; -import { t } from '../../src/i18n'; -import { DatasourceType } from '@sap-ux/odata-service-inquirer'; -import type { Editor } from 'mem-fs-editor'; -import { DirName } from '@sap-ux/project-access'; -import type { Logger } from '@sap-ux/logger'; - -// Mock dependencies -jest.mock('jsonc-parser', () => ({ - parse: jest.fn().mockReturnValue({ - configurations: [{ name: 'Existing Config', type: 'node' }] - }) -})); -jest.mock('../../src/debug-config/workspaceManager', () => ({ - handleWorkspaceConfig: jest.fn() -})); -jest.mock('../../src/debug-config/config', () => ({ - configureLaunchJsonFile: jest.fn(), - writeApplicationInfoSettings: jest.requireActual('../../src/debug-config/config').writeApplicationInfoSettings -})); - -const mockLog = { - error: jest.fn(), - info: jest.fn() -} as unknown as Logger; - -const mockEditor = { - exists: jest.fn().mockReturnValue(false), - read: jest.fn(), - write: jest.fn() -} as unknown as Editor; - -describe('Config Functions', () => { - const launchJson = { - configurations: [{ name: 'New Config', type: 'node' }] - } as LaunchJSON; - - const existingLaunchJson = { - configurations: [{ name: 'Existing Config', type: 'node' }] - } as LaunchJSON; - - afterEach(() => { - jest.clearAllMocks(); - }); - - describe('updateWorkspaceFoldersIfNeeded', () => { - it('should update workspace folders if options are provided', () => { - const updateOptions = { - uri: '/mock/uri', - vscode: { - workspace: { - workspaceFolders: [], - updateWorkspaceFolders: jest.fn() - } - }, - projectName: 'Test Project' - } as UpdateWorkspaceFolderOptions; - updateWorkspaceFoldersIfNeeded(updateOptions); - expect(updateOptions.vscode.workspace.updateWorkspaceFolders).toHaveBeenCalledWith(0, undefined, { - name: 'Test Project', - uri: '/mock/uri' - }); - }); - - it('should not update workspace folders if no options are provided', () => { - const updateOptions: UpdateWorkspaceFolderOptions | undefined = undefined; - updateWorkspaceFoldersIfNeeded(updateOptions); - // No updateWorkspaceFolders call expected hence no app info json written - expect(mockEditor.write).not.toHaveBeenCalled(); - }); - }); - - describe('createOrUpdateLaunchConfigJSON', () => { - it('should create a new launch.json file if it does not exist', () => { - const rootFolderPath = '/root/folder'; - const appNotInWorkspace = false; - mockEditor.exists = jest.fn().mockReturnValue(false); - createOrUpdateLaunchConfigJSON( - rootFolderPath, - launchJson, - mockEditor, - undefined, - appNotInWorkspace, - mockLog - ); - expect(mockEditor.write).toHaveBeenCalledWith( - join(rootFolderPath, DirName.VSCode, LAUNCH_JSON_FILE), - JSON.stringify(launchJson, null, 4) - ); - }); - - it('should update an existing launch.json file', () => { - const rootFolderPath = '/root/folder'; - const appNotInWorkspace = false; - mockEditor.exists = jest.fn().mockReturnValue(true); - createOrUpdateLaunchConfigJSON( - rootFolderPath, - launchJson, - mockEditor, - undefined, - appNotInWorkspace, - mockLog - ); - - expect(mockEditor.write).toHaveBeenCalledWith( - join(rootFolderPath, DirName.VSCode, LAUNCH_JSON_FILE), - JSON.stringify( - { - configurations: [...existingLaunchJson.configurations, ...launchJson.configurations] - }, - null, - 4 - ) - ); - }); - - it('should not update an existing launch.json file when app not in workspace', () => { - const rootFolderPath = '/root/folder'; - const appNotInWorkspace = true; - mockEditor.exists = jest.fn().mockReturnValue(true); - createOrUpdateLaunchConfigJSON( - rootFolderPath, - launchJson, - mockEditor, - undefined, - appNotInWorkspace, - mockLog - ); - expect(mockEditor.write).toHaveBeenCalledWith( - join(rootFolderPath, DirName.VSCode, LAUNCH_JSON_FILE), - JSON.stringify(launchJson, null, 4) - ); - }); - - it('should handle errors while writing launch.json file', () => { - const rootFolderPath = '/root/folder'; - const appNotInWorkspace = false; - const mockEditorWithError = { - exists: jest.fn().mockReturnValue(false), - read: jest.fn(), - write: jest.fn().mockImplementation(() => { - throw new Error(); - }) - } as unknown as Editor; - createOrUpdateLaunchConfigJSON( - rootFolderPath, - launchJson, - mockEditorWithError, - undefined, - appNotInWorkspace, - mockLog - ); - expect(mockLog.error).toHaveBeenCalledWith(t('errorLaunchFile')); - }); - }); - - describe('configureLaunchConfig', () => { - it('should configure launch config and update workspace folders', () => { - const mockOptions = { - projectPath: '/mock/project/path', - writeToAppOnly: true, - vscode: { - workspace: { - workspaceFolders: [], - updateWorkspaceFolders: jest.fn() - } - } as any - } as DebugOptions; - - const mockLog = { - info: jest.fn(), - error: jest.fn() - } as unknown as Logger; - - // Mock handleWorkspaceConfig to return a specific launchJsonPath and cwd - (handleWorkspaceConfig as jest.Mock).mockReturnValue({ - launchJsonPath: '/mock/launch.json', - cwd: '${workspaceFolder}/path', - workspaceFolderUri: '/mock/launch.json' - }); - - // Call the function under test - configureLaunchConfig(mockOptions, mockEditor, mockLog); - - // Expectations to ensure that workspace folders are updated correctly - expect(mockOptions.vscode.workspace.updateWorkspaceFolders).toHaveBeenCalledWith(0, undefined, { - uri: '/mock/launch.json', - name: 'path' - }); - }); - - it('should log startApp message when datasourceType is capProject', () => { - const options = { - datasourceType: DatasourceType.capProject, - projectPath: 'some/path' - } as DebugOptions; - configureLaunchConfig(options, mockEditor, mockLog); - expect(mockLog.info).toHaveBeenCalledWith( - t('startApp', { npmStart: '`npm start`', cdsRun: '`cds run --in-memory`' }) - ); - }); - - it('Should not run in Yeoman CLI or if vscode not found', () => { - const options = { - datasourceType: DatasourceType.metadataFile, - projectPath: 'some/path', - vscode: false - } as DebugOptions; - configureLaunchConfig(options, mockEditor, mockLog); - expect(mockLog.info).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/packages/launch-config/test/debug-config/workspaceManager.test.ts b/packages/launch-config/test/debug-config/workspaceManager.test.ts index 686513adba..e56a6c55d6 100644 --- a/packages/launch-config/test/debug-config/workspaceManager.test.ts +++ b/packages/launch-config/test/debug-config/workspaceManager.test.ts @@ -49,12 +49,11 @@ describe('launchConfig Unit Tests', () => { }); const options = { - projectPath: mockProjectPath, isAppStudio, vscode: mockVscode } as DebugOptions; - const result = handleWorkspaceConfig(options); + const result = handleWorkspaceConfig(mockProjectPath, options); expect(result).toEqual({ launchJsonPath: mockProjectPath, cwd: '${workspaceFolder}' @@ -72,12 +71,11 @@ describe('launchConfig Unit Tests', () => { (getLaunchJsonPath as jest.Mock).mockReturnValue(mockTargetFolder); const options = { - projectPath: mockProjectPath, isAppStudio, vscode: mockVscode } as DebugOptions; - const result = handleWorkspaceConfig(options); + const result = handleWorkspaceConfig(mockProjectPath, options); expect(result).toEqual({ launchJsonPath: mockTargetFolder, cwd: '${workspaceFolder}/nestedFolder' @@ -94,11 +92,10 @@ describe('launchConfig Unit Tests', () => { (getLaunchJsonPath as jest.Mock).mockReturnValue(mockTargetFolder); const options = { - projectPath: mockProjectPath, isAppStudio, vscode: mockVscode } as DebugOptions; - const result = handleWorkspaceConfig(options); + const result = handleWorkspaceConfig(mockProjectPath, options); expect(result).toEqual({ launchJsonPath: mockTargetFolder, cwd: '${workspaceFolder}/project' @@ -114,11 +111,10 @@ describe('launchConfig Unit Tests', () => { }); const options = { - projectPath: mockProjectPath, isAppStudio, vscode: mockVscode } as DebugOptions; - const result = handleWorkspaceConfig(options); + const result = handleWorkspaceConfig(mockProjectPath, options); expect(result).toEqual({ launchJsonPath: mockProjectPath, cwd: '${workspaceFolder}' @@ -136,10 +132,9 @@ describe('launchConfig Unit Tests', () => { (path.relative as jest.Mock).mockReturnValue(mockNestedFolder); (formatCwd as jest.Mock).mockReturnValue('${workspaceFolder}/nestedFolder'); const options = { - projectPath: mockProjectPath, vscode: mockVscode } as DebugOptions; - const result = handleWorkspaceConfig(options); + const result = handleWorkspaceConfig(mockProjectPath, options); expect(result).toEqual({ launchJsonPath: mockWsFolder, cwd: '${workspaceFolder}/nestedFolder' @@ -151,7 +146,6 @@ describe('launchConfig Unit Tests', () => { it('should handle writeToAppOnly option', () => { const mockProjectPath = '/mock/project/path'; const options = { - projectPath: mockProjectPath, writeToAppOnly: true, vscode: mockVscode } as DebugOptions; @@ -161,7 +155,7 @@ describe('launchConfig Unit Tests', () => { cwd: '${workspaceFolder}' }); - const result = handleWorkspaceConfig(options); + const result = handleWorkspaceConfig(mockProjectPath, options); expect(result).toEqual({ launchJsonPath: mockProjectPath, cwd: '${workspaceFolder}' @@ -173,7 +167,6 @@ describe('launchConfig Unit Tests', () => { const mockProjectPath = '/mock/project/path'; const mockTargetFolder = '/target/folder'; const options = { - projectPath: mockProjectPath, vscode: { ...mockVscode, workspace: { ...mockVscode.workspace, workspaceFile: undefined } @@ -186,7 +179,7 @@ describe('launchConfig Unit Tests', () => { (getLaunchJsonPath as jest.Mock).mockReturnValue(mockTargetFolder); // Call the function under test - const result = handleWorkspaceConfig(options); + const result = handleWorkspaceConfig(mockProjectPath, options); // Assertions expect(result).toEqual({ @@ -205,7 +198,6 @@ describe('launchConfig Unit Tests', () => { it('should handle no workspace case', () => { const mockProjectPath = '/mock/project/path'; const options = { - projectPath: mockProjectPath, vscode: { ...mockVscode, workspace: undefined } } as DebugOptions; (handleAppsNotInWorkspace as jest.Mock).mockReturnValue({ @@ -213,7 +205,7 @@ describe('launchConfig Unit Tests', () => { cwd: '${workspaceFolder}' }); - const result = handleWorkspaceConfig(options); + const result = handleWorkspaceConfig(mockProjectPath, options); expect(result).toEqual({ launchJsonPath: mockProjectPath, cwd: '${workspaceFolder}' @@ -232,11 +224,10 @@ describe('launchConfig Unit Tests', () => { }; // Prepare options for the test const options = { - projectPath: mockProjectPath, vscode: mockVscode } as DebugOptions; // Call the function under test - const result = handleWorkspaceConfig(options); + const result = handleWorkspaceConfig(mockProjectPath, options); // Assertions expect(result).toEqual({ launchJsonPath: mockTargetFolder, @@ -263,11 +254,10 @@ describe('launchConfig Unit Tests', () => { // Prepare options for the test const options = { - projectPath: mockProjectPath, vscode: mockVscode } as DebugOptions; // Call the function under test - const result = handleWorkspaceConfig(options); + const result = handleWorkspaceConfig(mockProjectPath, options); // Assertions expect(result).toEqual({ launchJsonPath: mockProjectPath, diff --git a/packages/launch-config/test/launch-config-crud/create.test.ts b/packages/launch-config/test/launch-config-crud/create.test.ts index 55957a7813..f9d53d4ef0 100644 --- a/packages/launch-config/test/launch-config-crud/create.test.ts +++ b/packages/launch-config/test/launch-config-crud/create.test.ts @@ -1,14 +1,36 @@ -import { join } from 'path'; +import { basename, join } from 'path'; import { create as createStorage } from 'mem-fs'; import { create } from 'mem-fs-editor'; import { createLaunchConfig } from '../../src/launch-config-crud/create'; import { DirName, FileName } from '@sap-ux/project-access'; import { TestPaths } from '../test-data/utils'; +import type { DebugOptions } from '../../src/types'; +import { LAUNCH_JSON_FILE } from '../../src/types'; +import type { Logger } from '@sap-ux/logger'; +import { DatasourceType } from '@sap-ux/odata-service-inquirer'; +import { t } from '../../src/i18n'; +import { isFolderInWorkspace } from '../../src/debug-config/helpers'; + +// Mock the helpers +jest.mock('../../src/debug-config/helpers', () => ({ + ...jest.requireActual('../../src/debug-config/helpers'), + isFolderInWorkspace: jest.fn() +})); describe('create', () => { const memFs = create(createStorage()); const memFilePath = join(TestPaths.tmpDir, 'fe-projects', FileName.Package); const memFileContent = '{}\n'; + const mockLog = { + error: jest.fn(), + info: jest.fn() + } as unknown as Logger; + + const clearMemFsPaths = (path: string) => { + if (memFs.exists(path)) { + memFs.delete(path); + } + }; beforeEach(() => { memFs.writeJSON(memFilePath, memFileContent); @@ -19,7 +41,7 @@ describe('create', () => { }); test('launch.json file is missing, create new file with new config', async () => { - const result: any = await createLaunchConfig( + const result = await createLaunchConfig( TestPaths.tmpDir, { name: 'LaunchConfig_One', projectRoot: join(TestPaths.tmpDir, 'fe-projects') }, memFs @@ -64,7 +86,7 @@ describe('create', () => { const ui5VersionUri = 'DUMMY_UI5_URI'; // Select destination const backendConfigs = [{ path: 'TEST_PATH', name: 'TEST_DESTINAME', url: 'dummy' }]; - const result: any = await createLaunchConfig( + const result = await createLaunchConfig( TestPaths.tmpDir, { name: 'LaunchConfig_One', @@ -117,7 +139,7 @@ describe('create', () => { } ] }); - const result: any = await createLaunchConfig( + const result = await createLaunchConfig( TestPaths.tmpDir, { name: 'LaunchConfig_Two', projectRoot: join(TestPaths.tmpDir, 'fe-projects') }, memFs @@ -153,4 +175,279 @@ describe('create', () => { ] }); }); + + test('launch.json file is missing, create new file with new config when debug options is provided', async () => { + const projectPath = join(TestPaths.tmpDir, 'test-projects'); + const launchConfigPath = join(projectPath, '.vscode', 'launch.json'); + if (memFs.exists(launchConfigPath)) { + memFs.delete(launchConfigPath); + } + const fs = await createLaunchConfig( + projectPath, + { + name: 'test-projects', + projectRoot: projectPath, + debugOptions: { + datasourceType: DatasourceType.odataServiceUrl, + vscode: true + } as DebugOptions + }, + memFs, + mockLog + ); + + expect(fs.exists(launchConfigPath)).toBe(true); + expect(mockLog.info).toHaveBeenCalledWith( + t('startServerMessage', { + folder: basename(projectPath), + npmCommand: 'start' + }) + ); + expect(fs.readJSON(launchConfigPath)).toStrictEqual({ + version: '0.2.0', + configurations: [ + { + name: 'Start test-projects', + type: 'node', + request: 'launch', + cwd: '${workspaceFolder}', + runtimeExecutable: 'npx', + windows: { + runtimeExecutable: 'npx.cmd' + }, + runtimeArgs: ['fiori', 'run'], + args: ['--open', 'index.htmlundefined'], + console: 'internalConsole', + internalConsoleOptions: 'openOnSessionStart', + outputCapture: 'std', + env: { + 'DEBUG': '--inspect', + 'FIORI_TOOLS_URL_PARAMS': 'sap-ui-xx-viewCache=false' + } + }, + { + name: 'Start test-projects Local', + type: 'node', + request: 'launch', + cwd: '${workspaceFolder}', + runtimeExecutable: 'npx', + windows: { + runtimeExecutable: 'npx.cmd' + }, + runtimeArgs: ['fiori', 'run'], + args: ['--config', './ui5-local.yaml', '--open', 'index.htmlundefined'], + console: 'internalConsole', + internalConsoleOptions: 'openOnSessionStart', + outputCapture: 'std', + env: { + 'FIORI_TOOLS_URL_PARAMS': 'sap-ui-xx-viewCache=false' + } + } + ] + }); + }); + + test('launch.json file is missing, will not create config when debug options provided and app source is cap project', async () => { + const projectPath = join(TestPaths.tmpDir, 'test-projects'); + const launchConfigPath = join(projectPath, DirName.VSCode, LAUNCH_JSON_FILE); + clearMemFsPaths(launchConfigPath); + + const fs = await createLaunchConfig( + TestPaths.tmpDir, + { + name: 'test-projects', + projectRoot: projectPath, + debugOptions: { + datasourceType: DatasourceType.capProject, + vscode: true + } as DebugOptions + }, + memFs, + mockLog + ); + expect(fs.exists(launchConfigPath)).toBe(false); + expect(mockLog.info).toHaveBeenCalledWith( + t('startApp', { npmStart: '`npm start`', cdsRun: '`cds run --in-memory`' }) + ); + }); + + test('Should create launch.json or run in Yeoman CLI or if vscode not found', async () => { + const projectPath = join(TestPaths.tmpDir, 'test-projects'); + const launchConfigPath = join(projectPath, DirName.VSCode, LAUNCH_JSON_FILE); + clearMemFsPaths(launchConfigPath); + const fs = await createLaunchConfig( + TestPaths.tmpDir, + { + name: 'test-projects', + projectRoot: projectPath, + debugOptions: { + datasourceType: DatasourceType.capProject, + vscode: false + } as DebugOptions + }, + memFs, + mockLog + ); + expect(fs.exists(launchConfigPath)).toBe(false); + }); + + test('launch.json file already exists, update file with debig config when debug options is provided and app is created out of', async () => { + const projectPath = join(TestPaths.tmpDir, 'test', 'test-projects'); + const launchJSONPath = join(TestPaths.tmpDir, 'test', '.vscode', 'launch.json'); + clearMemFsPaths(launchJSONPath); + memFs.writeJSON(launchJSONPath, { + version: '0.2.0', + configurations: [ + { + name: 'LaunchConfig_One' + } + ] + }); + (isFolderInWorkspace as jest.Mock).mockReturnValue(true); + const result: any = await createLaunchConfig( + projectPath, + { + name: 'test-projects', + projectRoot: projectPath, + debugOptions: { + datasourceType: DatasourceType.odataServiceUrl, + vscode: { + workspace: { + workspaceFile: { scheme: 'file' } + } + } as any, + isAppStudio: false + } as DebugOptions + }, + memFs + ); + expect(result.exists(launchJSONPath)).toBe(true); + const expectedLaunchConfigPath = join(TestPaths.tmpDir, 'test', '.vscode', 'launch.json'); + const updatedJson = result.readJSON(expectedLaunchConfigPath); + expect(updatedJson).toStrictEqual({ + version: '0.2.0', + configurations: [ + { + name: 'LaunchConfig_One' + }, + { + name: 'Start test-projects', + type: 'node', + request: 'launch', + cwd: '${workspaceFolder}/test-projects', + runtimeExecutable: 'npx', + windows: { + runtimeExecutable: 'npx.cmd' + }, + runtimeArgs: ['fiori', 'run'], + args: ['--open', 'index.htmlundefined'], + console: 'internalConsole', + internalConsoleOptions: 'openOnSessionStart', + outputCapture: 'std', + env: { + DEBUG: '--inspect', + FIORI_TOOLS_URL_PARAMS: 'sap-ui-xx-viewCache=false' + } + }, + { + name: 'Start test-projects Local', + type: 'node', + request: 'launch', + cwd: '${workspaceFolder}/test-projects', + runtimeExecutable: 'npx', + windows: { + runtimeExecutable: 'npx.cmd' + }, + runtimeArgs: ['fiori', 'run'], + args: ['--config', './ui5-local.yaml', '--open', 'index.htmlundefined'], + console: 'internalConsole', + internalConsoleOptions: 'openOnSessionStart', + outputCapture: 'std', + env: { + FIORI_TOOLS_URL_PARAMS: 'sap-ui-xx-viewCache=false' + } + } + ] + }); + }); + + test('launch.json file already exists, update file with debig config when debug options is provided', async () => { + const projectPath = join(TestPaths.tmpDir, 'test', 'test-projects'); + const launchJSONPath = join(TestPaths.tmpDir, 'test', '.vscode', 'launch.json'); + clearMemFsPaths(launchJSONPath); + memFs.writeJSON(launchJSONPath, { + version: '0.2.0', + configurations: [ + { + name: 'LaunchConfig_One' + } + ] + }); + (isFolderInWorkspace as jest.Mock).mockReturnValue(true); + const result: any = await createLaunchConfig( + projectPath, + { + name: 'test-projects', + projectRoot: projectPath, + debugOptions: { + datasourceType: DatasourceType.odataServiceUrl, + vscode: { + workspace: { + workspaceFile: { scheme: 'file' } + } + } as any, + isAppStudio: false + } as DebugOptions + }, + memFs + ); + expect(result.exists(launchJSONPath)).toBe(true); + const expectedLaunchConfigPath = join(TestPaths.tmpDir, 'test', '.vscode', 'launch.json'); + const updatedJson = result.readJSON(expectedLaunchConfigPath); + expect(updatedJson).toStrictEqual({ + version: '0.2.0', + configurations: [ + { + name: 'LaunchConfig_One' + }, + { + name: 'Start test-projects', + type: 'node', + request: 'launch', + cwd: '${workspaceFolder}/test-projects', + runtimeExecutable: 'npx', + windows: { + runtimeExecutable: 'npx.cmd' + }, + runtimeArgs: ['fiori', 'run'], + args: ['--open', 'index.htmlundefined'], + console: 'internalConsole', + internalConsoleOptions: 'openOnSessionStart', + outputCapture: 'std', + env: { + DEBUG: '--inspect', + FIORI_TOOLS_URL_PARAMS: 'sap-ui-xx-viewCache=false' + } + }, + { + name: 'Start test-projects Local', + type: 'node', + request: 'launch', + cwd: '${workspaceFolder}/test-projects', + runtimeExecutable: 'npx', + windows: { + runtimeExecutable: 'npx.cmd' + }, + runtimeArgs: ['fiori', 'run'], + args: ['--config', './ui5-local.yaml', '--open', 'index.htmlundefined'], + console: 'internalConsole', + internalConsoleOptions: 'openOnSessionStart', + outputCapture: 'std', + env: { + FIORI_TOOLS_URL_PARAMS: 'sap-ui-xx-viewCache=false' + } + } + ] + }); + }); }); From f22696b1731f83dc93fb2aa4fe50d2f73532b093 Mon Sep 17 00:00:00 2001 From: I743583 Date: Fri, 13 Sep 2024 17:34:30 +0100 Subject: [PATCH 11/14] pnpm install updates --- .changeset/tidy-papayas-film.md | 1 + packages/launch-config/package.json | 1 - .../launch-config/src/debug-config/config.ts | 11 +++++----- .../src/launch-config-crud/create.ts | 7 +++---- packages/launch-config/src/types/constants.ts | 2 ++ packages/launch-config/src/types/types.ts | 16 ++++++++++++--- .../test/debug-config/config.test.ts | 20 +++++++++++-------- .../test/launch-config-crud/create.test.ts | 13 ++++++------ packages/launch-config/tsconfig.json | 3 --- pnpm-lock.yaml | 3 --- 10 files changed, 42 insertions(+), 35 deletions(-) diff --git a/.changeset/tidy-papayas-film.md b/.changeset/tidy-papayas-film.md index 5ece385196..093413332b 100644 --- a/.changeset/tidy-papayas-film.md +++ b/.changeset/tidy-papayas-film.md @@ -3,3 +3,4 @@ --- Reverted the use of Node.js `fs` modules and replaced them with `mem-fs` for writing launch config files & Removed `writeApplicationInfoSettings()` from `@sap-ux/launch-config` +Refactoring create launch config functionalities. \ No newline at end of file diff --git a/packages/launch-config/package.json b/packages/launch-config/package.json index 261782e65a..b44865b159 100644 --- a/packages/launch-config/package.json +++ b/packages/launch-config/package.json @@ -34,7 +34,6 @@ "@sap-ux/project-access": "workspace:*", "@sap-ux/ui5-config": "workspace:*", "@sap-ux/ui5-info": "workspace:*", - "@sap-ux/odata-service-inquirer": "workspace:*", "i18next": "23.5.1", "jsonc-parser": "3.2.0", "mem-fs": "2.1.0", diff --git a/packages/launch-config/src/debug-config/config.ts b/packages/launch-config/src/debug-config/config.ts index 6a772b5fd9..cc0b679eb5 100644 --- a/packages/launch-config/src/debug-config/config.ts +++ b/packages/launch-config/src/debug-config/config.ts @@ -1,8 +1,7 @@ -import { DatasourceType, OdataVersion } from '@sap-ux/odata-service-inquirer'; import { basename } from 'path'; import { getLaunchConfig } from '../launch-config-crud/utils'; import type { LaunchConfig, LaunchJSON, DebugOptions, LaunchConfigEnv } from '../types'; -import { FIORI_TOOLS_LAUNCH_CONFIG_HANDLER_ID } from '../types'; +import { FIORI_TOOLS_LAUNCH_CONFIG_HANDLER_ID, ProjectDataSourceType, oDataVersionV2, oDataVersionV4 } from '../types'; // debug constants const testFlpSandboxHtml = 'test/flpSandbox.html'; @@ -87,7 +86,7 @@ export function configureLaunchJsonFile(rootFolder: string, cwd: string, configO const launchFile: LaunchJSON = { version: '0.2.0', configurations: [] }; // Add live configuration if the datasource is not from a metadata file - if (datasourceType !== DatasourceType.metadataFile) { + if (datasourceType !== ProjectDataSourceType.metadataFile) { const startCommand = `${startHtmlFile}${flpAppIdWithHash}`; const liveConfig = createLaunchConfig( `Start ${projectName}`, @@ -101,10 +100,10 @@ export function configureLaunchJsonFile(rootFolder: string, cwd: string, configO } // Add mock configuration for OData V2 or V4 - if (odataVersion && [OdataVersion.v2, OdataVersion.v4].includes(odataVersion)) { + if (odataVersion && [oDataVersionV2, oDataVersionV4].includes(odataVersion)) { const params = `${flpAppIdWithHash ?? ''}`; const mockCmdArgs = - isMigrator && odataVersion === OdataVersion.v2 + isMigrator && odataVersion === oDataVersionV2 ? ['--open', `${testFlpSandboxMockServerHtml}${params}`] : ['--config', './ui5-mock.yaml', '--open', `${testFlpSandboxHtml}${params}`]; const mockConfig = createLaunchConfig( @@ -119,7 +118,7 @@ export function configureLaunchJsonFile(rootFolder: string, cwd: string, configO } // Add local configuration - const shouldUseMockServer = isFioriElement && odataVersion === OdataVersion.v2 && isMigrator; + const shouldUseMockServer = isFioriElement && odataVersion === oDataVersionV2 && isMigrator; const localHtmlFile = shouldUseMockServer ? testFlpSandboxMockServerHtml : startHtmlFile; const startLocalCommand = `${localHtmlFile}${ migratorMockIntent ? `#${migratorMockIntent.replace('#', '')}` : flpAppIdWithHash diff --git a/packages/launch-config/src/launch-config-crud/create.ts b/packages/launch-config/src/launch-config-crud/create.ts index 2bfce0b4e3..a1ca3ba24c 100644 --- a/packages/launch-config/src/launch-config-crud/create.ts +++ b/packages/launch-config/src/launch-config-crud/create.ts @@ -2,7 +2,7 @@ import { create as createStorage } from 'mem-fs'; import { create } from 'mem-fs-editor'; import { join, basename } from 'path'; import { DirName } from '@sap-ux/project-access'; -import { LAUNCH_JSON_FILE } from '../types'; +import { LAUNCH_JSON_FILE, ProjectDataSourceType } from '../types'; import type { FioriOptions, LaunchJSON, UpdateWorkspaceFolderOptions, DebugOptions, LaunchConfig } from '../types'; import type { Editor } from 'mem-fs-editor'; import { generateNewFioriLaunchConfig } from './utils'; @@ -11,7 +11,6 @@ import { parse } from 'jsonc-parser'; import { handleWorkspaceConfig } from '../debug-config/workspaceManager'; import { configureLaunchJsonFile } from '../debug-config/config'; import type { Logger } from '@sap-ux/logger'; -import { DatasourceType } from '@sap-ux/odata-service-inquirer'; import { t } from '../i18n'; /** @@ -156,7 +155,7 @@ async function handleDebugOptions( ); const configurations = configureLaunchJsonFile(rootFolder, cwd, debugOptions).configurations; - const npmCommand = debugOptions.datasourceType === DatasourceType.metadataFile ? 'run start-mock' : 'start'; + const npmCommand = debugOptions.datasourceType === ProjectDataSourceType.metadataFile ? 'run start-mock' : 'start'; log?.info( t('startServerMessage', { folder: basename(rootFolder), @@ -208,7 +207,7 @@ export async function createLaunchConfig( if (!debugOptions.vscode) { return fs; } - if (debugOptions.datasourceType === DatasourceType.capProject) { + if (debugOptions.datasourceType === ProjectDataSourceType.capProject) { log?.info(t('startApp', { npmStart: '`npm start`', cdsRun: '`cds run --in-memory`' })); return fs; } diff --git a/packages/launch-config/src/types/constants.ts b/packages/launch-config/src/types/constants.ts index 0f54b94c7f..87cb457b31 100644 --- a/packages/launch-config/src/types/constants.ts +++ b/packages/launch-config/src/types/constants.ts @@ -1,3 +1,5 @@ export const FIORI_TOOLS_LAUNCH_CONFIG_HANDLER_ID = 'fiori_tools'; export const LAUNCH_JSON_FILE = 'launch.json'; export const RUN_SCRIPT = 'run-script'; +export const oDataVersionV2: string = '2', + oDataVersionV4: string = '4'; diff --git a/packages/launch-config/src/types/types.ts b/packages/launch-config/src/types/types.ts index 09f6b4dcb4..3e43f6dd91 100644 --- a/packages/launch-config/src/types/types.ts +++ b/packages/launch-config/src/types/types.ts @@ -1,6 +1,5 @@ import type { ODataVersion } from '@sap-ux/project-access'; import type { FioriToolsProxyConfigBackend } from '@sap-ux/ui5-config'; -import type { OdataVersion, DatasourceType } from '@sap-ux/odata-service-inquirer'; export enum Arguments { FrameworkVersion = '--framework-version', @@ -61,12 +60,23 @@ export interface LaunchConfigInfo { filePath: string; } +/** + * Enum representing the types of data sources or origins for a project. + * These types indicate how a project is generated. + */ +export enum ProjectDataSourceType { + capProject = 'capProject', + odataServiceUrl = 'odataServiceUrl', + none = 'none', + metadataFile = 'metadataFile' +} + /** * Configuration options for debugging launch configurations. */ export interface DebugOptions { /** Type of the data source used in the project. */ - datasourceType: DatasourceType; + datasourceType: ProjectDataSourceType; /** SAP client parameter for the connection. */ sapClientParam: string; /** FLP application ID. */ @@ -74,7 +84,7 @@ export interface DebugOptions { /** Indicates if the FLP sandbox environment is available. */ flpSandboxAvailable: boolean; /** Version of the OData service. */ - odataVersion?: OdataVersion; + odataVersion?: string; /** Indicates if the project is a Fiori Element. */ isFioriElement?: boolean; /** Intent parameter for the migrator mock. */ diff --git a/packages/launch-config/test/debug-config/config.test.ts b/packages/launch-config/test/debug-config/config.test.ts index 30ff9f17b4..a632a060d9 100644 --- a/packages/launch-config/test/debug-config/config.test.ts +++ b/packages/launch-config/test/debug-config/config.test.ts @@ -1,8 +1,12 @@ import { configureLaunchJsonFile } from '../../src/debug-config/config'; import type { DebugOptions, LaunchConfig, LaunchJSON } from '../../src/types'; import path from 'path'; -import { DatasourceType, OdataVersion } from '@sap-ux/odata-service-inquirer'; -import { FIORI_TOOLS_LAUNCH_CONFIG_HANDLER_ID } from '../../src/types'; +import { + FIORI_TOOLS_LAUNCH_CONFIG_HANDLER_ID, + ProjectDataSourceType, + oDataVersionV2, + oDataVersionV4 +} from '../../src/types'; const projectName = 'project1'; const cwd = `\${workspaceFolder}`; @@ -57,12 +61,12 @@ describe('debug config tests', () => { beforeEach(() => { configOptions = { vscode: vscodeMock, - odataVersion: OdataVersion.v2, + odataVersion: oDataVersionV2, sapClientParam: '', flpAppId: 'project1-tile', isFioriElement: true, flpSandboxAvailable: true, - datasourceType: DatasourceType.odataServiceUrl + datasourceType: ProjectDataSourceType.odataServiceUrl }; }); @@ -81,7 +85,7 @@ describe('debug config tests', () => { }); it('Should return the correct configuration for OData v4', () => { - configOptions.odataVersion = OdataVersion.v4; + configOptions.odataVersion = oDataVersionV4; const launchFile = configureLaunchJsonFile(projectPath, cwd, configOptions); expect(launchFile.configurations.length).toBe(3); @@ -91,7 +95,7 @@ describe('debug config tests', () => { }); it('Should return correct configuration for local metadata', () => { - configOptions.datasourceType = DatasourceType.metadataFile; + configOptions.datasourceType = ProjectDataSourceType.metadataFile; const launchFile = configureLaunchJsonFile(projectPath, cwd, configOptions); expect(launchFile.configurations.length).toBe(2); @@ -133,8 +137,8 @@ describe('debug config tests', () => { }); it('Should return correct configuration on BAS and sapClientParam is available', () => { - configOptions.odataVersion = OdataVersion.v2; - configOptions.datasourceType = DatasourceType.odataServiceUrl; + configOptions.odataVersion = oDataVersionV2; + configOptions.datasourceType = ProjectDataSourceType.odataServiceUrl; configOptions.sapClientParam = 'sapClientParam'; configOptions.isAppStudio = true; diff --git a/packages/launch-config/test/launch-config-crud/create.test.ts b/packages/launch-config/test/launch-config-crud/create.test.ts index f9d53d4ef0..718b8e792f 100644 --- a/packages/launch-config/test/launch-config-crud/create.test.ts +++ b/packages/launch-config/test/launch-config-crud/create.test.ts @@ -5,9 +5,8 @@ import { createLaunchConfig } from '../../src/launch-config-crud/create'; import { DirName, FileName } from '@sap-ux/project-access'; import { TestPaths } from '../test-data/utils'; import type { DebugOptions } from '../../src/types'; -import { LAUNCH_JSON_FILE } from '../../src/types'; +import { LAUNCH_JSON_FILE, ProjectDataSourceType } from '../../src/types'; import type { Logger } from '@sap-ux/logger'; -import { DatasourceType } from '@sap-ux/odata-service-inquirer'; import { t } from '../../src/i18n'; import { isFolderInWorkspace } from '../../src/debug-config/helpers'; @@ -188,7 +187,7 @@ describe('create', () => { name: 'test-projects', projectRoot: projectPath, debugOptions: { - datasourceType: DatasourceType.odataServiceUrl, + datasourceType: ProjectDataSourceType.odataServiceUrl, vscode: true } as DebugOptions }, @@ -258,7 +257,7 @@ describe('create', () => { name: 'test-projects', projectRoot: projectPath, debugOptions: { - datasourceType: DatasourceType.capProject, + datasourceType: ProjectDataSourceType.capProject, vscode: true } as DebugOptions }, @@ -281,7 +280,7 @@ describe('create', () => { name: 'test-projects', projectRoot: projectPath, debugOptions: { - datasourceType: DatasourceType.capProject, + datasourceType: ProjectDataSourceType.capProject, vscode: false } as DebugOptions }, @@ -310,7 +309,7 @@ describe('create', () => { name: 'test-projects', projectRoot: projectPath, debugOptions: { - datasourceType: DatasourceType.odataServiceUrl, + datasourceType: ProjectDataSourceType.odataServiceUrl, vscode: { workspace: { workspaceFile: { scheme: 'file' } @@ -390,7 +389,7 @@ describe('create', () => { name: 'test-projects', projectRoot: projectPath, debugOptions: { - datasourceType: DatasourceType.odataServiceUrl, + datasourceType: ProjectDataSourceType.odataServiceUrl, vscode: { workspace: { workspaceFile: { scheme: 'file' } diff --git a/packages/launch-config/tsconfig.json b/packages/launch-config/tsconfig.json index 4effa8f7dd..c8d9cee638 100644 --- a/packages/launch-config/tsconfig.json +++ b/packages/launch-config/tsconfig.json @@ -13,9 +13,6 @@ { "path": "../logger" }, - { - "path": "../odata-service-inquirer" - }, { "path": "../project-access" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 73194af42e..0c6d00baf9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1637,9 +1637,6 @@ importers: packages/launch-config: dependencies: - '@sap-ux/odata-service-inquirer': - specifier: workspace:* - version: link:../odata-service-inquirer '@sap-ux/project-access': specifier: workspace:* version: link:../project-access From b096887c700e257da395983042cdf0be1d4e750b Mon Sep 17 00:00:00 2001 From: I743583 Date: Tue, 17 Sep 2024 14:51:55 +0100 Subject: [PATCH 12/14] launch config review --- .../launch-config/src/debug-config/config.ts | 18 ++++++------ .../src/launch-config-crud/create.ts | 17 ++--------- packages/launch-config/src/types/constants.ts | 2 -- packages/launch-config/src/types/types.ts | 2 +- .../test/debug-config/config.test.ts | 13 +++------ .../test/debug-config/helpers.test.ts | 6 ++-- .../debug-config/workspaceManager.test.ts | 28 +++++++++---------- 7 files changed, 34 insertions(+), 52 deletions(-) diff --git a/packages/launch-config/src/debug-config/config.ts b/packages/launch-config/src/debug-config/config.ts index cc0b679eb5..4f7b8af968 100644 --- a/packages/launch-config/src/debug-config/config.ts +++ b/packages/launch-config/src/debug-config/config.ts @@ -1,7 +1,7 @@ import { basename } from 'path'; import { getLaunchConfig } from '../launch-config-crud/utils'; import type { LaunchConfig, LaunchJSON, DebugOptions, LaunchConfigEnv } from '../types'; -import { FIORI_TOOLS_LAUNCH_CONFIG_HANDLER_ID, ProjectDataSourceType, oDataVersionV2, oDataVersionV4 } from '../types'; +import { FIORI_TOOLS_LAUNCH_CONFIG_HANDLER_ID, ProjectDataSourceType } from '../types'; // debug constants const testFlpSandboxHtml = 'test/flpSandbox.html'; @@ -26,7 +26,7 @@ function getEnvUrlParams(sapClientParam: string): string { } /** - * Creates a launch configuration. + * Gets launch configuration. * * @param {string} name - The name of the configuration. * @param {string} cwd - The current working directory. @@ -36,7 +36,7 @@ function getEnvUrlParams(sapClientParam: string): string { * @param {string} [runConfig] - The optional run configuration for AppStudio. * @returns {LaunchConfig} The launch configuration object. */ -function createLaunchConfig( +function configureLaunchConfig( name: string, cwd: string, runtimeArgs: string[], @@ -88,7 +88,7 @@ export function configureLaunchJsonFile(rootFolder: string, cwd: string, configO // Add live configuration if the datasource is not from a metadata file if (datasourceType !== ProjectDataSourceType.metadataFile) { const startCommand = `${startHtmlFile}${flpAppIdWithHash}`; - const liveConfig = createLaunchConfig( + const liveConfig = configureLaunchConfig( `Start ${projectName}`, cwd, ['fiori', 'run'], @@ -100,13 +100,13 @@ export function configureLaunchJsonFile(rootFolder: string, cwd: string, configO } // Add mock configuration for OData V2 or V4 - if (odataVersion && [oDataVersionV2, oDataVersionV4].includes(odataVersion)) { + if (odataVersion && ['2.0', '4.0'].includes(odataVersion)) { const params = `${flpAppIdWithHash ?? ''}`; const mockCmdArgs = - isMigrator && odataVersion === oDataVersionV2 + isMigrator && odataVersion === '2.0' ? ['--open', `${testFlpSandboxMockServerHtml}${params}`] : ['--config', './ui5-mock.yaml', '--open', `${testFlpSandboxHtml}${params}`]; - const mockConfig = createLaunchConfig( + const mockConfig = configureLaunchConfig( `Start ${projectName} Mock`, cwd, ['fiori', 'run'], @@ -118,12 +118,12 @@ export function configureLaunchJsonFile(rootFolder: string, cwd: string, configO } // Add local configuration - const shouldUseMockServer = isFioriElement && odataVersion === oDataVersionV2 && isMigrator; + const shouldUseMockServer = isFioriElement && odataVersion === '2.0' && isMigrator; const localHtmlFile = shouldUseMockServer ? testFlpSandboxMockServerHtml : startHtmlFile; const startLocalCommand = `${localHtmlFile}${ migratorMockIntent ? `#${migratorMockIntent.replace('#', '')}` : flpAppIdWithHash }`; - const localConfig = createLaunchConfig( + const localConfig = configureLaunchConfig( `Start ${projectName} Local`, cwd, ['fiori', 'run'], diff --git a/packages/launch-config/src/launch-config-crud/create.ts b/packages/launch-config/src/launch-config-crud/create.ts index a1ca3ba24c..588c79eeec 100644 --- a/packages/launch-config/src/launch-config-crud/create.ts +++ b/packages/launch-config/src/launch-config-crud/create.ts @@ -26,16 +26,6 @@ function writeLaunchJsonFile(fs: Editor, launchJSONPath: string, configurations: fs.write(launchJSONPath, JSON.stringify(newLaunchJSONContent, null, 4)); } -/** - * Constructs the full path to the `launch.json` file based on the provided root folder. - * - * @param {string} rootFolder - The root directory where the `.vscode` folder is located. - * @returns {string} - The full path to the `launch.json` file. - */ -function getLaunchJsonPath(rootFolder: string): string { - return join(rootFolder, DirName.VSCode, LAUNCH_JSON_FILE); -} - /** * Handles the case where there are no debug options provided. It either enhances an existing `launch.json` * file with a new launch configuration or creates a new `launch.json` file with the initial configuration. @@ -47,7 +37,7 @@ function getLaunchJsonPath(rootFolder: string): string { * updated or created. */ async function handleNoDebugOptions(rootFolder: string, fioriOptions: FioriOptions, fs: Editor): Promise { - const launchJsonWritePath = getLaunchJsonPath(rootFolder); + const launchJsonWritePath = join(rootFolder, DirName.VSCode, LAUNCH_JSON_FILE); if (fs.exists(launchJsonWritePath)) { // launch.json exists, enhance existing file with new config const launchConfig = generateNewFioriLaunchConfig(rootFolder, fioriOptions); @@ -95,8 +85,7 @@ async function handleExistingLaunchJson( // replaceWithNew is needed in cases where launch config exists in // `.vscode` but isn't added to the workspace. If `replaceWithNew` is `true`, it indicates that the app is not // in the workspace, so the entire `launch.json` and replaced since launch config is then generated in app folder. - const newLaunchJSONContent = { version: '0.2.0', configurations }; - fs.write(launchJSONPath, JSON.stringify(newLaunchJSONContent, null, 4)); + writeLaunchJsonFile(fs, launchJSONPath, configurations); } else { for (const config of configurations) { await updateLaunchJSON( @@ -162,7 +151,7 @@ async function handleDebugOptions( npmCommand }) ); - const launchJsonWritePath = getLaunchJsonPath(launchJsonPath); + const launchJsonWritePath = join(launchJsonPath, DirName.VSCode, LAUNCH_JSON_FILE); if (fs.exists(launchJsonWritePath)) { await handleExistingLaunchJson(fs, launchJsonWritePath, configurations, appNotInWorkspace); } else { diff --git a/packages/launch-config/src/types/constants.ts b/packages/launch-config/src/types/constants.ts index 87cb457b31..0f54b94c7f 100644 --- a/packages/launch-config/src/types/constants.ts +++ b/packages/launch-config/src/types/constants.ts @@ -1,5 +1,3 @@ export const FIORI_TOOLS_LAUNCH_CONFIG_HANDLER_ID = 'fiori_tools'; export const LAUNCH_JSON_FILE = 'launch.json'; export const RUN_SCRIPT = 'run-script'; -export const oDataVersionV2: string = '2', - oDataVersionV4: string = '4'; diff --git a/packages/launch-config/src/types/types.ts b/packages/launch-config/src/types/types.ts index 3e43f6dd91..9a6801d319 100644 --- a/packages/launch-config/src/types/types.ts +++ b/packages/launch-config/src/types/types.ts @@ -84,7 +84,7 @@ export interface DebugOptions { /** Indicates if the FLP sandbox environment is available. */ flpSandboxAvailable: boolean; /** Version of the OData service. */ - odataVersion?: string; + odataVersion?: ODataVersion; /** Indicates if the project is a Fiori Element. */ isFioriElement?: boolean; /** Intent parameter for the migrator mock. */ diff --git a/packages/launch-config/test/debug-config/config.test.ts b/packages/launch-config/test/debug-config/config.test.ts index a632a060d9..d7142587d4 100644 --- a/packages/launch-config/test/debug-config/config.test.ts +++ b/packages/launch-config/test/debug-config/config.test.ts @@ -1,12 +1,7 @@ import { configureLaunchJsonFile } from '../../src/debug-config/config'; import type { DebugOptions, LaunchConfig, LaunchJSON } from '../../src/types'; import path from 'path'; -import { - FIORI_TOOLS_LAUNCH_CONFIG_HANDLER_ID, - ProjectDataSourceType, - oDataVersionV2, - oDataVersionV4 -} from '../../src/types'; +import { FIORI_TOOLS_LAUNCH_CONFIG_HANDLER_ID, ProjectDataSourceType } from '../../src/types'; const projectName = 'project1'; const cwd = `\${workspaceFolder}`; @@ -61,7 +56,7 @@ describe('debug config tests', () => { beforeEach(() => { configOptions = { vscode: vscodeMock, - odataVersion: oDataVersionV2, + odataVersion: '2.0', sapClientParam: '', flpAppId: 'project1-tile', isFioriElement: true, @@ -85,7 +80,7 @@ describe('debug config tests', () => { }); it('Should return the correct configuration for OData v4', () => { - configOptions.odataVersion = oDataVersionV4; + configOptions.odataVersion = '4.0'; const launchFile = configureLaunchJsonFile(projectPath, cwd, configOptions); expect(launchFile.configurations.length).toBe(3); @@ -137,7 +132,7 @@ describe('debug config tests', () => { }); it('Should return correct configuration on BAS and sapClientParam is available', () => { - configOptions.odataVersion = oDataVersionV2; + configOptions.odataVersion = '2.0'; configOptions.datasourceType = ProjectDataSourceType.odataServiceUrl; configOptions.sapClientParam = 'sapClientParam'; configOptions.isAppStudio = true; diff --git a/packages/launch-config/test/debug-config/helpers.test.ts b/packages/launch-config/test/debug-config/helpers.test.ts index 2445185ace..61be487724 100644 --- a/packages/launch-config/test/debug-config/helpers.test.ts +++ b/packages/launch-config/test/debug-config/helpers.test.ts @@ -95,7 +95,7 @@ describe('launchConfig Unit Tests', () => { // Test for create launch config outside workspace describe('handleAppsNotInWorkspace', () => { it('should create a launch config for non-workspace apps', () => { - const mockProjectPath = '/mock/project/path'; + const mockProjectPath = path.join('/mock/project/path'); const result = handleAppsNotInWorkspace(mockProjectPath, isAppStudio, mockVscode); expect(result.cwd).toBe('${workspaceFolder}'); expect(result.launchJsonPath).toBe( @@ -107,7 +107,7 @@ describe('launchConfig Unit Tests', () => { }); it('should handle cases where vscode.Uri is not available', () => { - const mockProjectPath = '/mock/project/path'; + const mockProjectPath = path.join('/mock/project/path'); const result = handleAppsNotInWorkspace(mockProjectPath, isAppStudio, {}); expect(result.cwd).toBe('${workspaceFolder}'); expect(result.launchJsonPath).toBe( @@ -117,7 +117,7 @@ describe('launchConfig Unit Tests', () => { }); it('should handle cases where isAppStudio is true', () => { - const mockProjectPath = '/mock/project/path', + const mockProjectPath = path.join('/mock/project/path'), isAppStudio = true; const result = handleAppsNotInWorkspace(mockProjectPath, isAppStudio, mockVscode); expect(result.cwd).toBe('${workspaceFolder}'); diff --git a/packages/launch-config/test/debug-config/workspaceManager.test.ts b/packages/launch-config/test/debug-config/workspaceManager.test.ts index e56a6c55d6..d91b03163b 100644 --- a/packages/launch-config/test/debug-config/workspaceManager.test.ts +++ b/packages/launch-config/test/debug-config/workspaceManager.test.ts @@ -41,7 +41,7 @@ describe('launchConfig Unit Tests', () => { describe('handleOpenFolderButNoWorkspaceFile', () => { it('should create a launch config for non-workspace apps if folder is not in workspace', () => { - const mockProjectPath = '/mock/project/path'; + const mockProjectPath = path.join('/mock/project/path'); (isFolderInWorkspace as jest.Mock).mockReturnValue(false); (handleAppsNotInWorkspace as jest.Mock).mockReturnValue({ launchJsonPath: mockProjectPath, @@ -61,8 +61,8 @@ describe('launchConfig Unit Tests', () => { }); it('should update paths for nested folders inside an open folder', () => { - const mockProjectPath = '/mock/project/nestedFolder'; - const mockTargetFolder = '/target/folder'; + const mockProjectPath = path.join('/mock/project/nestedFolder'); + const mockTargetFolder = path.join('/target/folder'); const mockNestedFolder = 'nestedFolder'; (isFolderInWorkspace as jest.Mock).mockReturnValue(true); @@ -85,8 +85,8 @@ describe('launchConfig Unit Tests', () => { describe('handleSavedWorkspace', () => { it('should handle projects inside the workspace', () => { - const mockProjectPath = '/mock/project/path'; - const mockTargetFolder = '/target/folder'; + const mockProjectPath = path.join('/mock/project/path'); + const mockTargetFolder = path.join('/target/folder'); (isFolderInWorkspace as jest.Mock).mockReturnValue(true); (formatCwd as jest.Mock).mockReturnValue('${workspaceFolder}/project'); (getLaunchJsonPath as jest.Mock).mockReturnValue(mockTargetFolder); @@ -103,7 +103,7 @@ describe('launchConfig Unit Tests', () => { }); it('should create a launch config for non-workspace apps', () => { - const mockProjectPath = '/mock/project/path'; + const mockProjectPath = path.join('/mock/project/path'); (isFolderInWorkspace as jest.Mock).mockReturnValue(false); (handleAppsNotInWorkspace as jest.Mock).mockReturnValue({ launchJsonPath: mockProjectPath, @@ -124,8 +124,8 @@ describe('launchConfig Unit Tests', () => { describe('handleUnsavedWorkspace', () => { it('should update paths for nested folders inside a workspace', () => { - const mockProjectPath = '/mock/project/nestedFolder'; - const mockWsFolder = '/mock/workspace/folder'; + const mockProjectPath = path.join('mock/project/configureLaunchConfig'); + const mockWsFolder = path.join('mock/workspace/folder'); const mockNestedFolder = 'nestedFolder'; mockVscode.workspace.getWorkspaceFolder.mockReturnValue({ uri: { fsPath: mockWsFolder } }); mockVscode.workspace.workspaceFile.scheme = 'folder'; @@ -144,7 +144,7 @@ describe('launchConfig Unit Tests', () => { describe('handleWorkspaceConfig', () => { it('should handle writeToAppOnly option', () => { - const mockProjectPath = '/mock/project/path'; + const mockProjectPath = path.join('/mock/project/path'); const options = { writeToAppOnly: true, vscode: mockVscode @@ -164,8 +164,8 @@ describe('launchConfig Unit Tests', () => { }); it('should handle open folder but no workspace file case', () => { - const mockProjectPath = '/mock/project/path'; - const mockTargetFolder = '/target/folder'; + const mockProjectPath = path.join('/mock/project/path'); + const mockTargetFolder = path.join('/target/folder'); const options = { vscode: { ...mockVscode, @@ -196,7 +196,7 @@ describe('launchConfig Unit Tests', () => { }); it('should handle no workspace case', () => { - const mockProjectPath = '/mock/project/path'; + const mockProjectPath = path.join('/mock/project/path'); const options = { vscode: { ...mockVscode, workspace: undefined } } as DebugOptions; @@ -214,8 +214,8 @@ describe('launchConfig Unit Tests', () => { }); it('should handle saved workspace case', () => { - const mockProjectPath = '/mock/project/path'; - const mockTargetFolder = '/target/folder'; + const mockProjectPath = path.join('/mock/project/path'); + const mockTargetFolder = path.join('/target/folder'); const mockVscode = { workspace: { getWorkspaceFolder: jest.fn().mockReturnValue({ uri: { fsPath: mockTargetFolder } }), From aa345d725e8a3860eb63b446e2852f77c3328833 Mon Sep 17 00:00:00 2001 From: kitzkan Date: Wed, 18 Sep 2024 07:57:49 +0100 Subject: [PATCH 13/14] Update project data source types in types.ts --- packages/launch-config/src/types/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/launch-config/src/types/types.ts b/packages/launch-config/src/types/types.ts index 9a6801d319..5e6e44fd4d 100644 --- a/packages/launch-config/src/types/types.ts +++ b/packages/launch-config/src/types/types.ts @@ -67,7 +67,6 @@ export interface LaunchConfigInfo { export enum ProjectDataSourceType { capProject = 'capProject', odataServiceUrl = 'odataServiceUrl', - none = 'none', metadataFile = 'metadataFile' } From ce744d33b3abda964b3237c42d8a4d30ec23b187 Mon Sep 17 00:00:00 2001 From: I743583 Date: Wed, 18 Sep 2024 18:47:22 +0100 Subject: [PATCH 14/14] fixing lint issues --- packages/launch-config/src/debug-config/config.ts | 2 +- .../src/debug-config/workspaceManager.ts | 2 +- .../launch-config/src/launch-config-crud/create.ts | 14 +++++++------- .../test/launch-config-crud/update.test.ts | 3 ++- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/launch-config/src/debug-config/config.ts b/packages/launch-config/src/debug-config/config.ts index 4f7b8af968..7e6c6bbf28 100644 --- a/packages/launch-config/src/debug-config/config.ts +++ b/packages/launch-config/src/debug-config/config.ts @@ -55,7 +55,7 @@ function configureLaunchConfig( /** * Configures the launch.json file based on provided options. * - * @param rootFolder + * @param rootFolder - The root folder path where the app will be generated. * @param {string} cwd - The current working directory. * @param {DebugOptions} configOpts - Configuration options for the launch.json file. * @returns {LaunchJSON} The configured launch.json object. diff --git a/packages/launch-config/src/debug-config/workspaceManager.ts b/packages/launch-config/src/debug-config/workspaceManager.ts index 4c28c771b1..6222d65010 100644 --- a/packages/launch-config/src/debug-config/workspaceManager.ts +++ b/packages/launch-config/src/debug-config/workspaceManager.ts @@ -83,7 +83,7 @@ function handleOpenFolderButNoWorkspaceFile( * This function handles different scenarios depending on whether a workspace is open, * whether the project is inside or outside of a workspace, and other factors. * - * @param rootFolder + * @param rootFolder - The root folder path where the app will be generated. * @param {DebugOptions} options - The options used to determine how to manage the workspace configuration. * @param {string} options.projectPath -The project's path including project name. * @param {boolean} [options.isAppStudio] - A boolean indicating whether the current environment is BAS. diff --git a/packages/launch-config/src/launch-config-crud/create.ts b/packages/launch-config/src/launch-config-crud/create.ts index 588c79eeec..d21a715bd4 100644 --- a/packages/launch-config/src/launch-config-crud/create.ts +++ b/packages/launch-config/src/launch-config-crud/create.ts @@ -128,7 +128,7 @@ function updateWorkspaceFoldersIfNeeded(updateWorkspaceFolders?: UpdateWorkspace * @param {Editor} fs - The file system editor to read and write the `launch.json` file. * @param {DebugOptions} debugOptions - Debug configuration options that dictate how the `launch.json` * should be generated and what commands should be logged. - * @param {Logger} log - Logger instance for logging information or warnings. + * @param {Logger} logger - Logger instance for logging information or warnings. * @returns {Promise} - Returns the file system editor after potentially modifying the workspace * and updating or creating the `launch.json` file. */ @@ -136,7 +136,7 @@ async function handleDebugOptions( rootFolder: string, fs: Editor, debugOptions: DebugOptions, - log?: Logger + logger?: Logger ): Promise { const { launchJsonPath, workspaceFolderUri, cwd, appNotInWorkspace } = handleWorkspaceConfig( rootFolder, @@ -145,7 +145,7 @@ async function handleDebugOptions( const configurations = configureLaunchJsonFile(rootFolder, cwd, debugOptions).configurations; const npmCommand = debugOptions.datasourceType === ProjectDataSourceType.metadataFile ? 'run start-mock' : 'start'; - log?.info( + logger?.info( t('startServerMessage', { folder: basename(rootFolder), npmCommand @@ -179,14 +179,14 @@ async function handleDebugOptions( * @param rootFolder - workspace root folder. * @param fioriOptions - options for the new launch config. * @param fs - optional, the memfs editor instance. - * @param log + * @param logger - optional, the logger instance. * @returns memfs editor instance. */ export async function createLaunchConfig( rootFolder: string, fioriOptions: FioriOptions, fs?: Editor, - log?: Logger + logger?: Logger ): Promise { fs = fs ?? create(createStorage()); const debugOptions = fioriOptions.debugOptions; @@ -197,8 +197,8 @@ export async function createLaunchConfig( return fs; } if (debugOptions.datasourceType === ProjectDataSourceType.capProject) { - log?.info(t('startApp', { npmStart: '`npm start`', cdsRun: '`cds run --in-memory`' })); + logger?.info(t('startApp', { npmStart: '`npm start`', cdsRun: '`cds run --in-memory`' })); return fs; } - return await handleDebugOptions(rootFolder, fs, debugOptions, log); + return await handleDebugOptions(rootFolder, fs, debugOptions, logger); } diff --git a/packages/launch-config/test/launch-config-crud/update.test.ts b/packages/launch-config/test/launch-config-crud/update.test.ts index 8eb1ab12da..a4a328542e 100644 --- a/packages/launch-config/test/launch-config-crud/update.test.ts +++ b/packages/launch-config/test/launch-config-crud/update.test.ts @@ -5,6 +5,7 @@ import { create } from 'mem-fs-editor'; import { createLaunchConfig, LAUNCH_JSON_FILE, updateLaunchConfig } from '../../src'; import { TestPaths } from '../test-data/utils'; import { parse } from 'jsonc-parser'; +import type { Editor } from 'mem-fs-editor'; function checkJSONComments(launchJsonString: string) { expect(launchJsonString).toMatch('// test json with comments - comment 1'); @@ -34,7 +35,7 @@ describe('update', () => { test('Create and then update existing launch config in launch.json', async (): Promise => { // create a new const launchJSONPath = join(TestPaths.feProjectsLaunchConfig); - let result: any = await createLaunchConfig( + let result: Editor = await createLaunchConfig( TestPaths.feProjects, { name: 'LaunchConfig_One',