From 164ee1086fdc993e92b506d09c910f19d4e236b4 Mon Sep 17 00:00:00 2001 From: Frank Weigel Date: Mon, 13 Oct 2025 21:27:43 +0200 Subject: [PATCH] feat(dts-generator): introduce new directive for modules with named exports The new .dtsgenrc option "modulesWithNamedExports" can be an array of module names for which named exports are generated. For library modules, this happens automatically, the y don't have to be listed. The new option is useful for the webcomponent package files created by ui5-tooling-modules. They should behave similar to library modules. --- .../api-report/dts-generator.api.md | 1 + .../dts-generator/src/generate-from-objects.ts | 10 ++++++++++ packages/dts-generator/src/generate.ts | 1 + .../dts-generator/src/js-utils/ui5-metadata.js | 2 ++ .../dts-generator/src/phases/json-fixer.ts | 18 ++++++++++++++++++ .../dts-generator/src/phases/json-to-ast.ts | 8 +++++--- packages/dts-generator/src/types/api-json.d.ts | 1 + 7 files changed, 38 insertions(+), 3 deletions(-) diff --git a/packages/dts-generator/api-report/dts-generator.api.md b/packages/dts-generator/api-report/dts-generator.api.md index c149177..d947b4d 100644 --- a/packages/dts-generator/api-report/dts-generator.api.md +++ b/packages/dts-generator/api-report/dts-generator.api.md @@ -48,6 +48,7 @@ export interface Directives { fqnToIgnore: { [fqn: string]: string; }; + modulesWithNamedExports: string[]; namespacesToInterfaces: { [orgNamespace: string]: true | [true] | [true, "keep_original_ns"]; }; diff --git a/packages/dts-generator/src/generate-from-objects.ts b/packages/dts-generator/src/generate-from-objects.ts index a5a873c..e07c2df 100644 --- a/packages/dts-generator/src/generate-from-objects.ts +++ b/packages/dts-generator/src/generate-from-objects.ts @@ -94,6 +94,15 @@ export interface Directives { deprecatedEnumAliases: { [fqn: string]: string; }; + + /** + * A list of modules (their names w/o the *.js extension) for which named exports + * will be generated. + * + * All `** /library.js` modules automatically use named exports, they don't have + * to be listed. + */ + modulesWithNamedExports: string[]; } /** @@ -135,6 +144,7 @@ const defaultOptions: GenerateFromObjectsConfig = { fqnToIgnore: {}, overlays: {}, deprecatedEnumAliases: {}, + modulesWithNamedExports: [], }, generateGlobals: false, }; diff --git a/packages/dts-generator/src/generate.ts b/packages/dts-generator/src/generate.ts index 74f7045..253bf31 100644 --- a/packages/dts-generator/src/generate.ts +++ b/packages/dts-generator/src/generate.ts @@ -33,6 +33,7 @@ async function loadDirectives(directivesPaths: string[]) { fqnToIgnore: {}, overlays: {}, deprecatedEnumAliases: {}, + modulesWithNamedExports: [], }; function mergeDirectives(loadedDirectives: Directives) { diff --git a/packages/dts-generator/src/js-utils/ui5-metadata.js b/packages/dts-generator/src/js-utils/ui5-metadata.js index fefca7c..e5ffdf1 100644 --- a/packages/dts-generator/src/js-utils/ui5-metadata.js +++ b/packages/dts-generator/src/js-utils/ui5-metadata.js @@ -243,6 +243,8 @@ export async function loadDirectives(directivesFiles) { forwardDeclarations: {}, fqnToIgnore: {}, overlays: {}, + deprecatedEnumAliases: {}, + modulesWithNamedExports: [], }; function mergeDirectives(loadedDirectives) { Object.keys(loadedDirectives).forEach((key) => { diff --git a/packages/dts-generator/src/phases/json-fixer.ts b/packages/dts-generator/src/phases/json-fixer.ts index c3ebcd3..0ac8d17 100644 --- a/packages/dts-generator/src/phases/json-fixer.ts +++ b/packages/dts-generator/src/phases/json-fixer.ts @@ -899,6 +899,23 @@ function markDeprecatedAliasesForEnums( }); } +function markEnumsAsUsingNamedExports( + symbols: ConcreteSymbol[], + directives: Directives, +) { + const modulesWithNamedExports = new Set(directives.modulesWithNamedExports); + symbols.forEach((symbol) => { + if ( + symbol.kind === "enum" && + symbol.module && + symbol.export && + modulesWithNamedExports.has(symbol.module) + ) { + symbol.useNamedExport = true; + } + }); +} + function _prepareApiJson( json: ApiJSON, directives: Directives, @@ -915,6 +932,7 @@ function _prepareApiJson( determineMissingExportsForTypes(json.symbols); parseTypeExpressions(json.symbols); markDeprecatedAliasesForEnums(json.symbols, directives); + markEnumsAsUsingNamedExports(json.symbols, directives); if (options.mainLibrary) { addForwardDeclarations(json, directives); addInterfaceWithModuleNames(json.symbols); diff --git a/packages/dts-generator/src/phases/json-to-ast.ts b/packages/dts-generator/src/phases/json-to-ast.ts index f38e939..3b0fc10 100644 --- a/packages/dts-generator/src/phases/json-to-ast.ts +++ b/packages/dts-generator/src/phases/json-to-ast.ts @@ -700,7 +700,8 @@ class ModuleBuilder extends ScopeBuilder { if ( !moduleImport.module.endsWith("/library") && exportName != "" && - symbol.kind === "enum" + symbol.kind === "enum" && + !symbol.useNamedExport ) { const defaultFQN = fqn.substring(0, fqn.lastIndexOf(".")); const defaultImportName = @@ -1656,7 +1657,7 @@ function buildInterfaceFromObject(ui5Object): Interface { */ function buildEnum(ui5Enum: EnumSymbol) { assertKnownProps( - ["name", "basename", "properties", "deprecatedAliasFor"], + ["name", "basename", "properties", "deprecatedAliasFor", "useNamedExport"], ui5Enum, ); @@ -1668,7 +1669,8 @@ function buildEnum(ui5Enum: EnumSymbol) { kind: "Enum", name: ui5Enum.basename, withValues: true, - isLibraryEnum: ui5Enum.module.endsWith("/library"), + isLibraryEnum: + ui5Enum.useNamedExport || ui5Enum.module.endsWith("/library"), deprecatedAliasFor: ui5Enum.deprecatedAliasFor, values: _.map(ui5Enum.properties, (prop) => buildVariableWithValue(prop, isStandardEnum), diff --git a/packages/dts-generator/src/types/api-json.d.ts b/packages/dts-generator/src/types/api-json.d.ts index b03bd24..c17a35a 100644 --- a/packages/dts-generator/src/types/api-json.d.ts +++ b/packages/dts-generator/src/types/api-json.d.ts @@ -158,6 +158,7 @@ export type EnumSymbol = SymbolBase & { stereotype?: "enum"; }; deprecatedAliasFor?: string; + useNamedExport?: boolean; [k: string]: any; }; /**