diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4d4df94867..fa874896fb7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1998,8 +1998,8 @@ jobs: - name: Swift lint run: | - swiftlint --config .swiftlint.yml - swiftformat --lint apps/macos/Sources --config .swiftformat + swiftlint lint --config config/swiftlint.yml + swiftformat --lint apps/macos/Sources --config config/swiftformat --exclude '**/OpenClawProtocol,**/HostEnvSecurityPolicy.generated.swift' - name: Swift build (release) run: | diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5f88e66d46c..880d4c01372 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -97,7 +97,7 @@ repos: # swiftlint (same as CI) - id: swiftlint name: swiftlint - entry: swiftlint --config .swiftlint.yml + entry: swiftlint lint --config config/swiftlint.yml language: system pass_filenames: false types: [swift] @@ -105,7 +105,7 @@ repos: # swiftformat --lint (same as CI) - id: swiftformat name: swiftformat - entry: swiftformat --lint apps/macos/Sources --config .swiftformat + entry: swiftformat --lint apps/macos/Sources --config config/swiftformat --exclude '**/OpenClawProtocol,**/HostEnvSecurityPolicy.generated.swift' language: system pass_filenames: false types: [swift] diff --git a/apps/ios/.swiftlint.yml b/apps/ios/.swiftlint.yml index 23db4515968..d88d6e49a96 100644 --- a/apps/ios/.swiftlint.yml +++ b/apps/ios/.swiftlint.yml @@ -1,4 +1,4 @@ -parent_config: ../../.swiftlint.yml +parent_config: ../../config/swiftlint.yml included: - Sources diff --git a/apps/ios/project.yml b/apps/ios/project.yml index 6229d45a816..cd219783101 100644 --- a/apps/ios/project.yml +++ b/apps/ios/project.yml @@ -70,7 +70,7 @@ targets: echo "error: swiftformat not found (brew install swiftformat)" >&2 exit 1 fi - swiftformat --lint --config "$SRCROOT/../../.swiftformat" \ + swiftformat --lint --config "$SRCROOT/../../config/swiftformat" \ --unexclude "$SRCROOT/Sources,$SRCROOT/ShareExtension,$SRCROOT/ActivityWidget,$SRCROOT/WatchExtension,$SRCROOT/../shared/OpenClawKit,$SRCROOT/../swabble" \ --filelist "$SRCROOT/SwiftSources.input.xcfilelist" - name: SwiftLint diff --git a/config/swiftformat b/config/swiftformat new file mode 100644 index 00000000000..8cc0fcbf19b --- /dev/null +++ b/config/swiftformat @@ -0,0 +1,51 @@ +# SwiftFormat configuration adapted from Peekaboo defaults (Swift 6 friendly) + +--swiftversion 6.2 + +# Self handling +--self insert +--selfrequired + +# Imports / extensions +--importgrouping testable-bottom +--extensionacl on-declarations + +# Indentation +--indent 4 +--indentcase false +--ifdef no-indent +--xcodeindentation enabled + +# Line breaks +--linebreaks lf +--maxwidth 120 + +# Whitespace +--trimwhitespace always +--emptybraces no-space +--nospaceoperators ...,..< +--ranges no-space +--someAny true +--voidtype void + +# Wrapping +--wraparguments before-first +--wrapparameters before-first +--wrapcollections before-first +--closingparen same-line + +# Organization +--organizetypes class,struct,enum,extension +--extensionmark "MARK: - %t + %p" +--marktypes always +--markextensions always +--structthreshold 0 +--enumthreshold 0 + +# Other +--stripunusedargs closure-only +--header ignore +--allman false + +# Exclusions +--exclude .build,.swiftpm,DerivedData,node_modules,dist,coverage,xcuserdata,Peekaboo,apps/swabble,apps/android,apps/ios,apps/shared diff --git a/config/swiftlint.yml b/config/swiftlint.yml new file mode 100644 index 00000000000..7a718857199 --- /dev/null +++ b/config/swiftlint.yml @@ -0,0 +1,150 @@ +# SwiftLint configuration adapted from Peekaboo defaults (Swift 6 friendly) + +included: + - ../apps/macos/Sources + +excluded: + - ../.build + - ../DerivedData + - "**/.build" + - "**/.swiftpm" + - "**/DerivedData" + - "**/Generated" + - "**/Resources" + - "**/Package.swift" + - "**/Tests/Resources" + - ../node_modules + - ../dist + - ../coverage + - "*.playground" + # Generated (protocol-gen-swift.ts) + - ../apps/macos/Sources/OpenClawProtocol/GatewayModels.swift + # Generated (generate-host-env-security-policy-swift.mjs) + - ../apps/macos/Sources/OpenClaw/HostEnvSecurityPolicy.generated.swift + +analyzer_rules: + - unused_declaration + - unused_import + +opt_in_rules: + - array_init + - closure_spacing + - contains_over_first_not_nil + - empty_count + - empty_string + - explicit_init + - fallthrough + - fatal_error_message + - first_where + - joined_default_parameter + - last_where + - literal_expression_end_indentation + - multiline_arguments + - multiline_parameters + - operator_usage_whitespace + - overridden_super_call + - pattern_matching_keywords + - private_outlet + - prohibited_super_call + - redundant_nil_coalescing + - sorted_first_last + - switch_case_alignment + - unneeded_parentheses_in_closure_argument + - vertical_parameter_alignment_on_call + +disabled_rules: + # SwiftFormat handles these + - trailing_whitespace + - trailing_newline + - trailing_comma + - vertical_whitespace + - indentation_width + + # Style exclusions + - explicit_self + - identifier_name + - file_header + - explicit_top_level_acl + - explicit_acl + - explicit_type_interface + - missing_docs + - required_deinit + - prefer_nimble + - quick_discouraged_call + - quick_discouraged_focused_test + - quick_discouraged_pending_test + - anonymous_argument_in_multiline_closure + - no_extension_access_modifier + - no_grouping_extension + - switch_case_on_newline + - strict_fileprivate + - extension_access_modifier + - convenience_type + - no_magic_numbers + - one_declaration_per_file + - vertical_whitespace_between_cases + - vertical_whitespace_closing_braces + - superfluous_else + - number_separator + - prefixed_toplevel_constant + - opening_brace + - trailing_closure + - contrasted_opening_brace + - sorted_imports + - redundant_type_annotation + - shorthand_optional_binding + - untyped_error_in_catch + - file_name + - todo + +force_cast: warning +force_try: warning + +type_name: + min_length: + warning: 2 + error: 1 + max_length: + warning: 60 + error: 80 + +function_body_length: + warning: 150 + error: 300 + +function_parameter_count: + warning: 7 + error: 10 + +file_length: + warning: 1500 + error: 2500 + ignore_comment_only_lines: true + +type_body_length: + warning: 800 + error: 1200 + +cyclomatic_complexity: + warning: 20 + error: 120 + +large_tuple: + warning: 4 + error: 5 + +nesting: + type_level: + warning: 4 + error: 6 + function_level: + warning: 5 + error: 7 + +line_length: + warning: 120 + error: 250 + ignores_comments: true + ignores_urls: true + +reporter: "xcode" diff --git a/package.json b/package.json index 2c7052d3a7b..85156ff10b0 100644 --- a/package.json +++ b/package.json @@ -1376,7 +1376,7 @@ "format:docs": "node scripts/format-docs.mjs", "format:docs:check": "node scripts/format-docs.mjs --check", "format:fix": "oxfmt --write --threads=1", - "format:swift": "swiftformat --lint --config .swiftformat apps/macos/Sources apps/ios/Sources apps/shared/OpenClawKit/Sources", + "format:swift": "swiftformat --lint --config config/swiftformat --exclude '**/apps/swabble,**/apps/android,**/apps/ios,**/apps/shared,**/OpenClawProtocol,**/HostEnvSecurityPolicy.generated.swift' apps/macos/Sources apps/ios/Sources apps/shared/OpenClawKit/Sources", "gateway:dev": "OPENCLAW_SKIP_CHANNELS=1 node scripts/run-node.mjs --dev gateway", "gateway:dev:reset": "OPENCLAW_SKIP_CHANNELS=1 node scripts/run-node.mjs --dev gateway --reset", "gateway:watch": "node scripts/gateway-watch-tmux.mjs gateway --force", @@ -1421,7 +1421,7 @@ "lint:plugins:no-register-http-handler": "node scripts/check-no-register-http-handler.mjs", "lint:plugins:plugin-sdk-subpaths-exported": "node scripts/check-plugin-sdk-subpath-exports.mjs", "lint:scripts": "pnpm lint:docker-e2e && node scripts/run-oxlint.mjs --tsconfig tsconfig.oxlint.scripts.json scripts", - "lint:swift": "swiftlint lint --config .swiftlint.yml && (cd apps/ios && swiftlint lint --config .swiftlint.yml)", + "lint:swift": "swiftlint lint --config config/swiftlint.yml && (cd apps/ios && swiftlint lint --config .swiftlint.yml)", "lint:tmp:channel-agnostic-boundaries": "node scripts/check-channel-agnostic-boundaries.mjs", "lint:tmp:dynamic-import-warts": "node scripts/check-dynamic-import-warts.mjs", "lint:tmp:no-random-messaging": "node scripts/check-no-random-messaging-tmp.mjs", diff --git a/scripts/changed-lanes.mjs b/scripts/changed-lanes.mjs index 62333a42a62..ab6588f8d29 100644 --- a/scripts/changed-lanes.mjs +++ b/scripts/changed-lanes.mjs @@ -9,7 +9,7 @@ const APP_PATH_RE = /^(?:apps\/|Swabble\/|appcast\.xml$)/u; const EXTENSION_PATH_RE = /^extensions\/[^/]+(?:\/|$)/u; const CORE_PATH_RE = /^(?:src\/|ui\/|packages\/)/u; const TOOLING_PATH_RE = - /^(?:scripts\/|test\/vitest\/|\.github\/|\.vscode\/|config\/|deploy\/|git-hooks\/|Dockerfile\.sandbox(?:-(?:browser|common))?$|Makefile$|docker-setup\.sh$|setup-podman\.sh$|openclaw\.podman\.env$|skills\/pyproject\.toml$|vitest(?:\..+)?\.config\.ts$|tsconfig.*\.json$|\.dockerignore$|\.gitignore$|\.jscpd\.json$|\.npmignore$|\.pre-commit-config\.yaml$|\.swiftformat$|\.oxlint.*|\.oxfmt.*)/u; + /^(?:scripts\/|test\/vitest\/|\.github\/|\.vscode\/|config\/|deploy\/|git-hooks\/|Dockerfile\.sandbox(?:-(?:browser|common))?$|Makefile$|docker-setup\.sh$|setup-podman\.sh$|openclaw\.podman\.env$|skills\/pyproject\.toml$|vitest(?:\..+)?\.config\.ts$|tsconfig.*\.json$|\.dockerignore$|\.gitignore$|\.jscpd\.json$|\.npmignore$|\.pre-commit-config\.yaml$|\.swiftformat$|\.swiftlint\.yml$|\.oxlint.*|\.oxfmt.*)/u; const ROOT_GLOBAL_PATH_RE = /^(?:package\.json$|pnpm-lock\.yaml$|pnpm-workspace\.yaml$|tsdown\.config\.ts$|vitest\.config\.ts$)/u; const LEGACY_ROOT_ASSET_PATH_RE = /^assets\//u; diff --git a/scripts/prepush-ci.sh b/scripts/prepush-ci.sh index c31f09959ee..8111b3acfeb 100644 --- a/scripts/prepush-ci.sh +++ b/scripts/prepush-ci.sh @@ -81,8 +81,8 @@ run_macos_ci_mirror() { return 0 fi - run_step swiftlint --config .swiftlint.yml - run_step swiftformat --lint apps/macos/Sources --config .swiftformat + run_step swiftlint lint --config config/swiftlint.yml + run_step swiftformat --lint apps/macos/Sources --config config/swiftformat --exclude '**/OpenClawProtocol,**/HostEnvSecurityPolicy.generated.swift' run_step swift build --package-path apps/macos --configuration release run_step swift test --package-path apps/macos --parallel } diff --git a/test/scripts/changed-lanes.test.ts b/test/scripts/changed-lanes.test.ts index bead8dc0539..b3034f6dcb1 100644 --- a/test/scripts/changed-lanes.test.ts +++ b/test/scripts/changed-lanes.test.ts @@ -327,10 +327,13 @@ describe("scripts/changed-lanes", () => { ".npmignore", ".pre-commit-config.yaml", ".swiftformat", + ".swiftlint.yml", "Makefile", "config/knip.config.ts", "config/markdownlint-cli2.jsonc", "config/shellcheckrc", + "config/swiftformat", + "config/swiftlint.yml", "deploy/fly.private.toml", "docker-setup.sh", "openclaw.podman.env",