Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ All notable changes are documented here. This project follows [Semantic Versioni

## [Unreleased]

## [2.5.0] - 2026-07-20

### Added

- Added App-root route-contract generation and validation scripts that discover local Feature Packages, update the single `RouteContracts.json`, and generate a searchable local route catalog.
- Added a URLRouterDemo build phase that verifies route contracts and refreshes the route catalog on every build.

### Changed

- Documented the App-root ownership model for route contracts and the Xcode/CI integration workflow in English and Chinese.

## [2.4.7] - 2026-07-19

### Changed
Expand Down
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ Add `URLRouter` to the App target and to any Feature Package that declares a

```swift
dependencies: [
.package(url: "https://github.com/relaxfinger/URLRouter.git", from: "2.4.7")
.package(url: "https://github.com/relaxfinger/URLRouter.git", from: "2.5.0")
]
```

Expand Down Expand Up @@ -172,9 +172,29 @@ lifecycle, telemetry, and coordinated concurrent routes.

```bash
swift test
swift Scripts/update_route_contracts.swift
swift Scripts/validate_route_contract.swift RouteContracts.json
```

`update_route_contracts.swift` scans every Swift Package in the App root that
declares a `RouteModule` and creates or updates the single App-owned
`RouteContracts.json`. Feature Packages do not keep their own copies. The
generator fails when it cannot reliably infer a route, rather than publishing a
guessed contract.

When URLRouter lives outside the App repository, point the script at the App
root (all relative paths below are resolved from it):

```bash
swift /path/to/URLRouter/Scripts/update_route_contracts.swift \
--app-root /path/to/MyApp \
--output RouteContracts.json
swift /path/to/URLRouter/Scripts/generate_route_catalog.swift \
--app-root /path/to/MyApp \
--contracts RouteContracts.json \
--output docs/route-catalog.html
```

The core library and `RouterHost` support all four listed Apple platforms. On
macOS, SwiftUI presents a `fullScreenCover` route as a sheet because macOS does
not provide `fullScreenCover`.
Expand Down
24 changes: 23 additions & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Package。

```swift
dependencies: [
.package(url: "https://github.com/relaxfinger/URLRouter.git", from: "2.4.7")
.package(url: "https://github.com/relaxfinger/URLRouter.git", from: "2.5.0")
]
```

Expand Down Expand Up @@ -168,9 +168,31 @@ URL builder、Universal Link、Tab 和带版本的路由协议。

```bash
swift test
swift Scripts/update_route_contracts.swift
swift Scripts/validate_route_contract.swift RouteContracts.json
swift Scripts/generate_route_catalog.swift
```

`update_route_contracts.swift` 会扫描当前 App 根目录内所有声明 `RouteModule` 的 Swift
Package,并生成或更新根目录唯一的 `RouteContracts.json`。随后,最后一条命令会扫描
同一批 Feature,并在
`docs/route-catalog.html` 生成可搜索的本地路由目录:URL 模板、路径/查询参数、目标页面、
Feature package 和展示方式都会列出。

当脚本放在 URLRouter 包内、但要扫描另一个 App 时,指定 App 根目录即可(契约和输出路径
均相对于该根目录):

```bash
swift /path/to/URLRouter/Scripts/generate_route_catalog.swift \
--app-root /path/to/MyApp \
--contracts RouteContracts.json \
--output docs/route-catalog.html
```

同一个 App 根目录只能有一份 `RouteContracts.json`;Feature Package 不应各自维护副本。
生成器会识别标准的 `RouteModule` 解析器、`ModuleRoute` 与 URL builder 写法;无法可靠推导
路径或参数时会失败,而不会生成猜测的契约。

核心库和 `RouterHost` 支持上述四个平台。macOS 的 SwiftUI 没有
`fullScreenCover`,因此该展示方式会自动以 sheet 呈现。

Expand Down
85 changes: 56 additions & 29 deletions RouteContracts.json
Original file line number Diff line number Diff line change
@@ -1,41 +1,68 @@
{
"schemaVersion": 1,
"supportedVersions": ["1"],
"routes": [
"routes" : [
{
"moduleID": "content",
"routeID": "article",
"pathTemplate": "/articles/:id",
"presentations": ["push"],
"requiredQueryItems": ["presentation", "version"]
"moduleID" : "navigation",
"pathTemplate" : "/",
"presentations" : [
"tab"
],
"requiredQueryItems" : [
"presentation",
"version"
],
"routeID" : "home"
},
{
"moduleID": "navigation",
"routeID": "home",
"pathTemplate": "/",
"presentations": ["tab"],
"requiredQueryItems": ["presentation", "version"]
"moduleID" : "navigation",
"pathTemplate" : "/favorites",
"presentations" : [
"tab"
],
"requiredQueryItems" : [
"presentation",
"version"
],
"routeID" : "favorites"
},
{
"moduleID": "navigation",
"routeID": "favorites",
"pathTemplate": "/favorites",
"presentations": ["tab"],
"requiredQueryItems": ["presentation", "version"]
"moduleID" : "navigation",
"pathTemplate" : "/settings",
"presentations" : [
"sheet"
],
"requiredQueryItems" : [
"presentation",
"version"
],
"routeID" : "settings"
},
{
"moduleID": "navigation",
"routeID": "settings",
"pathTemplate": "/settings",
"presentations": ["sheet"],
"requiredQueryItems": ["presentation", "version"]
"moduleID" : "navigation",
"pathTemplate" : "/sign-in",
"presentations" : [
"fullScreenCover"
],
"requiredQueryItems" : [
"presentation",
"version"
],
"routeID" : "signIn"
},
{
"moduleID": "navigation",
"routeID": "signIn",
"pathTemplate": "/sign-in",
"presentations": ["fullScreenCover"],
"requiredQueryItems": ["presentation", "version"]
"moduleID" : "content",
"pathTemplate" : "/articles/:id",
"presentations" : [
"push"
],
"requiredQueryItems" : [
"presentation",
"version"
],
"routeID" : "article"
}
],
"schemaVersion" : 1,
"supportedVersions" : [
"1"
]
}
}
Loading