Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support cjs and esm both by tshy #67

Merged
merged 4 commits into from
Feb 3, 2025
Merged

feat: support cjs and esm both by tshy #67

merged 4 commits into from
Feb 3, 2025

Conversation

fengmk2
Copy link
Member

@fengmk2 fengmk2 commented Feb 3, 2025

BREAKING CHANGE: drop Node.js < 18.19.0 support

part of eggjs/egg#3644

eggjs/egg#5257

Summary by CodeRabbit

  • New Features

    • Introduced a new middleware for handling multipart requests.
    • Added improved error handling for oversized file uploads.
  • Refactor

    • Streamlined configuration and context enhancements for better stability and TypeScript support.
    • Modernized the codebase by transitioning to ES modules and updating type definitions.
  • Chores

    • Updated package metadata, dependencies, and continuous integration settings to support newer Node.js versions.
    • Introduced a new TypeScript configuration for stricter type-checking.
  • Tests

    • Added unit tests to validate application behavior under incorrect configurations.
    • Established comprehensive tests for multipart form handling to ensure correct processing of file uploads.
    • Transitioned existing tests to TypeScript and updated assertions for consistency.

BREAKING CHANGE: drop Node.js < 18.19.0 support

part of eggjs/egg#3644

eggjs/egg#5257
Copy link

coderabbitai bot commented Feb 3, 2025

Warning

Rate limit exceeded

@fengmk2 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 18 minutes and 19 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 2fac548 and f9b5928.

📒 Files selected for processing (2)
  • src/lib/utils.ts (1 hunks)
  • test/.setup.ts (1 hunks)

Walkthrough

This pull request updates various configuration files and refactors the multipart file handling. Changes include modifications to ESLint and GitHub Actions settings, removal of legacy multipart implementations and associated TypeScript definitions, and updates to ignore files. A new implementation for multipart processing is introduced along with enhanced error handling, updated context methods, and refined utility functions. The package metadata has been updated and new testing and TypeScript configuration files have been added. These changes collectively modernize the codebase and improve type safety.

Changes

File(s) Change Summary
.eslintignore, .eslintrc Updated ESLint settings: added __snapshots__, removed node_modules/coverage; extended ESLint configuration to an array with TypeScript and node-prefix rules
.github/workflows/nodejs.yml Updated CI configuration: removed Node 16, keeping versions 18, 20, 22
.gitignore Added entries: .tshy*, .eslintcache, and dist
app.js, app/middleware/multipart.js, config/config.default.js, index.d.ts, test/wrong-mode.test.js Removed legacy multipart implementation files and TypeScript types
package.json Updated package name to @eggjs/multipart, added publishConfig, exports, updated repository URL, engines, file lists, and dependency versions
src/app.ts Introduced new AppBootHook class implementing ILifecycleBoot with updated configWillLoad method
src/app/extend/context.ts Refactored context extension: switched to ES modules, added TypeScript interfaces, and updated file handling methods with type annotations
src/app/middleware/multipart.ts Added new multipart middleware with configuration normalization and request file saving
src/app/schedule/clean_tmpdir.ts Refactored schedule file: updated to ES modules, added type annotations, and updated log messages
src/config/config.default.ts Introduced new multipart configuration with types and default values; extended EggAppConfig
src/index.ts Added import statements for configuration and context enhancements
src/lib/LimitError.ts, src/lib/MultipartFileTooLargeError.ts Added new error classes for file limit and oversized file errors
src/lib/utils.ts Updated to use ES module syntax; added humanizeBytes, refined normalizeOptions and checkFile with explicit types
src/typings/index.d.ts Added import for egg typings
test/wrong-mode.test.ts Added new unit tests for multipart configuration errors
tsconfig.json New TypeScript configuration file extending @eggjs/tsconfig with strict settings

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Middleware
    participant Context
    participant AppCore

    Client->>Middleware: Send multipart request
    Middleware->>Middleware: Check if request is multipart
    alt Multipart request valid
        Middleware->>Context: Call saveRequestFiles()
        Context-->>Middleware: Process file saving
    else Non-multipart or non-matching request
        Middleware->>Middleware: Skip file processing
    end
    Middleware->>AppCore: Pass control to next middleware
Loading
sequenceDiagram
    participant EggCore
    participant AppBootHook
    participant Logger

    EggCore->>AppBootHook: Instantiate and call configWillLoad()
    AppBootHook->>AppBootHook: Normalize multipart options
    AppBootHook->>Logger: Log multipart mode & temp directory info
    AppBootHook->>EggCore: Add 'multipart' to middleware configuration
Loading

Poem

I'm a little bunny, hopping in code light,
Updating configs and middleware just right.
New hooks and types in every byte,
Legacy files hopped off into the night.
I nibble on errors with a cheerful sight,
Coding with joy, my ears twitched with delight!
🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (11)
src/app/extend/context.ts (3)

8-9: Consider adding type declarations for co-busboy.
You may create a custom .d.ts file or install an existing type declaration library if available. This ensures better type safety.


169-169: Avoid unnecessary this alias.
You can directly reference this within methods, even in arrow functions, reducing confusion and aligning with recommended TypeScript patterns.

Example fix:

-// eslint-disable-next-line @typescript-eslint/no-this-alias
-const ctx = this;
+// Use `this` directly instead
🧰 Tools
🪛 Biome (1.9.4)

[error] 169-169: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


343-343: Split the assignment to avoid confusion.
Assignments within a variable declaration expression can reduce readability. Consider splitting them into separate statements.

Here’s a potential fix:

-    const limits: Record<string, number | undefined> = opts.limits = { ...options.limits };
+    opts.limits = { ...options.limits };
+    const limits: Record<string, number | undefined> = opts.limits;
🧰 Tools
🪛 Biome (1.9.4)

[error] 343-343: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

src/app/middleware/multipart.ts (1)

8-11: Remove or implement the commented configuration.

The commented line suggests incomplete configuration for pathToRegexpModule.

Either remove the comment or implement the configuration:

  const matchFn = options.fileModeMatch && pathMatching({
    match: options.fileModeMatch,
-    // pathToRegexpModule: app.options.pathToRegexpModule,
  });
src/app.ts (1)

7-18: Enhance type safety and error handling in configWillLoad.

The method could benefit from explicit return type and error handling for configuration normalization.

Apply this diff to improve the implementation:

-  configWillLoad() {
+  configWillLoad(): void {
+    try {
      this.app.config.multipart = normalizeOptions(this.app.config.multipart);
      const options = this.app.config.multipart;

      this.app.coreLogger.info('[@eggjs/multipart] %s mode enable', options.mode);
      if (options.mode === 'file' || options.fileModeMatch) {
        this.app.coreLogger.info('[@eggjs/multipart] will save temporary files to %j, cleanup job cron: %j',
          options.tmpdir, options.cleanSchedule.cron);
        // enable multipart middleware
        this.app.config.coreMiddleware.push('multipart');
      }
+    } catch (err) {
+      this.app.coreLogger.error('[@eggjs/multipart] failed to load config: %s', err);
+      throw err;
+    }
   }
test/wrong-mode.test.ts (1)

4-27: Add more test cases for configuration validation.

Consider adding test cases for other configuration scenarios:

  • Invalid tmpdir path
  • Invalid cleanSchedule configuration
  • Missing required options

Example test case:

it('should start fail when tmpdir is not writable', async () => {
  app = mm.app({
    baseDir: 'apps/wrong-tmpdir',
  });
  await assert.rejects(async () => {
    await app.ready();
  }, /tmpdir is not writable/);
});
src/app/schedule/clean_tmpdir.ts (3)

1-6: Improve type safety by specifying a more precise return type.

The return type any could be replaced with a more specific type.

Apply this diff to improve type safety:

-export default (app: EggCore): any => {
+export default (app: EggCore): typeof CleanTmpdir => {

17-30: Enhance error logging with more details.

Consider adding more context to error logs to aid in debugging.

Apply this diff to improve error logging:

  } catch (err) {
    /* c8 ignore next 3 */
-   ctx.coreLogger.error('[@eggjs/multipart:CleanTmpdir:error] remove tmpdir: %j error: %s', dir, err);
+   ctx.coreLogger.error('[@eggjs/multipart:CleanTmpdir:error] remove tmpdir: %j error: %s\nStack: %s', 
+     dir, err.message, err.stack);
    ctx.coreLogger.error(err);
  }

32-53: Consider performance and configurability improvements.

  1. The sequential directory removal could be parallelized for better performance.
  2. The cleanup periods (1 year, 3 months, 7 days) could be made configurable.

Example implementation:

interface CleanupConfig {
  years: number;
  months: number;
  days: number;
}

async subscribe() {
  const { ctx } = this;
  const config = ctx.app.config;
  const cleanupConfig = config.multipart.cleanupConfig || {
    years: 1,
    months: 3,
    days: 7,
  };
  
  ctx.coreLogger.info('[@eggjs/multipart:CleanTmpdir] start clean tmpdir: %j', config.multipart.tmpdir);
  
  const tasks = [];
  
  // years
  for (let i = 1; i <= cleanupConfig.years; i++) {
    const date = dayjs().subtract(i, 'years');
    const dir = path.join(config.multipart.tmpdir, date.format('YYYY'));
    tasks.push(this._remove(dir));
  }
  
  // months and days (similar implementation)
  
  await Promise.all(tasks);
  
  ctx.coreLogger.info('[@eggjs/multipart:CleanTmpdir] end');
}
src/lib/utils.ts (1)

72-85: Consider improving error handling and type safety.

  1. The void | Error union type could be improved.
  2. The any type for fileStream should be more specific.
  3. Error handling could be more robust.

Consider these improvements:

-options.checkFile = (_fieldName: string, fileStream: any, fileName: string): void | Error => {
+interface FileStream {
+  readable: boolean;
+  // Add other expected properties
+}
+
+options.checkFile = (_fieldName: string, fileStream: FileStream | null, fileName: string): Error | undefined => {
   // just ignore, if no file
-  if (!fileStream || !fileName) return;
+  if (!fileStream || !fileName) return undefined;
   try {
     if (!checkExt(fileName)) {
-      const err = new Error('Invalid filename: ' + fileName);
-      Reflect.set(err, 'status', 400);
+      const err = new Error('Invalid filename: ' + fileName) as Error & { status?: number };
+      err.status = 400;
       return err;
     }
+    return undefined;
   } catch (err: any) {
     err.status = 400;
     return err;
   }
 };
🧰 Tools
🪛 Biome (1.9.4)

[error] 72-72: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

src/config/config.default.ts (1)

92-98: Consider improving type safety in checkFile signature.

The checkFile method signature could be improved:

  1. The any type for file parameter should be more specific
  2. The void | Error union type could be clearer

Consider this improvement:

-  checkFile?(
-    fieldname: string,
-    file: any,
-    filename: string,
-    encoding: string,
-    mimetype: string
-  ): void | Error;
+  checkFile?(
+    fieldname: string,
+    file: {
+      readable: boolean;
+      // Add other expected properties
+    } | null,
+    filename: string,
+    encoding: string,
+    mimetype: string
+  ): Error | undefined;
🧰 Tools
🪛 Biome (1.9.4)

[error] 98-98: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fa296f0 and 998a6d1.

📒 Files selected for processing (22)
  • .eslintignore (1 hunks)
  • .eslintrc (1 hunks)
  • .github/workflows/nodejs.yml (1 hunks)
  • .gitignore (1 hunks)
  • app.js (0 hunks)
  • app/middleware/multipart.js (0 hunks)
  • config/config.default.js (0 hunks)
  • index.d.ts (0 hunks)
  • package.json (2 hunks)
  • src/app.ts (1 hunks)
  • src/app/extend/context.ts (11 hunks)
  • src/app/middleware/multipart.ts (1 hunks)
  • src/app/schedule/clean_tmpdir.ts (4 hunks)
  • src/config/config.default.ts (1 hunks)
  • src/index.ts (1 hunks)
  • src/lib/LimitError.ts (1 hunks)
  • src/lib/MultipartFileTooLargeError.ts (1 hunks)
  • src/lib/utils.ts (3 hunks)
  • src/typings/index.d.ts (1 hunks)
  • test/wrong-mode.test.js (0 hunks)
  • test/wrong-mode.test.ts (1 hunks)
  • tsconfig.json (1 hunks)
💤 Files with no reviewable changes (5)
  • app.js
  • app/middleware/multipart.js
  • config/config.default.js
  • test/wrong-mode.test.js
  • index.d.ts
✅ Files skipped from review due to trivial changes (5)
  • src/index.ts
  • .eslintignore
  • .gitignore
  • src/typings/index.d.ts
  • tsconfig.json
🧰 Additional context used
🪛 Biome (1.9.4)
src/config/config.default.ts

[error] 98-98: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

src/lib/utils.ts

[error] 72-72: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

src/app/extend/context.ts

[error] 73-73: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)


[error] 169-169: This aliasing of this is unnecessary.

Arrow functions inherits this from their enclosing scope.
Safe fix: Use this instead of an alias.

(lint/complexity/noUselessThisAlias)


[error] 343-343: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Node.js / Test (windows-latest, 22)
  • GitHub Check: Node.js / Test (windows-latest, 20)
  • GitHub Check: Node.js / Test (windows-latest, 18)
🔇 Additional comments (21)
src/lib/LimitError.ts (1)

1-13: Looks good.
The error class is well-structured, with a clear code property and 413 status code, making it straightforward for consumers to handle limit-related errors.

src/lib/MultipartFileTooLargeError.ts (1)

1-15: Implementation is appropriate for large file handling.
This custom error clearly communicates context about the file that triggered the size limit, aiding debugging and error handling.

src/lib/utils.ts (2)

1-4: LGTM! Module imports updated to ESM syntax.

The conversion from CommonJS to ESM imports aligns with modern JavaScript practices.


32-37: LGTM! Well-structured type-safe helper function.

The humanizeBytes function effectively encapsulates the byte conversion logic with proper type checking.

src/config/config.default.ts (1)

101-123: LGTM! Well-structured default configuration.

The default configuration values are sensible and well-documented. The use of as MultipartConfig ensures type safety.

.eslintrc (1)

2-5: LGTM! Enhanced ESLint configuration.

The updated ESLint configuration properly supports TypeScript and enforces Node.js prefix conventions.

.github/workflows/nodejs.yml (1)

15-15: LGTM! Updated Node.js version requirements.

Removing Node.js 16 and testing against versions 18, 20, and 22 aligns with the PR objective to drop support for versions earlier than 18.19.0.

package.json (14)

2-2: Package Name Update
The package name has been updated to a scoped name ("@eggjs/multipart"), which is beneficial for proper package organization and namespace management.


4-6: Publish Configuration Added
A new "publishConfig" field with "access": "public" has been introduced. This ensures that when the package is published, it will have the intended public access settings.


11-16: EggPlugin Exports Configuration
The "eggPlugin" section now includes an "exports" object that specifies module entry points for "import", "require", and "typescript". This clearly delineates the responsibilities for both ESM and CommonJS consumers.


21-21: Repository URL Update
The repository URL has been updated to "git+https://github.com/eggjs/multipart.git", ensuring that the package metadata reflects the correct source repository.


34-34: Homepage Update
The "homepage" field now points to "https://github.com/eggjs/multipart#readme", aligning it with the updated repository information.


36-36: Node.js Engine Requirement Update
The "engines" field now requires Node.js version >= 18.19.0, effectively dropping support for older Node.js versions. This is a breaking change—please ensure that the documentation and downstream dependencies are updated accordingly.


39-43: Dependencies Update
The dependencies have been revised to include new packages (e.g., "@eggjs/core") and update versions for others such as "bytes", "co-busboy", and "egg-path-matching". Verify that these versions are compatible with the new Node.js engine requirement and the overall project architecture.


46-65: DevDependencies Update
A comprehensive update of the devDependencies has been performed, adding tools like "@arethetypeswrong/cli", "@eggjs/bin", "@eggjs/mock", and others. These changes aim to improve the development workflow and type safety. Please double-check that no conflicts arise with the existing build process.


66-74: Scripts Restructuring
The scripts have been restructured to include linting, pretesting, testing, CI, and cleanup commands. The "prepublishOnly" script now runs a sequence of commands: "tshy && tshy-after && attw --pack". Please verify that the attw command is valid and that any necessary dependency for it is included, as it does not appear in the current dependency lists.


76-76: Module Type Declaration
The addition of "type": "module" enforces an ES module format, which aligns with the updated dual-support strategy for ESM and CommonJS.


77-82: Tshy Configuration Addition
A new "tshy" configuration object has been added that maps the package’s primary export to "./src/index.ts". This setup is presumably used by the build or bundling process. Please ensure that this configuration is correctly integrated with your toolchain.


83-95: Exports Field for Dual Module Support
The "exports" field provides explicit entry points for both ECMAScript modules and CommonJS, along with corresponding TypeScript definitions. This robust configuration is key to supporting both module systems; however, please verify that the provided file paths (for both ESM and CJS builds) match the actual build output.


96-99: Files Field Update
The "files" array now includes only "dist" and "src", ensuring that only necessary files are published while excluding extraneous ones. This improves package security and distribution size.


100-101: Main and Types Fields Update
The updates to the "types" and "main" fields now correctly point to "./dist/commonjs/index.d.ts" and "./dist/commonjs/index.js", respectively. This change confirms that the CommonJS build is now the default for environments that do not support ESM natively.

src/app/extend/context.ts Show resolved Hide resolved
src/app/middleware/multipart.ts Outdated Show resolved Hide resolved
src/app/middleware/multipart.ts Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
test/multipart.test.ts (1)

389-393: Remove duplicate before hook.

There are duplicate before hooks in the "upload one file" test suite. Combine them into a single hook to improve maintainability.

-    before(async () => {
-      await app.ready();
-      server = app.listen();
-      host = 'http://127.0.0.1:' + server.address().port;
-    });
-    before(async () => {
-      await app.httpRequest()
-        .get('/upload')
-        .expect(200);
-    });
+    before(async () => {
+      await app.ready();
+      server = app.listen();
+      host = 'http://127.0.0.1:' + server.address().port;
+      await app.httpRequest()
+        .get('/upload')
+        .expect(200);
+    });
🧹 Nitpick comments (9)
src/lib/utils.ts (3)

32-36: Handle potential null returns from bytes library
If the bytes function fails to parse the input, it can return null. Consider handling that scenario more gracefully, for instance by throwing an error or defaulting to zero.

-  return bytes(size) as number;
+  const result = bytes(size);
+  if (result === null) {
+    throw new Error(`Invalid size input: ${size}`);
+  }
+  return result;

76-76: Use Error | undefined instead of void | Error for clarity
Returning void in a union type may be confusing in TypeScript. Using Error | undefined makes the intent more explicit and aligns better with common conventions.

- options.checkFile = (_fieldName: string, fileStream: any, fileName: string): void | Error => {
+ options.checkFile = (_fieldName: string, fileStream: any, fileName: string): Error | undefined => {
🧰 Tools
🪛 Biome (1.9.4)

[error] 76-76: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)


82-86: Use a consistent approach to set error status
Currently, line 82 sets the error status using Reflect.set(err, 'status', 400); while line 86 uses direct assignment err.status = 400;. Consider standardizing the approach for consistency.

test/fixtures/apps/whitelist-function/app/controller/upload.js (2)

8-8: Refactor the while loop condition for better readability.

The assignment within the while condition makes the code harder to read and maintain. Consider restructuring using async iteration.

-  while ((part = await parts()) != null) {
+  for await (const part of parts()) {
     if (Array.isArray(part)) {
       continue;
     } else {
       break;
     }
   }
🧰 Tools
🪛 Biome (1.9.4)

[error] 8-8: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)


16-17: Consider using async streams with pipeline.

For better error handling and memory management, consider using the stream pipeline API.

-  const ws = fs.createWriteStream(path.join(this.app.config.logger.dir, 'multipart-test-file'));
-  part.pipe(ws);
+  const { pipeline } = require('node:stream/promises');
+  await pipeline(
+    part,
+    fs.createWriteStream(path.join(this.app.config.logger.dir, 'multipart-test-file'))
+  );
test/dynamic-option.test.ts (1)

37-37: Consider using a proper type for form stream.

Instead of casting to any, consider creating a proper type definition for the form stream.

interface FormStream extends NodeJS.ReadableStream {
  headers(): { [key: string]: string };
}

Then use it like:

-  stream: form as any,
+  stream: form as FormStream,
test/ts.test.ts (1)

16-25: Consolidate setup hooks for better maintainability.

Multiple before hooks can be consolidated into a single hook.

-  before(() => {
-    app = mm.app({
-      baseDir: 'apps/ts',
-    });
-    return app.ready();
-  });
-  before(() => {
-    server = app.listen();
-    host = 'http://127.0.0.1:' + server.address().port;
-  });
+  before(async () => {
+    app = mm.app({
+      baseDir: 'apps/ts',
+    });
+    await app.ready();
+    server = app.listen();
+    host = 'http://127.0.0.1:' + server.address().port;
+  });
🧰 Tools
🪛 Biome (1.9.4)

[error] 22-25: Disallow duplicate setup and teardown hooks.

Disallow before duplicacy inside the describe function.

(lint/suspicious/noDuplicateTestHooks)

test/multipart-for-await.test.ts (1)

40-40: Consolidate form stream type casting.

Multiple instances of as any type casting can be improved by defining a proper type.

Create a types file (e.g., test/types.ts) with:

import formstream from 'formstream';

declare module 'formstream' {
  interface FormStream extends NodeJS.ReadableStream {
    headers(): { [key: string]: string };
  }
  
  interface FormStreamConstructor {
    new(): FormStream;
    (): FormStream;
  }
  
  const formstream: FormStreamConstructor;
  export = formstream;
}

Then remove all as any casts from the test files.

Also applies to: 64-64, 82-82, 100-100, 119-119, 141-141

test/file-mode.test.ts (1)

67-67: Consider using a more specific type for the stream property.

The stream property is consistently cast to any type across multiple test cases. Consider creating a proper type for the form stream to improve type safety.

-stream: form as any,
+stream: form as FormStream,

Add the following type definition at the top of the file:

interface FormStream extends NodeJS.ReadableStream {
  headers(): { [key: string]: string };
}

Also applies to: 103-103, 125-125, 161-161, 188-188, 206-206, 221-221, 238-238, 257-257, 276-276, 294-294, 312-312, 331-331, 410-410, 428-428, 514-514, 535-535, 551-551, 570-570, 588-588, 633-633, 655-655, 677-677

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 998a6d1 and c48a1ec.

📒 Files selected for processing (12)
  • package.json (2 hunks)
  • src/app/middleware/multipart.ts (1 hunks)
  • src/lib/utils.ts (1 hunks)
  • test/dynamic-option.test.ts (3 hunks)
  • test/file-mode.test.ts (22 hunks)
  • test/fixtures/apps/ts/config/config.default.ts (2 hunks)
  • test/fixtures/apps/whitelist-function/app/controller/upload.js (1 hunks)
  • test/fixtures/apps/whitelist-function/app/router.js (0 hunks)
  • test/multipart-for-await.test.ts (8 hunks)
  • test/multipart.test.ts (40 hunks)
  • test/ts.test.js (0 hunks)
  • test/ts.test.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • test/fixtures/apps/whitelist-function/app/router.js
  • test/ts.test.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/middleware/multipart.ts
🧰 Additional context used
🪛 Biome (1.9.4)
test/fixtures/apps/whitelist-function/app/controller/upload.js

[error] 8-8: The assignment should not be in an expression.

The use of assignments in expressions is confusing.
Expressions are often considered as side-effect free.

(lint/suspicious/noAssignInExpressions)

test/ts.test.ts

[error] 22-25: Disallow duplicate setup and teardown hooks.

Disallow before duplicacy inside the describe function.

(lint/suspicious/noDuplicateTestHooks)


[error] 29-29: Disallow duplicate setup and teardown hooks.

Disallow after duplicacy inside the describe function.

(lint/suspicious/noDuplicateTestHooks)


[error] 30-30: Disallow duplicate setup and teardown hooks.

Disallow after duplicacy inside the describe function.

(lint/suspicious/noDuplicateTestHooks)

src/lib/utils.ts

[error] 76-76: void is confusing inside a union type.

Unsafe fix: Use undefined instead.

(lint/suspicious/noConfusingVoidType)

test/multipart.test.ts

[error] 393-397: Disallow duplicate setup and teardown hooks.

Disallow before duplicacy inside the describe function.

(lint/suspicious/noDuplicateTestHooks)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Node.js / Test (windows-latest, 22)
  • GitHub Check: Node.js / Test (windows-latest, 20)
  • GitHub Check: Node.js / Test (windows-latest, 18)
🔇 Additional comments (11)
test/fixtures/apps/ts/config/config.default.ts (2)

1-15: Well-implemented type definition with clear documentation!

The PowerPartial<T> type implementation is clean and follows TypeScript best practices. The recursive type correctly handles nested objects, making all properties optional at any depth. The documentation with examples is particularly helpful.


24-26: Consider expanding multipart configuration options.

Given that this PR focuses on enhancing multipart functionality and adding CJS/ESM support, the multipart configuration might benefit from additional options to control module-specific behavior and file handling settings.

Let's check what options are available in the new implementation:

✅ Verification successful

Expand Multipart Configuration Options

  • The test fixture (test/fixtures/apps/ts/config/config.default.ts) only sets config.multipart to { mode: 'file' }, while example usages in the repository (e.g. in the README and in conditions within src/app.ts) indicate additional options like tmpdir, cleanSchedule, and fileModeMatch exist.
  • The interface defined in src/config/config.default.ts for MultipartConfig documents further properties that can be leveraged for enhanced multipart handling, which could be beneficial given the PR’s focus on extended multipart functionality and CJS/ESM support.

Consider reviewing and expanding the fixture’s multipart configuration to incorporate these options to ensure consistency and full functionality.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for multipart configuration interface or type definitions
ast-grep --pattern 'interface $name {
  $$$
}' | grep -A 10 'Multipart\|Config'

# Search for usage examples of multipart configuration
rg -A 5 'multipart.*=.*{' test/

Length of output: 209


Script:

#!/bin/bash
echo "Searching for config.multipart assignments in configuration files:"
rg -A 5 "config\.multipart" test/fixtures/apps/ts/config/config.default.ts

echo "Searching for usage examples of multipart configuration in the repository:"
rg -A 5 'config\.multipart\s*=' .

echo "Searching for definitions of interfaces containing 'Multipart':"
rg -A 5 'interface\s+.*Multipart' .

Length of output: 3262

package.json (3)

36-36: Acknowledge the breaking change to Node.js versions
Raising the required version from Node.js 14 to 18.19.0 is a significant change. Ensure the project documentation and announcements convey this break in backward compatibility.


66-75: Comprehensive scripts configuration
These scripts cover linting, running tests, cleaning, and publishing tasks. The workflow is well-structured for continuous integration and development.


83-95: Good use of conditional exports
Providing separate ESM and CommonJS exports, along with a dedicated TypeScript entry, ensures broad compatibility and a smooth developer experience.

test/multipart-for-await.test.ts (1)

128-131: Investigate and document the skipped fieldNameSize test.

The TODO comment references busboy 1.x limitations. Let's verify if this limitation still exists in the current version.

✅ Verification successful

Update the skipped test for fieldNameSize
Investigation shows that the installed busboy (v1.6.0) documents support for fieldNameSize (with a default of 100 bytes). This indicates that the original limitation noted in the TODO is likely outdated. Please verify that egg-multipart now handles fieldNameSize correctly and, if so, remove the skip on this test and update the test case accordingly.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check current busboy version and relevant changes
npm list busboy
# Check if the limitation is documented in current version
curl -s https://raw.githubusercontent.com/mscdex/busboy/master/README.md | grep -A 5 fieldNameSize

Length of output: 2143

test/file-mode.test.ts (3)

1-10: LGTM! Clean import statements.

The imports are well-organized, using the node: protocol for Node.js built-in modules and direct imports for third-party packages.


15-17: LGTM! Proper type annotations.

Type annotations have been correctly added for variables:

  • app: MockApplication
  • server: any
  • host: string

349-350: LGTM! Modern async/await usage.

The code uses scheduler.wait from node:timers/promises instead of a custom sleep function, which is a better approach for handling delays in tests.

test/multipart.test.ts (2)

15-17: LGTM! Consistent type annotations.

Type annotations have been correctly and consistently added for variables across all test suites:

  • app: MockApplication
  • server: any
  • host: string

Also applies to: 251-253, 315-317, 379-381, 599-601


118-119: LGTM! Modern async/await usage.

The code uses scheduler.wait from node:timers/promises instead of a custom sleep function, which is a better approach for handling delays in tests.

Also applies to: 558-559

package.json Show resolved Hide resolved
test/ts.test.ts Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (8)
test/file-mode-limit-filesize-per-request.test.ts (2)

9-9: Consider using a more specific type for server variable.

Instead of using any, consider using Server from the 'node:http' module for better type safety.

-  let server: any;
+  let server: import('node:http').Server;

37-37: Consider extracting repeated type assertions into a helper function.

The as any type assertion for the form stream is repeated across multiple test cases. Consider extracting this into a helper function for better maintainability.

// Add at the top of the file
function createRequestOptions(form: formstream, options: Partial<urllib.RequestOptions> = {}) {
  return {
    method: 'POST',
    headers: form.headers(),
    stream: form as any,
    ...options,
  };
}

// Usage in tests
const res = await urllib.request(host + '/upload-limit-1mb', createRequestOptions(form));

Also applies to: 61-61, 77-77, 102-102

test/stream-mode-with-filematch.test.ts (1)

49-49: Replace any type assertions with proper types.

Using as any type assertions can mask potential type incompatibilities. Consider defining proper types for the form stream.

// Add this type definition at the top of the file
type FormStream = ReturnType<typeof formstream>;

// Then replace the type assertions
-      stream: form as any,
+      stream: form as FormStream,

Also applies to: 90-90, 113-113

test/enable-pathToRegexpModule.test.ts (1)

46-46: Consider using a proper type instead of any.

The test file has multiple instances of type casting form to any. This reduces type safety. Consider creating a proper type for the form stream to avoid using any.

// Add this type definition at the top of the file
type FormStream = ReturnType<typeof formstream>;

// Then replace the type casting with
stream: form as FormStream

Also applies to: 87-87, 128-128

test/stream-mode-with-filematch-glob.test.ts (4)

14-14: Consider using a more specific type for server.

Instead of using any, consider using http.Server type from Node.js for better type safety.

-  let server: any;
+  let server: import('node:http').Server;

49-49: Consider using a more specific type for form stream.

Instead of casting to any, consider creating a proper type for the form stream.

-      stream: form as any,
+      stream: form as formstream.Form,

75-114: Consider extracting common test setup code.

Both test cases share identical setup code for form creation and validation. Consider extracting this into a helper function to improve maintainability and reduce duplication.

async function createAndSubmitForm(url: string) {
  const form = formstream();
  form.field('foo', 'fengmk2').field('love', 'egg');
  form.file('file1', __filename, 'foooooooo.js');
  form.file('file2', __filename);
  form.buffer('file3', Buffer.from(''), '', 'application/octet-stream');
  form.file('bigfile', path.join(__dirname, 'fixtures', 'bigfile.js'));
  form.field('work', 'with Node.js');

  const headers = form.headers();
  return urllib.request(host + url, {
    method: 'POST',
    headers,
    stream: form as formstream.Form,
  });
}

async function validateResponse(res: urllib.HttpResponse, app: MockApplication) {
  assert.equal(res.status, 200);
  const data = JSON.parse(res.data);
  // ... rest of the validation logic
}

131-131: Apply consistent type handling across all test cases.

For consistency with previous suggestions, update the type casting here as well.

-      stream: form as any,
+      stream: form as formstream.Form,
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c48a1ec and 2fac548.

📒 Files selected for processing (4)
  • test/enable-pathToRegexpModule.test.ts (5 hunks)
  • test/file-mode-limit-filesize-per-request.test.ts (6 hunks)
  • test/stream-mode-with-filematch-glob.test.ts (5 hunks)
  • test/stream-mode-with-filematch.test.ts (8 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Node.js / Test (windows-latest, 22)
  • GitHub Check: Node.js / Test (windows-latest, 20)
  • GitHub Check: Node.js / Test (windows-latest, 18)
🔇 Additional comments (9)
test/file-mode-limit-filesize-per-request.test.ts (2)

1-5: LGTM! Well-organized imports.

The transition to ES modules and TypeScript is clean and well-structured, with proper organization of imports (built-ins first, followed by external packages).


29-121: LGTM! Comprehensive test coverage.

The test suite thoroughly covers:

  • Success cases for files within size limits
  • Error cases for files exceeding limits
  • Input validation for content type
  • Proper cleanup of temporary files

The assertions are well-structured and verify all important aspects of the responses.

test/stream-mode-with-filematch.test.ts (2)

1-10: LGTM! Clean migration to ESM imports.

The migration from CommonJS to ESM is well-executed with proper organization of imports and correct ESM-compatible filename/dirname setup.


12-32: Verify @eggjs/mock compatibility with the test suite.

The migration from egg-mock to @eggjs/mock looks good, but let's verify the compatibility and feature parity between the libraries.

✅ Verification successful

@eggjs/mock integration has been successfully verified.

  • The npm view shows that @eggjs/mock is up-to-date and reliable.
  • Searches confirmed that the codebase exclusively uses @eggjs/mock across the tests.
  • There are no lingering references to egg-mock, and the API usage in the test files (including test/stream-mode-with-filematch.test.ts) aligns well with @eggjs/mock's expected behavior.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if @eggjs/mock provides all the required features used in the test

# Check if the package exists and get its details
echo "Checking @eggjs/mock package..."
npm view @eggjs/mock

# Search for any usage of egg-mock features in the codebase that might not be available in @eggjs/mock
echo "Checking for potentially unsupported features..."
rg -l 'egg-mock' .
rg -l '@eggjs/mock' .

Length of output: 1814

🧰 Tools
🪛 Biome (1.9.4)

[error] 22-25: Disallow duplicate setup and teardown hooks.

Disallow before duplicacy inside the describe function.

(lint/suspicious/noDuplicateTestHooks)


[error] 29-29: Disallow duplicate setup and teardown hooks.

Disallow after duplicacy inside the describe function.

(lint/suspicious/noDuplicateTestHooks)


[error] 30-30: Disallow duplicate setup and teardown hooks.

Disallow after duplicacy inside the describe function.

(lint/suspicious/noDuplicateTestHooks)

test/enable-pathToRegexpModule.test.ts (3)

9-11: LGTM! Type annotations improve type safety.

The addition of TypeScript types for app, server, and host variables improves type safety and code maintainability.


13-16: Verify if the commented configuration can be removed.

The pathToRegexpModule configuration is commented out. If this configuration is no longer needed, consider removing it entirely rather than leaving it commented.

✅ Verification successful

Remove the commented-out configuration for clarity.

The repository search confirms that the pathToRegexpModule configuration only appears as commented-out code (both in the test and in src/app/middleware/multipart.ts) with no active usage. Its reference in the CHANGELOG suggests past support but no current reliance in the code. Therefore, it is safe to remove this commented configuration.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other usages of pathToRegexpModule
rg "pathToRegexpModule" -g "!test/enable-pathToRegexpModule.test.ts"

Length of output: 496


8-8: Verify if the test suite should remain skipped.

The test suite is currently disabled with .skip. Please verify if this is intentional and if there's a tracking issue for re-enabling these tests.

✅ Verification successful

Test suite intentionally skipped pending configuration update

The evidence confirms that the test suite in test/enable-pathToRegexpModule.test.ts remains disabled via .skip. The commented configuration line (// pathToRegexpModule: require.resolve('path-to-regexp-v8')) suggests that re-enabling is anticipated only after additional work or updates. No further tracking issue or context was found in the repository to indicate an immediate plan to re-enable the tests.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for related issues or TODOs about skipped tests
rg -i "enable-pathToRegexpModule.*skip" -g "!test/enable-pathToRegexpModule.test.ts"

Length of output: 86


Script:

#!/bin/bash
# Display the first 30 lines of the test file to inspect any comments or reasoning for skipping the suite
sed -n '1,30p' test/enable-pathToRegexpModule.test.ts

# Additionally, search the test file for keywords that might explain why the test suite is skipped
grep -Ei "(skip|TODO|disable|temporary)" test/enable-pathToRegexpModule.test.ts || echo "No skip-related comments found"

Length of output: 1084

test/stream-mode-with-filematch-glob.test.ts (2)

1-10: LGTM! Well-structured imports following Node.js best practices.

The import statements follow best practices by using the 'node:' prefix for built-in modules and properly handling ESM __filename/__dirname.


65-65: Verify the MIME type for TypeScript files.

The MIME type video/mp2t for a TypeScript file seems incorrect. TypeScript files typically use application/typescript or text/typescript.

test/stream-mode-with-filematch.test.ts Show resolved Hide resolved
@fengmk2 fengmk2 merged commit ccefb3e into master Feb 3, 2025
13 checks passed
@fengmk2 fengmk2 deleted the egg-v4 branch February 3, 2025 14:44
fengmk2 pushed a commit that referenced this pull request Feb 3, 2025
[skip ci]

## [4.0.0](v3.5.0...v4.0.0) (2025-02-03)

### ⚠ BREAKING CHANGES

* drop Node.js < 18.19.0 support

part of eggjs/egg#3644

eggjs/egg#5257

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
  - Introduced a new middleware for handling multipart requests.
  - Added improved error handling for oversized file uploads.

- **Refactor**
- Streamlined configuration and context enhancements for better
stability and TypeScript support.
- Modernized the codebase by transitioning to ES modules and updating
type definitions.

- **Chores**
- Updated package metadata, dependencies, and continuous integration
settings to support newer Node.js versions.
- Introduced a new TypeScript configuration for stricter type-checking.

- **Tests**
- Added unit tests to validate application behavior under incorrect
configurations.
- Established comprehensive tests for multipart form handling to ensure
correct processing of file uploads.
- Transitioned existing tests to TypeScript and updated assertions for
consistency.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

### Features

* support cjs and esm both by tshy ([#67](#67)) ([ccefb3e](ccefb3e))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

1 participant