Skip to content

feat: split swagger package in ui, generator and move preset#783

Merged
tada5hi merged 4 commits intomasterfrom
feat/swagger-bundle-preset
May 5, 2026
Merged

feat: split swagger package in ui, generator and move preset#783
tada5hi merged 4 commits intomasterfrom
feat/swagger-bundle-preset

Conversation

@tada5hi
Copy link
Copy Markdown
Contributor

@tada5hi tada5hi commented May 4, 2026

Summary by CodeRabbit

  • New Features

    • Split @routup/swagger into two packages: @routup/swagger-generator (spec generation) and @routup/swagger-ui (UI mounting); decorators package exposes a preset via a new subpath.
  • Documentation

    • Updated docs, READMEs and examples to reflect the new generator/UI split and updated plugin references.
  • Chores

    • Release tooling and manifest updated to publish the two new packages and link their versions.

Copilot AI review requested due to automatic review settings May 4, 2026 20:37
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

Warning

Rate limit exceeded

@tada5hi has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 50 minutes and 47 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ 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.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fee5452b-0b65-4852-b05f-0cc194db529e

📥 Commits

Reviewing files that changed from the base of the PR and between 0373b23 and 53b7447.

📒 Files selected for processing (6)
  • packages/docs/src/swagger-generator/index.md
  • packages/swagger-generator/README.md
  • packages/swagger-generator/src/generate-swagger.ts
  • packages/swagger-generator/src/index.ts
  • packages/swagger-generator/test/unit/v2/module.spec.ts
  • packages/swagger-generator/test/unit/v3/module.spec.ts
📝 Walkthrough

Walkthrough

The PR splits the monolithic @routup/swagger package into two packages—@routup/swagger-generator (OpenAPI generation) and @routup/swagger-ui (Swagger UI mounting)—moves preset handling into @routup/decorators (new ./preset export), and refactors the generator API to an options-driven generate() with automatic metadata/preset defaults.

Changes

Package Split & Architecture Refactor

Layer / File(s) Summary
Package Structure Setup
packages/swagger-generator/package.json, packages/swagger-generator/tsconfig.json, packages/swagger-generator/tsdown.config.ts, packages/swagger-ui/package.json, packages/swagger-ui/tsconfig.json, packages/swagger-ui/tsconfig.build.json, packages/swagger-ui/tsdown.config.ts
Added package manifests and build/TS configs for @routup/swagger-generator and @routup/swagger-ui; defines exports, scripts, and publish metadata.
Decorators Preset Export
packages/decorators/package.json, packages/decorators/tsdown.config.ts, packages/decorators/src/preset/module.ts
@routup/decorators gains a ./preset subpath export; buildPreset() now sets name to @routup/decorators; @trapi/metadata marked optional via peerDependenciesMeta.
Core Generate API & Logic
packages/swagger-generator/src/generate.ts, packages/swagger-generator/src/index.ts
Introduces GenerateOptions and overloads for generate() (options-driven API, defaulting to v3.2); merges DEFAULT_DATA with options.data via smob; normalizes/initializes metadata (auto-applies decorators preset and default entryPoint when missing); calls generateSwagger.
Public Exports & Re-exports
packages/swagger-generator/src/index.ts, packages/swagger-ui/src/index.ts, packages/swagger-ui/src/handler.ts
swagger-generator re-exports types from @trapi/metadata and @trapi/swagger, exports buildPreset from @routup/decorators/preset, and re-exports ./generate. swagger-ui updates internal import paths and adds a default export.
Documentation & Site
packages/docs/src/.vitepress/config.mts, packages/docs/src/.vitepress/theme/components/PluginGrid.vue, packages/docs/src/decorators/index.md, packages/docs/src/swagger-generator/index.md, packages/docs/src/swagger-ui/index.md, packages/docs/src/swagger/*, README.md, .agents/references/trapi.md, .agents/structure.md, packages/swagger-generator/README.md, packages/swagger-ui/README.md
Docs updated to replace unified swagger with swagger-generator and swagger-ui; new pages for generator/UI; removed old @routup/swagger docs; TRAPI/structure agent docs updated to reflect preset relocation and package split.
Release & Versioning
.release-please-manifest.json, release-please-config.json, .agents/conventions.md
Release manifest and config replace packages/swagger with packages/swagger-generator and packages/swagger-ui; add linked-versions group for the two components and document the linkage in conventions.
Tests & CI Config
packages/swagger-generator/test/unit/v2/module.spec.ts, packages/swagger-generator/test/unit/v3/module.spec.ts, packages/swagger-ui/test/vitest.config.ts
Unit tests updated to the new generate() argument shape (move servers into data, pass metadata at top-level); added Vitest config for swagger-ui with coverage thresholds.
Old Package Decomposition
packages/swagger/src/generator/constants.ts, packages/swagger/src/generator/index.ts, packages/swagger/src/generator/type.ts, packages/swagger/src/index.ts, packages/swagger/src/utils/index.ts, packages/swagger/CHANGELOG.md, packages/swagger/README.md, packages/swagger/writable/.gitignore
Removed re-exports, types, docs, and UI/default exports from the legacy @routup/swagger package (contents deleted/stripped), effectively deprecating the previous unified package in favor of the split packages.

Sequence Diagram

sequenceDiagram
    actor Dev
    participant Generator as "@routup/swagger-generator"
    participant Decorators as "@routup/decorators/preset"
    participant TRAPI as "@trapi/swagger"
    participant UI as "@routup/swagger-ui"

    Dev->>Generator: generate(options)
    Generator->>Generator: merge DEFAULT_DATA with options.data
    alt metadata.preset missing
        Generator->>Decorators: buildPreset()
        Decorators-->>Generator: Preset (name="@routup/decorators")
    end
    Generator->>TRAPI: generateSwagger({version, metadata, data})
    TRAPI-->>Generator: OpenAPI spec (v2/v3)
    Generator-->>Dev: OutputForVersion<V>

    Dev->>UI: swaggerUI(specOrUrl, options)
    UI->>UI: createUIHandler(...)
    UI-->>Dev: Handler (mountable on Router)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • routup/plugins#779: Changes to generate() API signature, metadata handling, and preset application align with the refactored generator implementation in this PR.

Poem

🐰 Once one swagger split in two,
Generator crafts specs brand new,
UI mounts them for all to view,
Decorators guide the cue—
Hoppity hooray, clean and true!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: split swagger package in ui, generator and move preset' clearly and specifically describes the main change in the PR: splitting a monolithic swagger package into separate ui and generator packages and moving a preset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/swagger-bundle-preset

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@tada5hi tada5hi changed the title Feat/swagger bundle preset feat: split swagger package in ui, generator and move preset May 4, 2026
tada5hi added 2 commits May 4, 2026 22:38
…r-ui

UI-only consumers no longer pull `@trapi/metadata` and `@trapi/swagger`
(both transitively need TypeScript), and generator-only consumers (CI
build steps) no longer pull `swagger-ui-dist` and its ~10MB of static
assets. Each half is independently versionable; they're kept aligned
via a release-please linked-versions group.

Layout:
- `@routup/swagger-generator` — `generate()`, `Version`, `buildPreset()`,
  bundled metadata preset (`packages/swagger-generator/src/{generator,preset}/`).
  No runtime routup dep.
- `@routup/swagger-ui` — `swaggerUI()`, `createUIHandler()`, URL helpers,
  `swagger-ui-dist` assets (`packages/swagger-ui/src/`,
  `packages/swagger-ui/assets/template.tpl`).

The internal preset name moved from `@routup/swagger` to
`@routup/swagger-generator` (only relevant if you cache by preset name).

BREAKING CHANGE: `@routup/swagger` is removed. Replace
`import { generate, Version, buildPreset } from '@routup/swagger'` with
`@routup/swagger-generator`, and `import { swaggerUI } from '@routup/swagger'`
with `@routup/swagger-ui`. Install whichever halves you need.
… API

The metadata preset now lives where it's most useful — next to the
decorators it decodes — and is published as the `./preset` subpath
export of `@routup/decorators`. Any trapi-based tool (the `trapi` CLI,
custom generators) can consume it directly via
`--preset @routup/decorators/preset` without depending on
`@routup/swagger-generator`.

`@routup/decorators` gains `@trapi/metadata` as an *optional* peer
dependency (peerDependenciesMeta.optional = true) — runtime-only users
who never touch the preset don't need it installed.

`@routup/swagger-generator` is now a thin wrapper:
- `generate()` takes `SwaggerGenerateOptions` directly
  (`{ version, metadata, data }`), the same shape as
  `@trapi/swagger`'s `generateSwagger()` — no more `GeneratorContext`
  wrapper, no more `options.metadata` / `options.<data fields>` mix.
- `buildPreset()` is re-exported from `@routup/decorators/preset` so
  it's still a single import for typical consumers, and the rest of
  `@trapi/swagger`'s public API (`Version`, `SpecV2`/`V3`,
  `saveSwagger`, types) is re-exported via `export * from
  '@trapi/swagger'`.
- The wrapper applies the same defaults as before (entryPoint =
  `<cwd>/src/**/*.ts`, ignore node_modules, preset = buildPreset(),
  version = V3_2, default data name/description/consumes/produces).

BREAKING CHANGE: `@routup/swagger-generator` no longer exports
`GeneratorContext`, `GeneratorOptionsInput`, or `GeneratorOutput`, and
`generate()`'s call shape changed. Migrate from
`generate({ version, options: { metadata, ...data } })` to
`generate({ version, metadata, data })`. The internal preset name
moved from `@routup/swagger-generator` to `@routup/decorators` (only
relevant if you cache by preset name).
@tada5hi tada5hi force-pushed the feat/swagger-bundle-preset branch from 3b3f7e4 to f7a6a87 Compare May 4, 2026 20:39
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR splits the former Swagger plugin into two focused packages—@routup/swagger-generator (OpenAPI generation via TRAPI + routup decorators preset) and @routup/swagger-ui (mounting Swagger UI from a spec/path/URL)—and updates release + docs metadata accordingly.

Changes:

  • Replace @routup/swagger / @routup/swagger-preset with @routup/swagger-generator and @routup/swagger-ui in release-please config, manifest, and root README.
  • Introduce new swagger-ui implementation pieces (handler/module/utils/url/type, assets template) plus Vitest setup and fixtures.
  • Move the TRAPI preset into @routup/decorators as a ./preset subpath export and update generator defaults/tests to use it.

Reviewed changes

Copilot reviewed 40 out of 60 changed files in this pull request and generated no comments.

Show a summary per file
File Description
release-please-config.json Swap old swagger packages to new generator/ui components + linked-versions group update.
README.md Update plugin list to reference swagger-generator and swagger-ui.
packages/swagger-ui/* New Swagger UI package structure, handler/utilities, assets template, and tests.
packages/swagger-generator/* New generator package structure, generate() API update, and tests.
packages/decorators/* Add ./preset entry build/export and implement preset handlers in decorators package.
packages/docs/src/* Update docs to reflect new package split and navigation entries.
package-lock.json Update lockfile for new workspaces/deps (currently inconsistent).
nx.json Formatting + disable analytics.
.release-please-manifest.json Manifest now tracks swagger-generator and swagger-ui packages.
.agents/* Update repo structure + conventions + TRAPI reference docs for the new split.
Comments suppressed due to low confidence (1)

packages/swagger-ui/src/handler.ts:20

  • createUIHandler() uses isFileURL() to decide whether to read the document from disk, but Node fs.readFileSync() won’t accept a "file://..." string path. Since isFileURL() currently returns true for file URLs (and the unit test asserts this), passing a file URL string as the document will be classified as “file” but then fail at runtime when reading. Fix by converting file URL strings to a URL object / file path (e.g. fileURLToPath(new URL(document)) or pass a URL object into readFileSync).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@tada5hi
Copy link
Copy Markdown
Contributor Author

tada5hi commented May 4, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@tada5hi
Copy link
Copy Markdown
Contributor Author

tada5hi commented May 4, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@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: 8

🧹 Nitpick comments (2)
packages/swagger-ui/test/vitest.config.ts (1)

11-16: 💤 Low value

Coverage thresholds, especially branches: 58, are quite low for a new package.

58% branch coverage leaves a significant portion of conditional logic untested. Consider raising these thresholds closer to the other metrics (lines/statements at 73%) or adding a tracking issue so they improve over time rather than codifying a low baseline.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/swagger-ui/test/vitest.config.ts` around lines 11 - 16, The branch
coverage threshold in the Vitest config's thresholds object (key: branches) is
set too low (58%); update the thresholds.branches value to be closer to
lines/statements (e.g., 73%) or create/link a tracking issue and add a comment
in the same vitest.config.ts indicating this is temporary and listing the issue
number so the low baseline isn't codified indefinitely; modify the thresholds
object in vitest.config.ts accordingly and ensure CI will fail if coverage drops
below the new value.
packages/swagger-ui/src/index.ts (1)

1-8: 💤 Low value

Intermediate import only needed for the default re-export — can be collapsed.

Line 1's import exists purely to power Line 8's export default. A re-export alias removes the extra step:

♻️ Proposed simplification
-import { swaggerUI } from './module';
-
 export * from './handler';
 export * from './module';
 export * from './type';
 export * from './utils';
-
-export default swaggerUI;
+export { swaggerUI as default } from './module';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/swagger-ui/src/index.ts` around lines 1 - 8, Remove the intermediate
import of swaggerUI and collapse it into a single re-export: replace the
standalone import of swaggerUI (currently used only to power the default export)
with a direct re-export from './module' so the module still exports everything
from './handler', './module', './type', './utils' and also exposes swaggerUI as
the default export; target the symbol swaggerUI from './module' and eliminate
the unused import line.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/decorators/package.json`:
- Around line 58-65: Update the peer dependency range for "@trapi/metadata" in
package.json so it will accept future pre-releases on the 2.x track; replace the
current "^2.0.0-beta.2" value with a more inclusive range such as
">=2.0.0-beta.2 <3.0.0" (or switch to "^2.0.0" once stable) in the
peerDependencies section so consumers running later 2.x betas (e.g.,
2.0.1-beta.1 or 2.1.0-beta.1) won't get false peer-dep warnings.

In `@packages/docs/src/swagger-generator/index.md`:
- Around line 30-44: The example broadens file discovery by setting
metadata.entryPoint.cwd to process.cwd() with pattern '**/*.ts'; either remove
the explicit entryPoint to use the generator's default scan root or narrow the
entryPoint to target the src tree (e.g., set metadata.entryPoint.cwd to
process.cwd() and metadata.entryPoint.pattern to 'src/**/*.ts'), updating the
example around generate and Version to ensure the snippet only scans source
files not repo-wide tests/configs.

In `@packages/swagger-generator/README.md`:
- Around line 47-58: The V2 README example uses process.cwd() but omits the
required ESM import; add "import process from 'node:process'" at the top of the
V2 snippet so the example that calls process.cwd() compiles in strict
ESM/no-global environments and matches the V3 example; update the code block
that shows generate(...) with Version.V2 (symbols: generate, Version,
process.cwd) to include that import.

In `@packages/swagger-generator/src/generate.ts`:
- Around line 23-27: The generic safety bug stems from GenerateOptions<V>
allowing an optional version, letting callers pick a non-default generic (e.g.,
V2) but pass no version at runtime; fix by making version required for the
generic parameter: change GenerateOptions<V extends `${Version}` = `${Version}`>
to require version: V (i.e., remove the optional from { version?: V } -> {
version: V }), and update generate<V = typeof Version.V3_2>(options:
GenerateOptions<V>) to use options.version directly (remove or avoid the runtime
fallback to Version.V3_2 and the unsafe as V cast); this ensures
OutputForVersion<V> matches the actual runtime options.version and preserves
type soundness for functions like generate and the OutputForVersion return type.
- Around line 28-29: The merge currently created with createMerger and used in
merge({}, DEFAULT_DATA, options.data || {}) prevents callers from replacing
default arrays because arrayDistinct/priority cause DEFAULT_DATA to win; to fix,
either create the merger with explicit options that allow overrides (e.g., set
array: false and priority: 'right' on the createMerger call where createMerger
is invoked) or flip the merge order so caller data is the rightmost source
(e.g., call merge({}, options.data || {}, DEFAULT_DATA)), ensuring DEFAULT_DATA,
merge, createMerger, and options.data/SwaggerGenerateData are the referenced
symbols to update.

In `@packages/swagger-ui/package.json`:
- Around line 57-61: The package.json currently lists "@types/swagger-ui-dist"
under "dependencies", which is wrong for a types-only package; update
package.json in the packages/swagger-ui manifest so that
"@types/swagger-ui-dist" is removed from "dependencies" and placed either into
"devDependencies" if the types are only used internally by this package (no
re-exports), or into "peerDependencies" if the declarations are part of the
public API surface re-exported by this package (so consumers control the
version); verify in src/index.ts whether the types are re-exported to choose the
correct target.

In `@packages/swagger-ui/README.md`:
- Line 29: The README example uses an internal test fixture path in the
router.use('/docs', swaggerUI('test/data/swagger.json')) line; replace that
repository-internal path with a generic or clearly-labelled "local file" example
(e.g., 'path/to/swagger.json' or a note like 'local-file: ./openapi.yaml'), or
add a separate “from a local file” example block, so callers using the
swaggerUI(...) helper see a realistic, non-repo-specific file path; update the
example text near the router.use(...) and swaggerUI(...) invocation to reflect
this change.
- Around line 3-6: The README badges point to the wrong GitHub repository
(Tada5hi/routup); update the badge URLs in the README so they reference the
correct repository (routup/plugins) and package scope for CI, codecov and Snyk.
Concretely, change the GitHub Actions badge link that references
actions/workflows/main.yml, the codecov URL that uses branch/master and token,
and the Snyk test URL so they target routup/plugins instead of Tada5hi/routup;
ensure the npm badge remains scoped to `@routup/swagger-ui` if applicable.

---

Nitpick comments:
In `@packages/swagger-ui/src/index.ts`:
- Around line 1-8: Remove the intermediate import of swaggerUI and collapse it
into a single re-export: replace the standalone import of swaggerUI (currently
used only to power the default export) with a direct re-export from './module'
so the module still exports everything from './handler', './module', './type',
'./utils' and also exposes swaggerUI as the default export; target the symbol
swaggerUI from './module' and eliminate the unused import line.

In `@packages/swagger-ui/test/vitest.config.ts`:
- Around line 11-16: The branch coverage threshold in the Vitest config's
thresholds object (key: branches) is set too low (58%); update the
thresholds.branches value to be closer to lines/statements (e.g., 73%) or
create/link a tracking issue and add a comment in the same vitest.config.ts
indicating this is temporary and listing the issue number so the low baseline
isn't codified indefinitely; modify the thresholds object in vitest.config.ts
accordingly and ensure CI will fail if coverage drops below the new value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 12c65398-bd94-48a6-b09a-ecee44d02fd8

📥 Commits

Reviewing files that changed from the base of the PR and between 5386ee3 and f7a6a87.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (59)
  • .agents/conventions.md
  • .agents/references/trapi.md
  • .agents/structure.md
  • .release-please-manifest.json
  • README.md
  • packages/decorators/package.json
  • packages/decorators/src/preset/class.ts
  • packages/decorators/src/preset/index.ts
  • packages/decorators/src/preset/method.ts
  • packages/decorators/src/preset/module.ts
  • packages/decorators/src/preset/parameter.ts
  • packages/decorators/src/preset/swagger.ts
  • packages/decorators/tsdown.config.ts
  • packages/docs/src/.vitepress/config.mts
  • packages/docs/src/.vitepress/theme/components/PluginGrid.vue
  • packages/docs/src/decorators/index.md
  • packages/docs/src/swagger-generator/index.md
  • packages/docs/src/swagger-ui/index.md
  • packages/docs/src/swagger/generator.md
  • packages/docs/src/swagger/index.md
  • packages/swagger-generator/LICENSE
  • packages/swagger-generator/README.md
  • packages/swagger-generator/package.json
  • packages/swagger-generator/src/generate.ts
  • packages/swagger-generator/src/index.ts
  • packages/swagger-generator/test/unit/v2/module.spec.ts
  • packages/swagger-generator/test/unit/v3/module.spec.ts
  • packages/swagger-generator/test/vitest.config.ts
  • packages/swagger-generator/tsconfig.build.json
  • packages/swagger-generator/tsconfig.json
  • packages/swagger-generator/tsdown.config.ts
  • packages/swagger-ui/LICENSE
  • packages/swagger-ui/README.md
  • packages/swagger-ui/assets/template.tpl
  • packages/swagger-ui/package.json
  • packages/swagger-ui/src/constants.ts
  • packages/swagger-ui/src/handler.ts
  • packages/swagger-ui/src/index.ts
  • packages/swagger-ui/src/module.ts
  • packages/swagger-ui/src/object.ts
  • packages/swagger-ui/src/type.ts
  • packages/swagger-ui/src/url.ts
  • packages/swagger-ui/src/utils.ts
  • packages/swagger-ui/test/data/swagger.json
  • packages/swagger-ui/test/unit/ui/module.spec.ts
  • packages/swagger-ui/test/unit/ui/utils.spec.ts
  • packages/swagger-ui/test/vitest.config.ts
  • packages/swagger-ui/tsconfig.build.json
  • packages/swagger-ui/tsconfig.json
  • packages/swagger-ui/tsdown.config.ts
  • packages/swagger/CHANGELOG.md
  • packages/swagger/README.md
  • packages/swagger/src/generator/constants.ts
  • packages/swagger/src/generator/index.ts
  • packages/swagger/src/generator/type.ts
  • packages/swagger/src/index.ts
  • packages/swagger/src/utils/index.ts
  • packages/swagger/writable/.gitignore
  • release-please-config.json
💤 Files with no reviewable changes (11)
  • packages/swagger/src/generator/constants.ts
  • packages/swagger/writable/.gitignore
  • packages/swagger/src/utils/index.ts
  • packages/swagger/src/generator/index.ts
  • packages/swagger-ui/tsconfig.json
  • packages/docs/src/swagger/index.md
  • packages/swagger/CHANGELOG.md
  • packages/swagger/src/generator/type.ts
  • packages/docs/src/swagger/generator.md
  • packages/swagger/README.md
  • packages/swagger/src/index.ts

Comment thread packages/decorators/package.json Outdated
Comment thread packages/docs/src/swagger-generator/index.md Outdated
Comment thread packages/swagger-generator/README.md
Comment thread packages/swagger-generator/src/generate.ts Outdated
Comment thread packages/swagger-generator/src/generate.ts Outdated
Comment thread packages/swagger-ui/package.json
Comment on lines +3 to +6
[![npm version](https://badge.fury.io/js/@routup%2Fswagger-ui.svg)](https://badge.fury.io/js/@routup%2Fswagger-ui)
[![main](https://github.com/Tada5hi/routup/actions/workflows/main.yml/badge.svg)](https://github.com/Tada5hi/routup/actions/workflows/main.yml)
[![codecov](https://codecov.io/gh/tada5hi/routup/branch/master/graph/badge.svg?token=QFGCsHRUax)](https://codecov.io/gh/tada5hi/routup)
[![Known Vulnerabilities](https://snyk.io/test/github/Tada5hi/routup/badge.svg)](https://snyk.io/test/github/Tada5hi/routup)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Badge URLs point to the wrong repository.

Lines 4–6 reference Tada5hi/routup (the author's personal repo) instead of routup/plugins where this package actually lives. CI, codecov, and Snyk badges will show stale status from an unrelated repo.

🔧 Proposed fix
-[![main](https://github.com/Tada5hi/routup/actions/workflows/main.yml/badge.svg)](https://github.com/Tada5hi/routup/actions/workflows/main.yml)
-[![codecov](https://codecov.io/gh/tada5hi/routup/branch/master/graph/badge.svg?token=QFGCsHRUax)](https://codecov.io/gh/tada5hi/routup)
-[![Known Vulnerabilities](https://snyk.io/test/github/Tada5hi/routup/badge.svg)](https://snyk.io/test/github/Tada5hi/routup)
+[![main](https://github.com/routup/plugins/actions/workflows/main.yml/badge.svg)](https://github.com/routup/plugins/actions/workflows/main.yml)
+[![codecov](https://codecov.io/gh/routup/plugins/branch/master/graph/badge.svg)](https://codecov.io/gh/routup/plugins)
+[![Known Vulnerabilities](https://snyk.io/test/github/routup/plugins/badge.svg)](https://snyk.io/test/github/routup/plugins)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
[![npm version](https://badge.fury.io/js/@routup%2Fswagger-ui.svg)](https://badge.fury.io/js/@routup%2Fswagger-ui)
[![main](https://github.com/Tada5hi/routup/actions/workflows/main.yml/badge.svg)](https://github.com/Tada5hi/routup/actions/workflows/main.yml)
[![codecov](https://codecov.io/gh/tada5hi/routup/branch/master/graph/badge.svg?token=QFGCsHRUax)](https://codecov.io/gh/tada5hi/routup)
[![Known Vulnerabilities](https://snyk.io/test/github/Tada5hi/routup/badge.svg)](https://snyk.io/test/github/Tada5hi/routup)
[![npm version](https://badge.fury.io/js/@routup%2Fswagger-ui.svg)](https://badge.fury.io/js/@routup%2Fswagger-ui)
[![main](https://github.com/routup/plugins/actions/workflows/main.yml/badge.svg)](https://github.com/routup/plugins/actions/workflows/main.yml)
[![codecov](https://codecov.io/gh/routup/plugins/branch/master/graph/badge.svg)](https://codecov.io/gh/routup/plugins)
[![Known Vulnerabilities](https://snyk.io/test/github/routup/plugins/badge.svg)](https://snyk.io/test/github/routup/plugins)
🧰 Tools
🪛 LanguageTool

[style] ~3-~3: Using many exclamation marks might seem excessive (in this case: 3 exclamation marks for a text that’s 963 characters long)
Context: .../badge.fury.io/js/@routup%2Fswagger-ui) main codecov [![Known Vulnerabilities](https://snyk.io/...

(EN_EXCESSIVE_EXCLAMATION)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/swagger-ui/README.md` around lines 3 - 6, The README badges point to
the wrong GitHub repository (Tada5hi/routup); update the badge URLs in the
README so they reference the correct repository (routup/plugins) and package
scope for CI, codecov and Snyk. Concretely, change the GitHub Actions badge link
that references actions/workflows/main.yml, the codecov URL that uses
branch/master and token, and the Snyk test URL so they target routup/plugins
instead of Tada5hi/routup; ensure the npm badge remains scoped to
`@routup/swagger-ui` if applicable.

Comment thread packages/swagger-ui/README.md Outdated
tada5hi added 2 commits May 5, 2026 10:08
- generate(): switch to overload signatures so version is required when V
  is non-default, eliminating the unsound `as V` cast that let
  `generate<typeof Version.V2>({})` compile while returning a V3_2 spec
  at runtime.
- generate(): swap the smob merger to `{ array: false, priority: 'right' }`
  so callers can actually replace `name`, `description`, and the
  `consumes`/`produces` arrays in `data` — the previous left-priority
  array-merge silently appended to defaults instead of overriding.
- decorators: widen the new `@trapi/metadata` peer range to
  `>=2.0.0-beta.2 <3.0.0` — caret + pre-release semver excludes future
  pre-releases on a higher patch/minor (e.g., 2.0.1-beta.1) which would
  produce false peer warnings.
- swagger-ui: move `@types/swagger-ui-dist` from `dependencies` to
  `peerDependencies` (with a devDep mirror for typecheck) — the types
  flow through the public `UIOptions` / `Spec` surface, so the consumer
  should control the version.
- docs: drop the explicit `metadata.entryPoint = { cwd: process.cwd(),
  pattern: '**/*.ts' }` from generator examples; the wrapper default
  already scans `<cwd>/src/**/*.ts`, and the explicit form broadened
  copy-paste discovery to repo-wide tests/configs.
- swagger-ui README: replace `test/data/swagger.json` (repo-internal
  fixture) with `./openapi.json` so the example reads as a generic
  caller path.

Repo-wide README badge URLs (`Tada5hi/routup` → `routup/plugins`)
deferred to issue #784 to keep this PR scoped.
…and trim re-exports

Renames the public entry point from `generate` to `generateSwagger` so
the wrapper reads as a routup-flavored variant of `@trapi/swagger`'s
upstream `generateSwagger()` — same name, same shape, plus the
routup-specific defaults. Also rename the source file
`src/generate.ts` → `src/generate-swagger.ts` to match.

Trim the public re-exports to the minimum needed for the
`generateSwagger()` call path:
- types: `OutputForVersion`, `SpecV2`, `SpecV3`,
  `SwaggerGenerateData`, `SwaggerGenerateOptions`, `SwaggerSaveOptions`
  (plus the metadata types for the `metadata` field)
- values: `Version`, `saveSwagger`

Anything else from `@trapi/swagger` (parameter variants, security
schemes, generator classes, low-level helpers) is now imported
directly from `@trapi/swagger`. Same for `buildPreset` — drop it from
`@routup/swagger-generator`'s surface so consumers import it from
`@routup/decorators/preset` (the canonical location), keeping the
seams clean.

BREAKING CHANGE: `generate()` is now `generateSwagger()`. The
`buildPreset` re-export from `@routup/swagger-generator` is removed —
`import { buildPreset } from '@routup/decorators/preset'` instead.
The wide re-export of `@trapi/swagger` is narrowed; types/values not
in the trimmed list above must now be imported from `@trapi/swagger`
directly.
Copy link
Copy Markdown

@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 (2)
packages/decorators/package.json (1)

72-72: 💤 Low value

devDependencies range for @trapi/metadata is narrower than the peer range.

The peer range (>=2.0.0-beta.2 <3.0.0) now intentionally accepts future 2.x pre-releases (e.g. 2.0.1-beta.1, 2.1.0-beta.1), but the devDependency ^2.0.0-beta.2 won't resolve those same versions — ^ on a pre-release tuple only covers pre-releases with the exact same major.minor.patch base. This means local CI/builds won't exercise the package against newer 2.x betas as they ship, creating a subtle gap between what's tested and what's allowed by the peer range.

🔧 Proposed fix
-        "@trapi/metadata": "^2.0.0-beta.2",
+        "@trapi/metadata": ">=2.0.0-beta.2 <3.0.0",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/decorators/package.json` at line 72, The devDependency for
`@trapi/metadata` in devDependencies is too narrow compared to the
peerDependencies range; update the devDependencies entry for "@trapi/metadata"
to match the peer range (for example use ">=2.0.0-beta.2 <3.0.0") so local
CI/tests exercise the same 2.x beta releases the peer range allows, then
regenerate your lockfile (npm/yarn install) to persist the change.
packages/swagger-ui/package.json (1)

54-57: ⚡ Quick win

Mark @types/swagger-ui-dist as an optional peer dependency.

@types/swagger-ui-dist latest is 3.30.6, so the ^3.30.5 range is fine. However, listing it as a non-optional peer dependency means every consumer — including plain-JavaScript projects and TypeScript projects that don't need to use the types directly — will receive an unmet peer dependency warning if they don't install it. Adding peerDependenciesMeta with optional: true is the standard pattern for @types/* peer deps.

📦 Proposed fix
     "peerDependencies": {
         "@types/swagger-ui-dist": "^3.30.5",
         "routup": "^5.0.0-beta.6"
     },
+    "peerDependenciesMeta": {
+        "@types/swagger-ui-dist": {
+            "optional": true
+        }
+    },
     "dependencies": {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/swagger-ui/package.json` around lines 54 - 57, Update package.json
to mark the `@types` swagger peer as optional: in the same package.json that
declares "peerDependencies" with "@types/swagger-ui-dist": "^3.30.5", add a
"peerDependenciesMeta" object and set " `@types/swagger-ui-dist`": { "optional":
true } (use the exact package name "@types/swagger-ui-dist" as the key) so
consumers that don’t need the types won’t get unmet peer dependency warnings
while preserving the existing version range.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/swagger-generator/src/generate.ts`:
- Around line 26-31: The overloads for generate are unsound because a
GenerateOptions value with an optional version can match the no-version
overload; make them mutually exclusive by requiring the "no-version" overload to
explicitly forbid a version and the other to require it: change the first
overload signature to accept Omit<GenerateOptions,'version'> & { version?:
undefined } and keep the second as Omit<GenerateOptions,'version'> & { version:
V } (generic V) so generate(...) returns OutputForVersion<typeof Version.V3_2>
when no version is provided and OutputForVersion<V> when a concrete version is
supplied; update references to GenerateOptions, Version, OutputForVersion, and
the generate function accordingly.

---

Nitpick comments:
In `@packages/decorators/package.json`:
- Line 72: The devDependency for `@trapi/metadata` in devDependencies is too
narrow compared to the peerDependencies range; update the devDependencies entry
for "@trapi/metadata" to match the peer range (for example use ">=2.0.0-beta.2
<3.0.0") so local CI/tests exercise the same 2.x beta releases the peer range
allows, then regenerate your lockfile (npm/yarn install) to persist the change.

In `@packages/swagger-ui/package.json`:
- Around line 54-57: Update package.json to mark the `@types` swagger peer as
optional: in the same package.json that declares "peerDependencies" with
"@types/swagger-ui-dist": "^3.30.5", add a "peerDependenciesMeta" object and set
" `@types/swagger-ui-dist`": { "optional": true } (use the exact package name
"@types/swagger-ui-dist" as the key) so consumers that don’t need the types
won’t get unmet peer dependency warnings while preserving the existing version
range.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1d549be2-92f4-4391-8082-249bf7baf7a2

📥 Commits

Reviewing files that changed from the base of the PR and between f7a6a87 and 0373b23.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (7)
  • packages/decorators/package.json
  • packages/docs/src/swagger-generator/index.md
  • packages/docs/src/swagger-ui/index.md
  • packages/swagger-generator/README.md
  • packages/swagger-generator/src/generate.ts
  • packages/swagger-ui/README.md
  • packages/swagger-ui/package.json
✅ Files skipped from review due to trivial changes (4)
  • packages/swagger-ui/README.md
  • packages/swagger-generator/README.md
  • packages/docs/src/swagger-generator/index.md
  • packages/docs/src/swagger-ui/index.md

Comment on lines +26 to +31
export function generate(
options: Omit<GenerateOptions, 'version'>,
): Promise<OutputForVersion<typeof Version.V3_2>>;
export function generate<V extends `${Version}`>(
options: Omit<GenerateOptions, 'version'> & { version: V },
): Promise<OutputForVersion<V>>;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

TypeScript overload resolution: can a value typed as { version?: string }satisfy a parameter type omittingversion, and does that affect which overload is selected?

💡 Result:

Yes. A value of type { version?: string } can satisfy a parameter type that omits version (e.g. {} or an object type without a required version property), and that does not inherently force a different overload to be selected. 1) Why it satisfies the parameter type TypeScript uses structural typing: an object type is compatible with another as long as it has at least the required members of the target type; extra properties are allowed. So if the parameter type doesn’t require version, the optional version?: string property doesn’t prevent assignability. This is consistent with the general assignability/structural compatibility rules in the TS docs. [1] 2) Does that affect which overload is chosen? In overload resolution, TypeScript selects the overload whose parameter type is compatible with the argument type. If both the “version-omitting” parameter type and the argument type are compatible, then the argument can match that overload. There isn’t a special “optional property presence changes overload selection” rule; selection is driven by which overload signatures are applicable under assignability. [2] Important caveat There are known/long-standing edge cases where overload resolution can behave unexpectedly when one of the parameter types has only optional properties (see TypeScript issue #2634). That’s about overload matching quirks in the presence of “all-optional” object shapes, not about normal cases where the parameter simply omits a property. [3] So in the common case you asked about (parameter type omits version, argument type has version?: string), it should still match the “omitting version” overload; the overload selection should be unaffected by merely having an optional extra property. [1][2]

Citations:


🏁 Script executed:

# First, let's see the file and understand the context around lines 26-31 and 59
head -80 packages/swagger-generator/src/generate.ts | cat -n

Repository: routup/plugins

Length of output: 2489


🏁 Script executed:

# Also check if GenerateOptions is defined in this file
grep -n "GenerateOptions" packages/swagger-generator/src/generate.ts | head -20

Repository: routup/plugins

Length of output: 310


Overload typing is unsound for GenerateOptions-typed variables.

A variable typed as GenerateOptions structurally satisfies Omit<GenerateOptions, 'version'> (because having an optional version property is compatible with omitting it), so the first overload (lines 26-28) may be selected even when the variable carries a version property at runtime. This causes the return type to resolve to V3_2 while line 59 may actually generate a different version, violating type safety.

💡 Suggested type-safe overload shape
 export type GenerateOptions = Partial<SwaggerGenerateOptions>;
+type GenerateOptionsWithoutVersion = Omit<GenerateOptions, 'version'> & { version?: never };

 export function generate(): Promise<OutputForVersion<typeof Version.V3_2>>;
 export function generate(
-    options: Omit<GenerateOptions, 'version'>,
+    options: GenerateOptionsWithoutVersion,
 ): Promise<OutputForVersion<typeof Version.V3_2>>;
 export function generate<V extends `${Version}`>(
     options: Omit<GenerateOptions, 'version'> & { version: V },
 ): Promise<OutputForVersion<V>>;
+export function generate(
+    options: GenerateOptions,
+): Promise<OutputForVersion<`${Version}`>>;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function generate(
options: Omit<GenerateOptions, 'version'>,
): Promise<OutputForVersion<typeof Version.V3_2>>;
export function generate<V extends `${Version}`>(
options: Omit<GenerateOptions, 'version'> & { version: V },
): Promise<OutputForVersion<V>>;
type GenerateOptionsWithoutVersion = Omit<GenerateOptions, 'version'> & { version?: never };
export function generate(): Promise<OutputForVersion<typeof Version.V3_2>>;
export function generate(
options: GenerateOptionsWithoutVersion,
): Promise<OutputForVersion<typeof Version.V3_2>>;
export function generate<V extends `${Version}`>(
options: Omit<GenerateOptions, 'version'> & { version: V },
): Promise<OutputForVersion<V>>;
export function generate(
options: GenerateOptions,
): Promise<OutputForVersion<`${Version}`>>;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/swagger-generator/src/generate.ts` around lines 26 - 31, The
overloads for generate are unsound because a GenerateOptions value with an
optional version can match the no-version overload; make them mutually exclusive
by requiring the "no-version" overload to explicitly forbid a version and the
other to require it: change the first overload signature to accept
Omit<GenerateOptions,'version'> & { version?: undefined } and keep the second as
Omit<GenerateOptions,'version'> & { version: V } (generic V) so generate(...)
returns OutputForVersion<typeof Version.V3_2> when no version is provided and
OutputForVersion<V> when a concrete version is supplied; update references to
GenerateOptions, Version, OutputForVersion, and the generate function
accordingly.

@tada5hi tada5hi merged commit bd81c1c into master May 5, 2026
6 of 7 checks passed
@github-actions github-actions Bot mentioned this pull request May 5, 2026
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