Skip to content

Conversation

@seonggukchoi
Copy link
Contributor

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Other... Please describe:

What is the current behavior?

export enum FooBarEnum {
  FOO = 'FOO',
  BAR = 'BAR',
}

export class FooBarEntity {
  fooBarPrice!: number;
  fooBarEnum!: FooBarEnum;
}

This class will be converted as:

fooBarPrice: { required: true, type: () => Number },
fooBarEnum: { required: true, enum: (await import("./foo-bar.entity.js")).FooBarEnum

The enum property has an await statement without an async function wrapping.

Issue Number: N/A

What is the new behavior?

Wrap enum property values in arrow functions to support dynamic imports.
When the enum type reference contains dynamic import syntax, the function is marked as async.

  • Enum properties now use function form: enum: () => EnumType
  • Dynamic imports use async form: enum: async () => EnumType
  • Detect import() syntax and add async modifier accordingly
  • Update all test fixtures to reflect new enum property format
export enum FooBarEnum {
  FOO = 'FOO',
  BAR = 'BAR',
}

export class FooBarEntity {
  fooBarPrice!: number;
  fooBarEnum!: FooBarEnum;
}

This class will be converted as:

fooBarPrice: { required: true, type: () => Number },
fooBarEnum: { required: true, enum: async () => (await import("./foo-bar.entity.js")).FooBarEnum

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

This change may be related to: #3603

@seonggukchoi seonggukchoi force-pushed the master branch 2 times, most recently from bde4830 to 3bf3ab4 Compare November 18, 2025 10:22
- Check identifierText.includes('await ') instead of typeName.includes('import(')
- Update test fixtures to conditionally add async based on esmCompatible
- Add regression test for same-file array types (nestjs#3630)
@seonggukchoi
Copy link
Contributor Author

seonggukchoi commented Nov 18, 2025

The commit eb5bc19 applied the same async modifier fix pattern to enum properties that was applied to type properties.
The async modifier should only be added when the identifier actually contains await (for ESM dynamic imports), not based on the typeName containing import(.
Also, the commit eb5bc19 fixes the regression from #3603 where same-file types and enums were incorrectly getting async modifiers added when not using ESM mode.

@seonggukchoi
Copy link
Contributor Author

@kamilmysliwiec Hello Kamil, I know you’re usually quite busy, but would it be possible for you to review this PR with higher priority?

In an ESM environment, using a class or a TypeScript enum as a property type currently results in an incorrect code transformation, causing the application to fail to start at runtime.

I’ve also included tests addressing the issue introduced in the 11.2.2 patch (#3630).
Wishing you a wonderful day!

@kamilmysliwiec
Copy link
Member

Doesn't this change break older projects (same as the previous PR #3630)?

@seonggukchoi
Copy link
Contributor Author

@kamilmysliwiec
I’ve looked into this more deeply, and it appears that the root cause of #3630 is that the type metadata cannot properly resolve an async function.

With the changes introduced in this PR, adding the following code should make it work correctly:

if (isPromise(metadata.type)) {
  metadata.type = await metadata.type;
}

However, since this requires the use of await, a large number of functions would need to become async, and ultimately SwaggerModule.createDocument(app, config) in main.ts would also need to be awaited, which changes the public interface.

If the project has decided to rely on await import for ESM compatibility, this change may be unavoidable. What are your thoughts on this?

@seonggukchoi
Copy link
Contributor Author

Doesn't this change break older projects (same as the previous PR #3630)?

In a CommonJS environment, everything works as expected.
In the ESM case, the issue described above still persists, but the application no longer fails during runtime boot, which is an improvement.

@kamilmysliwiec
Copy link
Member

If the project has decided to rely on await import for ESM compatibility, this change may be unavoidable. What are your thoughts on this?

Is there any specific reason why we cant stick to require given that it's now compatible with ESM?

@seonggukchoi
Copy link
Contributor Author

If the project has decided to rely on await import for ESM compatibility, this change may be unavoidable. What are your thoughts on this?

Is there any specific reason why we cant stick to require given that it's now compatible with ESM?

The CLI plugin’s ESM-compatible mode uses await import instead of require, which leads to the current issue.
Because the plugin stores metadata in static, non-async functions, placing await import inside them results in a runtime syntax error.

The change I proposed earlier is intended to address this behavior.
Although the current code works correctly in CommonJS mode, I believe that adding proper async/await support is necessary for full compatibility within the ESM ecosystem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants