Skip to content
Open
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
577a5ff
First modifications: ESM support for OData
BrigittaK307 Sep 16, 2025
825ad4b
Added one test case for ESM
BrigittaK307 Sep 17, 2025
18e6d88
Merge branch 'main' of https://github.com/SAP/cloud-sdk-js into I7533…
BrigittaK307 Oct 14, 2025
b03b119
Added ESM flag and parsed it in the neccessary functions
BrigittaK307 Oct 14, 2025
a663cd8
Added changeset file
BrigittaK307 Oct 14, 2025
a10d026
Modified changeset file
BrigittaK307 Oct 14, 2025
7d0eb8c
Merge branch 'main' into I753325-esm-support-oData
KavithaSiva Oct 16, 2025
bce7ee0
undo esm config settings
deekshas8 Oct 16, 2025
ed83c7e
Added ESM support for the remaining files and corrected the changeset…
BrigittaK307 Oct 17, 2025
fbdb198
Fixed pipeline issues
BrigittaK307 Oct 17, 2025
87e14af
Changes from lint:fix
Oct 17, 2025
0b5deb7
Deleted ESM flag, reverted index.js file
BrigittaK307 Oct 17, 2025
f81eb21
Merge branch 'I753325-esm-support-oData' of https://github.com/SAP/cl…
BrigittaK307 Oct 17, 2025
240c706
Changes from lint:fix
Oct 17, 2025
2ea6550
Merge branch 'main' into I753325-esm-support-oData
deekshas8 Oct 17, 2025
8f8fe0a
Solved PR comments
BrigittaK307 Oct 22, 2025
e0cf04c
Reverted generator file and made tsConfig common for openapi and gene…
BrigittaK307 Oct 23, 2025
708b257
Apply suggestion from @deekshas8
BrigittaK307 Oct 24, 2025
421ced1
Apply suggestion from @deekshas8
BrigittaK307 Oct 24, 2025
dee4c61
Apply suggestion from @deekshas8
BrigittaK307 Oct 24, 2025
f1024fe
Merge branch 'main' into I753325-esm-support-oData
deekshas8 Oct 27, 2025
2641470
Modified tsConfig structure, tests and solved PR comments
BrigittaK307 Oct 27, 2025
d318346
Merge branch 'I753325-esm-support-oData' of https://github.com/SAP/cl…
BrigittaK307 Oct 27, 2025
adc174e
Solved linter issues
BrigittaK307 Oct 27, 2025
7b3184f
Changes from lint:fix
Oct 27, 2025
0ceb080
Code refactoring and modification of tests
BrigittaK307 Oct 28, 2025
ae84e7c
Merge branch 'I753325-esm-support-oData' of https://github.com/SAP/cl…
BrigittaK307 Oct 28, 2025
91d6d77
Solved linter issues
BrigittaK307 Oct 28, 2025
ed29e9d
Changes from lint:fix
Oct 28, 2025
298cb52
Solved errors from pipelines
BrigittaK307 Oct 28, 2025
fe22f4d
Merge branch 'I753325-esm-support-oData' of https://github.com/SAP/cl…
BrigittaK307 Oct 28, 2025
4a1554e
Changes from lint:fix
Oct 28, 2025
4eb7c0b
Merge branch 'main' into I753325-esm-support-oData
deekshas8 Nov 11, 2025
b58ddcc
Moved module type and renamed test cases
BrigittaK307 Nov 12, 2025
59a79c5
Merge branch 'I753325-esm-support-oData' of https://github.com/SAP/cl…
BrigittaK307 Nov 12, 2025
6f1324a
Changes from lint:fix
Nov 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/honest-candles-kick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@sap-cloud-sdk/generator': minor
'@sap-cloud-sdk/generator-common': minor
---

[New Functionality] Introduce option `generateESM` in OData generator to generate ESM compatible code.
21 changes: 20 additions & 1 deletion .github/actions/check-public-api/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion packages/generator-common/src/file-writer/package-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export interface PackageJsonOptions {
* @internal
*/
description: string;
/**
* @internal
*/
moduleType?: 'commonjs' | 'esm';
}

/* eslint-disable valid-jsdoc */
Expand All @@ -23,7 +27,7 @@ export interface PackageJsonOptions {
export function packageJsonBase(
options: PackageJsonOptions
): Record<string, any> {
return {
const basePackageJson: Record<string, any> = {
name: options.npmPackageName,
version: '1.0.0',
description: options.description,
Expand All @@ -39,4 +43,11 @@ export function packageJsonBase(
url: ''
}
};

if (options.moduleType === 'esm') {
basePackageJson.type = 'module';
basePackageJson.main = './index.mjs';
}

return basePackageJson;
}
4 changes: 4 additions & 0 deletions packages/generator-common/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,8 @@ export interface CommonGeneratorOptions {
* Generate default `README.md` files in the client directories.
*/
readme?: boolean;
/**
* Generate ECMAScript modules instead of CommonJS modules.
*/
generateESM?: boolean;
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
import { defaultTsConfig } from '@sap-cloud-sdk/generator-common/internal';
import mock from 'mock-fs';
import { tsconfigJson } from './tsconfig-json';
import type { ParsedGeneratorOptions } from './options';
import { defaultTsConfig, tsconfigJson } from './ts-config';

describe('tsconfigJson', () => {
afterEach(() => {
mock.restore();
});

it('returns the default tsconfig if transpilation is enabled', async () => {
const tsConfig = await tsconfigJson({
transpile: true
} as ParsedGeneratorOptions);
const tsConfig = await tsconfigJson(true, undefined);
expect(JSON.parse(tsConfig!)).toEqual(defaultTsConfig);
});

it('returns undefined if transpilation is disabled', async () => {
const tsConfig = await tsconfigJson({
transpile: false
} as ParsedGeneratorOptions);
const tsConfig = await tsconfigJson(false, undefined);
expect(tsConfig).toBeUndefined();
});

Expand All @@ -29,9 +23,7 @@ describe('tsconfigJson', () => {
'customConfig.json': JSON.stringify(customConfig)
}
});
const tsConfig = await tsconfigJson({
tsconfig: './path/customConfig.json'
} as ParsedGeneratorOptions);
const tsConfig = await tsconfigJson(false, './path/customConfig.json');
expect(JSON.parse(tsConfig!)).toEqual(customConfig);
});

Expand All @@ -42,18 +34,14 @@ describe('tsconfigJson', () => {
'tsconfig.json': JSON.stringify(customConfig)
}
});
const tsConfig = await tsconfigJson({
tsconfig: './path'
} as ParsedGeneratorOptions);
const tsConfig = await tsconfigJson(false, './path');
expect(JSON.parse(tsConfig!)).toEqual(customConfig);
});

it('returns custom config content if custom file or directory does not exist', async () => {
mock({});
await expect(() =>
tsconfigJson({
tsconfig: './path'
} as ParsedGeneratorOptions)
).rejects.toThrow('Could not read tsconfig.json at ./path.');
await expect(() => tsconfigJson(false, './path')).rejects.toThrow(
'Could not read tsconfig.json at ./path.'
);
});
});
18 changes: 17 additions & 1 deletion packages/generator-common/src/ts-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { promises } from 'fs';
import { resolve } from 'path';
import { unixEOL, ErrorWithCause } from '@sap-cloud-sdk/util';
const { readFile, lstat } = promises;

/**
* @internal
*/
Expand Down Expand Up @@ -46,3 +45,20 @@ export async function readCustomTsConfig(configPath: string): Promise<string> {
);
}
}

/**
* Build a tsconfig.json file as string.
* If transpile is true or tsconfig is provided, return the appropriate config.
* @param transpile - Whether to transpile.
* @param tsconfig - Path to custom tsconfig file.
* @returns The serialized tsconfig.json contents.
* @internal
*/
export async function tsconfigJson(
transpile: boolean,
tsconfig: string | undefined
): Promise<string | undefined> {
if (transpile || tsconfig) {
return tsconfig ? readCustomTsConfig(tsconfig) : formatTsConfig();
}
}
19 changes: 4 additions & 15 deletions packages/generator/.nycrc
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@

{
"extension": [
".ts"
],
"include": [
"src/**/*"
],
"exclude": [
"**/*.d.ts"
],
"reporter": [
"cobertura",
"html",
"text-summary"
],
"extension": [".ts"],
"include": ["src/**/*"],
"exclude": ["**/*.d.ts"],
"reporter": ["cobertura", "html", "text-summary"],
"all": true
}
4 changes: 4 additions & 0 deletions packages/generator/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<!-- sap-cloud-sdk-logo -->
<!-- This block is inserted by scripts/replace-common-readme.ts. Do not adjust it manually. -->

<a href="https://sap.github.io/cloud-sdk/docs/js/overview"><img src="https://help.sap.com/doc/2324e9c3b28748a4ae2ad08166d77675/1.0/en-US/logo-with-js.svg" alt="SAP Cloud SDK for JavaScript Logo" height="122.92" width="226.773"/></a>

<!-- sap-cloud-sdk-logo-stop -->

# @sap-cloud-sdk/generator
Expand Down Expand Up @@ -41,6 +43,7 @@ For more detailed overview visit our [generator documentation](https://sap.githu

<!-- sap-cloud-sdk-common-readme -->
<!-- This block is inserted by scripts/replace-common-readme.ts. Do not adjust it manually. -->

## Support

The recommended way to get in touch with us is to create an issue on [GitHub](https://github.com/SAP/cloud-sdk-js/issues).
Expand Down Expand Up @@ -68,4 +71,5 @@ If you would like to contribute to the SAP Cloud SDK, please make yourself famil
## License

The SAP Cloud SDK is released under the [Apache License Version 2.0.](http://www.apache.org/licenses/)

<!-- sap-cloud-sdk-common-readme-stop -->
6 changes: 4 additions & 2 deletions packages/generator/src/batch/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import { importBatchDeclarations } from './imports';
import { readRequestType, writeRequestType } from './type';
import type { VdmServiceMetadata } from '../vdm-types';
import type { SourceFileStructure } from 'ts-morph';
import type { CreateFileOptions } from '@sap-cloud-sdk/generator-common/internal';

/**
* @internal
*/
export function batchSourceFile(
service: VdmServiceMetadata
service: VdmServiceMetadata,
options?: CreateFileOptions
): SourceFileStructure {
return {
kind: StructureKind.SourceFile,
statements: [
...importBatchDeclarations(service),
...importBatchDeclarations(service, options),
batchFunction(service),
changesetFunction(service),
`export const default${service.className}Path = '${service.serviceOptions.basePath}';`,
Expand Down
6 changes: 4 additions & 2 deletions packages/generator/src/batch/imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import { unique } from '@sap-cloud-sdk/util';
import { odataImportDeclarationTsMorph } from '../imports';
import type { ImportDeclarationStructure } from 'ts-morph';
import type { VdmServiceMetadata } from '../vdm-types';
import type { CreateFileOptions } from '@sap-cloud-sdk/generator-common/internal';

/**
* @internal
*/
export function importBatchDeclarations(
service: VdmServiceMetadata
service: VdmServiceMetadata,
options?: CreateFileOptions
): ImportDeclarationStructure[] {
return [
odataImportDeclarationTsMorph(
Expand All @@ -32,7 +34,7 @@ export function importBatchDeclarations(
},
{
kind: StructureKind.ImportDeclaration,
moduleSpecifier: './index',
moduleSpecifier: options?.generateESM ? './index.js' : './index',
namedImports: getNamedImports(service)
}
];
Expand Down
6 changes: 4 additions & 2 deletions packages/generator/src/complex-type/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,20 @@ import { complexTypeNamespace } from './namespace';
import type { VdmComplexType } from '../vdm-types';
import type { ODataVersion } from '@sap-cloud-sdk/util';
import type { SourceFileStructure } from 'ts-morph';
import type { CreateFileOptions } from '@sap-cloud-sdk/generator-common/internal';

/**
* @internal
*/
export function complexTypeSourceFile(
complexType: VdmComplexType,
oDataVersion: ODataVersion
oDataVersion: ODataVersion,
options?: CreateFileOptions
): SourceFileStructure {
return {
kind: StructureKind.SourceFile,
statements: [
...importDeclarations(complexType, oDataVersion),
...importDeclarations(complexType, oDataVersion, options),
complexTypeInterface(complexType),
fieldTypeClass(complexType),
complexTypeNamespace(complexType)
Expand Down
46 changes: 46 additions & 0 deletions packages/generator/src/complex-type/imports.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from '../../test/test-util/data-model';
import { importDeclarations } from './imports';
import type { VdmComplexType } from '../vdm-types';
import type { CreateFileOptions } from '@sap-cloud-sdk/generator-common/internal';

describe('complex type imports', () => {
it('importDeclarations', () => {
Expand Down Expand Up @@ -94,4 +95,49 @@ describe('complex type imports', () => {
}
]);
});

describe('ESM support', () => {
const commonjsOptions = {
generateESM: false
} as CreateFileOptions;

const esmOptions = {
generateESM: true
} as CreateFileOptions;

it('importDeclarations with CommonJS', () => {
const actual = importDeclarations(
complexMealWithDesert,
'v2',
commonjsOptions
);

expect(
actual.find(imp => imp.moduleSpecifier === './ComplexDesert')
?.moduleSpecifier
).toBe('./ComplexDesert');
});

it('importDeclarations with ESM', () => {
const actual = importDeclarations(
complexMealWithDesert,
'v2',
esmOptions
);

expect(
actual.find(imp => imp.moduleSpecifier === './ComplexDesert.js')
?.moduleSpecifier
).toBe('./ComplexDesert.js');
});

it('maintains backward compatibility when options is undefined', () => {
const actual = importDeclarations(complexMealWithDesert, 'v2');

expect(
actual.find(imp => imp.moduleSpecifier === './ComplexDesert')
?.moduleSpecifier
).toBe('./ComplexDesert');
});
});
});
8 changes: 5 additions & 3 deletions packages/generator/src/complex-type/imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ import {
import type { ImportDeclarationStructure } from 'ts-morph';
import type { ODataVersion } from '@sap-cloud-sdk/util';
import type { VdmComplexType } from '../vdm-types';
import type { CreateFileOptions } from '@sap-cloud-sdk/generator-common/internal';

/**
* @internal
*/
export function importDeclarations(
complexType: VdmComplexType,
oDataVersion: ODataVersion
oDataVersion: ODataVersion,
options?: CreateFileOptions
): ImportDeclarationStructure[] {
return [
...complexTypeImportDeclarations(complexType.properties),
...enumTypeImportDeclarations(complexType.properties),
...complexTypeImportDeclarations(complexType.properties, options),
...enumTypeImportDeclarations(complexType.properties, options),
odataImportDeclarationTsMorph(
[
'DefaultDeSerializers',
Expand Down
Loading
Loading