diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c47f594..5abcdf2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,7 @@ jobs: - run: npm i -g @sap/cds-dk@${{ matrix.cds-version }} - run: npm i - run: npm run build - - run: cd tests/bookshop && npm i && npm run build + - run: cd tests/bookshop && npm run build - run: npm run test # integration-tests: # runs-on: ubuntu-latest diff --git a/cds-plugin.ts b/cds-plugin.ts index b179f12..83034a7 100644 --- a/cds-plugin.ts +++ b/cds-plugin.ts @@ -29,6 +29,10 @@ cds.build?.register?.('process-validation', ProcessValidationPlugin); // Register import handler for: cds import --from process // @ts-expect-error: import does not exist on cds type cds.import ??= {}; +//@ts-expect-error: cds type does not exist +cds.import.options ??= {}; +//@ts-expect-error: cds type does not exist +cds.import.options.process = { no_copy: true, as: 'cds', config: 'kind=process-service' }; // @ts-expect-error: process does not exist on cds.import type cds.import.from ??= {}; // @ts-expect-error: from does not exist on cds.import type diff --git a/lib/processImport.ts b/lib/processImport.ts index 314ca5d..0e8bec2 100644 --- a/lib/processImport.ts +++ b/lib/processImport.ts @@ -79,9 +79,6 @@ async function fetchAndSaveProcessDefinition(processName: string): Promise { const processHeader = loadProcessHeader(jsonFilePath); const csnModel = buildCsnModel(processHeader); - // Register service in package.json for local imports too - const serviceName = `${processHeader.projectId}.${capitalize(processHeader.identifier)}Service`; - const modelPath = getModelPathFromFilePath(jsonFilePath); - await addServiceToPackageJson(serviceName, modelPath); - return csnModel; } -/** - * Convert absolute/relative file path to model path for package.json - * e.g., "./srv/external/foo.json" -> "srv/external/foo" - * "/abs/path/srv/external/foo.json" -> "srv/external/foo" - */ -function getModelPathFromFilePath(filePath: string): string { - // Resolve to absolute, then make relative to cds.root - const absolutePath = path.resolve(filePath); - let relativePath = path.relative(cds.root, absolutePath); - - // Remove .json extension - if (relativePath.endsWith('.json')) { - relativePath = relativePath.slice(0, -5); - } - - // Normalize path separators - relativePath = relativePath.replace(/\\/g, '/'); - - // Replace "workflows" prefix with "srv/external" - if (relativePath.startsWith('workflows/')) { - relativePath = 'srv/external/' + relativePath.slice('workflows/'.length); - } - - return relativePath; -} - function loadProcessHeader(filePath: string): ProcessHeader { const content = fs.readFileSync(path.resolve(filePath), 'utf-8'); const header = JSON.parse(content) as ProcessHeader; @@ -175,7 +141,7 @@ function buildCsnModel(process: ProcessHeader): csn.CsnModel { return { $version: '2.0', definitions, - meta: { creator: 'cds-import-process' }, + meta: { creator: '@cap-js/process' }, }; } @@ -562,28 +528,6 @@ function ensureObjectSchema(schema?: JsonSchema): JsonSchema { return { type: 'object', properties: {}, required: [] }; } -// ============================================================================ -// PACKAGE.JSON UPDATE -// ============================================================================ - -async function addServiceToPackageJson(serviceName: string, modelPath: string): Promise { - const packagePath = path.join(cds.root, 'package.json'); - - try { - const content = await fs.promises.readFile(packagePath, 'utf8'); - const pkg = JSON.parse(content); - - pkg.cds ??= {}; - pkg.cds.requires ??= {}; - pkg.cds.requires[serviceName] = { kind: 'external', model: modelPath }; - - await fs.promises.writeFile(packagePath, JSON.stringify(pkg, null, 2) + '\n', 'utf8'); - LOG.debug(`Added ${serviceName} to package.json`); - } catch (error) { - LOG.warn(`Could not update package.json: ${error}`); - } -} - // ============================================================================ // UTILITIES // ============================================================================ diff --git a/package.json b/package.json index 107b150..5a8d0a1 100644 --- a/package.json +++ b/package.json @@ -32,9 +32,9 @@ "tests/bookshop" ], "dependencies": { - "@sap-cloud-sdk/connectivity": "^4.1.2", - "@sap-cloud-sdk/http-client": "^4.1.2", - "@sap-cloud-sdk/resilience": "^4.1.2" + "@sap-cloud-sdk/connectivity": "^4.5.1", + "@sap-cloud-sdk/http-client": "^4.5.1", + "@sap-cloud-sdk/resilience": "^4.5.1" }, "cds": { "requires": { @@ -42,6 +42,9 @@ "[development]": { "kind": "local-process-service" }, + "[hybrid]": { + "kind": "deployed-process-service" + }, "[production]": { "kind": "deployed-process-service" } @@ -63,13 +66,13 @@ }, "devDependencies": { "@cap-js/cds-test": "^0.4", - "@cap-js/cds-types": "^0.15.0", + "@cap-js/cds-types": "^0.16.0", "@types/jest": "^30.0.0", - "@types/node": "^24.0.0", - "jest": "^30.2.0", + "@types/node": "^25.5.0", + "jest": "^30.3.0", "ts-jest": "^29.4.6", "tsx": "^4", "typescript": "^5", - "typescript-eslint": "^8.56.1" + "typescript-eslint": "^8.57.0" } } diff --git a/tests/bookshop/package.json b/tests/bookshop/package.json index edc39e5..4697be5 100644 --- a/tests/bookshop/package.json +++ b/tests/bookshop/package.json @@ -8,10 +8,10 @@ "devDependencies": { "@cap-js/sqlite": "^2", "tsx": "^4", - "@cap-js/cds-types": "^0.15.0", - "@types/node": "^24.0.0", + "@cap-js/cds-types": "^0.16.0", + "@types/node": "^25.5.0", "typescript": "^5", - "@cap-js/cds-typer": ">=0.1" + "@cap-js/cds-typer": ">=0.38" }, "scripts": { "start": "cds-serve", @@ -31,7 +31,7 @@ } }, "eu12.bpm-horizon-walkme.sdshipmentprocessor.ShipmentHandlerService": { - "kind": "external", + "kind": "process-service", "model": "srv/external/eu12.bpm-horizon-walkme.sdshipmentprocessor.shipmentHandler" } } diff --git a/tests/bookshop/srv/external/eu12.bpm-horizon-walkme.sdshipmentprocessor.shipmentHandler.cds b/tests/bookshop/srv/external/eu12.bpm-horizon-walkme.sdshipmentprocessor.shipmentHandler.cds index 6c08660..94ea8cf 100644 --- a/tests/bookshop/srv/external/eu12.bpm-horizon-walkme.sdshipmentprocessor.shipmentHandler.cds +++ b/tests/bookshop/srv/external/eu12.bpm-horizon-walkme.sdshipmentprocessor.shipmentHandler.cds @@ -94,4 +94,3 @@ service ShipmentHandlerService { cascade : Boolean ); }; - diff --git a/tests/integration/process-import/process-import.test.ts b/tests/integration/process-import/process-import.test.ts index 2df70ae..154beb8 100644 --- a/tests/integration/process-import/process-import.test.ts +++ b/tests/integration/process-import/process-import.test.ts @@ -363,92 +363,6 @@ describe('Process Import Integration Tests', () => { }); }); - describe('Package.json Update', () => { - it('should add service to package.json with kind external', async () => { - const targetPath = path.join(tempDir, 'srv', 'external', 'test.project.simpleProcess.json'); - await fs.promises.copyFile(simpleProcessPath, targetPath); - - await importProcess(targetPath); - - const packageJsonPath = path.join(tempDir, 'package.json'); - const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, 'utf8')); - - expect(packageJson.cds).toBeDefined(); - expect(packageJson.cds.requires).toBeDefined(); - expect(packageJson.cds.requires['test.project.SimpleProcessService']).toBeDefined(); - expect(packageJson.cds.requires['test.project.SimpleProcessService'].kind).toBe('external'); - expect(packageJson.cds.requires['test.project.SimpleProcessService'].model).toBe( - 'srv/external/test.project.simpleProcess', - ); - }); - - it('should compute correct model path from absolute file path', async () => { - const targetPath = path.join(tempDir, 'srv', 'external', 'my.custom.path.json'); - await fs.promises.copyFile(simpleProcessPath, targetPath); - - await importProcess(targetPath); - - const packageJsonPath = path.join(tempDir, 'package.json'); - const packageJson = JSON.parse(await fs.promises.readFile(packageJsonPath, 'utf8')); - - expect(packageJson.cds.requires['test.project.SimpleProcessService'].model).toBe( - 'srv/external/my.custom.path', - ); - }); - - it('should preserve existing package.json content', async () => { - const existingPackageJson = { - name: 'test-project', - version: '1.0.0', - dependencies: { '@sap/cds': '^7.0.0' }, - cds: { - requires: { - ExistingService: { kind: 'external', model: 'srv/existing' }, - }, - }, - }; - await fs.promises.writeFile( - path.join(tempDir, 'package.json'), - JSON.stringify(existingPackageJson, null, 2), - ); - - const targetPath = path.join(tempDir, 'srv', 'external', 'test.json'); - await fs.promises.copyFile(simpleProcessPath, targetPath); - - await importProcess(targetPath); - - const packageJson = JSON.parse( - await fs.promises.readFile(path.join(tempDir, 'package.json'), 'utf8'), - ); - - expect(packageJson.name).toBe('test-project'); - expect(packageJson.dependencies['@sap/cds']).toBe('^7.0.0'); - expect(packageJson.cds.requires['ExistingService']).toBeDefined(); - expect(packageJson.cds.requires['test.project.SimpleProcessService']).toBeDefined(); - }); - - it('should create cds.requires if not present', async () => { - const packageJson = { name: 'test-project', version: '1.0.0' }; - await fs.promises.writeFile( - path.join(tempDir, 'package.json'), - JSON.stringify(packageJson, null, 2), - ); - - const targetPath = path.join(tempDir, 'srv', 'external', 'test.json'); - await fs.promises.copyFile(simpleProcessPath, targetPath); - - await importProcess(targetPath); - - const updatedPackageJson = JSON.parse( - await fs.promises.readFile(path.join(tempDir, 'package.json'), 'utf8'), - ); - - expect(updatedPackageJson.cds).toBeDefined(); - expect(updatedPackageJson.cds.requires).toBeDefined(); - expect(updatedPackageJson.cds.requires['test.project.SimpleProcessService']).toBeDefined(); - }); - }); - describe('Edge Cases', () => { it('should handle process with empty inputs', async () => { const emptyInputsProcess = {