Skip to content

Releases: theblixguy/swift-bylaws

SwiftSyntax 604.0.0 artifact

Choose a tag to compare

@swift-bylaws-release swift-bylaws-release released this 18 Sep 17:57
Immutable release. Only release title and notes can be modified.
8580640

Prebuilt SwiftSyntax 604.0.0 for Bylaws.

SwiftSyntax 603.0.2 artifact

Choose a tag to compare

@swift-bylaws-release swift-bylaws-release released this 18 Sep 18:09
Immutable release. Only release title and notes can be modified.
8580640

Prebuilt SwiftSyntax 603.0.2 for Bylaws.

SwiftSyntax 602.0.0 artifact

Choose a tag to compare

@swift-bylaws-release swift-bylaws-release released this 18 Sep 18:03
Immutable release. Only release title and notes can be modified.
8580640

Prebuilt SwiftSyntax 602.0.0 for Bylaws.

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 17 Sep 07:08
Immutable release. Only release title and notes can be modified.

Configure caches for Swift tests

Swift Testing can now configure the disk and selection caches at test or suite scope:

@Suite(
  .codebase(.app),
  .parseCache(validation: .content),
  .selectionCache()
)

.parseCache sets the disk-cache directory, size target and validation mode, while .selectionCache sets how much memory rules in the same scope can use to reuse query selections. Nested tests and suites inherit the settings unless they provide their own, and a zero budget turns off the corresponding cache.

Recheck rules affected by changed files

When a hook or CI job knows which files have changed since the previous cached run, it can pass the complete list to bylaws lint:

bylaws lint --changed-path Sources/Checkout/CheckoutView.swift Package.swift

Bylaws records the inputs that each rule reads and saves its findings in the disk cache. Later runs recheck rules affected by the changed paths and reuse the other saved findings. A rule that does run still checks all of its current inputs, so a change in one file can report a violation in another.

The first run checks every rule, as does any rule whose inputs cannot be fully tracked, such as one that reads compiler-index data. The changed-path list must also include generated inputs that changed, such as a refreshed Bazel graph.

Reuse parsed sources in Bazel

bylaws_lint now parses source files in separate Bazel actions before it runs the rules. Bazel can reuse those results locally or remotely, so changing a rule or data file does not parse the sources again. When a source file changes, only the parse action that contains it runs again.

Bylaws divides large source sets across several parse actions automatically, so existing bylaws_lint targets do not need any new configuration. If a project needs a different action size, set sources_per_parse_action as described in the Bazel setup guide.

Other changes

  • The disk-cache size now covers parsed files and saved rule results together.
  • Swift Package Index can build the documentation for every public Bylaws module.

Full changelog

v0.3.1

Choose a tag to compare

@github-actions github-actions released this 16 Sep 04:26
Immutable release. Only release title and notes can be modified.

Skip source reads for unchanged files

When you enable the parse cache, Bylaws now uses file metadata to check whether it can reuse a parsed file. It checks the file's identity, size and modification and change times, which lets a cache hit skip reading and hashing the source.

You can use the new default with:

bylaws lint --cache

Bylaws reads and hashes the source when the metadata changes, a cache entry is missing or damaged, or a timestamp is too recent or ambiguous to trust. A change that preserves every checked metadata field can go undetected, so you can choose content validation when each source file must be checked by its contents:

bylaws lint --cache-validation content

This option also enables caching. If you want to select metadata validation explicitly, use --cache-validation metadata. You can switch between the two modes and reuse the same parsed entries.

Disk caching remains opt-in for the CLI. All selected rules run on each invocation, including when every parsed file comes from the cache.

Choose validation for each codebase in Swift tests

You can set the validation policy alongside the cache directory and disk-size target:

let codebase = Codebase(
  root: .directory(projectPath),
  parseCache: .init(
    directory: cacheDirectory,
    budget: 500_000_000,
    validation: .content
  )
)

Here, cacheDirectory is a URL, and the budget is a soft cleanup target in bytes. Leave out validation to use the metadata default. Each codebase can have its own settings without changing the process environment.

Store the parse cache in fewer files

Bylaws now groups parsed files into indexed packs and writes new entries in batches, so later runs open fewer cache files. Pack reads can use memory mapping when the platform considers it safe. Cleanup can also combine small packs to reduce the file count.

The first cache-enabled run after upgrading rebuilds entries from the previous storage format. Bylaws removes the old entries during a scheduled cleanup, and your existing cache directory and size settings continue to apply.

See the performance guide for cache configuration and limits.

Full changelog

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 16 Sep 03:36
Immutable release. Only release title and notes can be modified.

Inspect values and expressions in your source

You can inspect literal values, member references, arrays, dictionaries and string interpolation through codebase.expressions. Call arguments also expose an expression property, so a rule can check what an argument contains without comparing its source text.

For example, add this rule to Bylaws.swift to report HTTP URL literals in your networking code:

import Bylaws

let codebase = Codebase(including: ["Sources/Networking/**"])

let rules: [Rule] = [
  Rule("https-literals", "Networking URL literals use HTTPS") {
    try await codebase.expressions.violations(
      matching: Matcher<SourceExpression>("contain an HTTP URL") {
        $0.stringValue?.hasPrefix("http://") ?? false
      }
    )
  },
]

The rule checks decoded string literals, including raw strings and escaped characters. A reference such as serviceURL has no literal value, so checking the URL it holds needs a separate runtime test. These queries work through the CLI and Swift Testing. See the expression guide for more examples.

Check assignments and their build conditions

You can query assignments with codebase.assignments and initial values with codebase.variableBindings, including code inside functions, closures and accessors. Each result includes its source location and containing declarations.

Expressions, assignments and variable bindings also expose their #if, #elseif and #else context. For example, this rule reports assignments of true to a project's allowsInsecureConnections setting outside a DEBUG branch:

import Bylaws

let codebase = Codebase(including: ["Sources/**"])

let rules: [Rule] = [
  Rule("debug-settings", "Insecure connection settings confined to DEBUG") {
    try await codebase.assignments.violations(
      matching: Matcher<SourceAssignment>(
        "enable insecure connections outside DEBUG"
      ) {
        $0.target.referenceName == "allowsInsecureConnections"
          && $0.value.booleanValue == true
          && !$0.compilationBranches.contains { $0.condition == "DEBUG" }
      }
    )
  },
]

The same assignment fails outside the conditional block or in its #else branch. The rule matches the exact condition DEBUG, so DEBUG || STAGING also fails. Bylaws reads every branch, including code for other build configurations. The conditional-compilation guide explains nested branches and earlier conditions in a chain.

Connect a source reference to its compiler symbol

You can use index.occurrences(at: location) to look up compiler occurrences at an exact source position, then compare symbol.usr to distinguish declarations with the same name. For client.send(), use the location of send to identify the method the compiler resolved.

The lookup uses the source from a completed indexed build and can return several occurrences or none. It works in Swift tests and CLI rule bodies. See the source-location example for filtering references and comparing symbols.

Reduce repeated work between rules

The CLI can combine name filters into one pass and reuse selections when rules repeat the same query. It also skips inheritance analysis for supported rules that only check names, paths or other properties written in the source. Native Swift filter chains and custom closures keep their existing behaviour.

You can change the default 64 MiB selection-cache budget:

bylaws lint --selection-cache-size 32MiB

The budget covers selections retained during the run. Parsed files and active rule evaluations use additional memory. If you want to turn off selection reuse, pass --selection-cache-size 0. For discovered rules in Swift Testing, use SelectionCache.withBudget around the calls to report() that should share a cache.

Bazel targets can set the same budget for each lint action:

bylaws_lint(
    name = "architecture",
    srcs = ["//Sources:lint_sources"],
    rules = ["Bylaws.swift"],
    data = ["MODULE.bazel"],
    selection_cache_size = "32MiB",
)

Bazel continues to manage reuse between actions. See the performance guide for the supported filters and Swift Testing setup.

Choose the parse-cache size and location

You can now set the disk-cache cleanup target from the CLI:

bylaws lint --cache-path .bylaws-cache --cache-size 500MB

The size option enables disk caching and replaces the default 1 GB target. Both cache-size options take whole bytes or a suffix such as MB or MiB. The disk size is a soft cleanup target, so the cache can grow beyond it between cleanups. A changed target takes effect the next time Bylaws loads the cache.

In Swift tests, you can give each codebase its own cache directory and budget:

let codebase = Codebase(
  root: .directory(projectPath),
  parseCache: .init(directory: cacheDirectory, budget: 500_000_000)
)

You can give each codebase a different cache directory URL, which lets parallel tests use different settings without changing the process environment. If you want to disable disk caching for a codebase, set its budget to zero.

Other changes

  • The new security cookbook has rules for logging privacy, keychain access, authentication handling and debug settings, with examples of code that passes and fails each check.
  • bylaws init now excludes **/*.docc/** from generated rules. Remove that pattern from the excluding list if you want to check the Swift examples in your DocC bundles.
  • Existing parse-cache entries are rebuilt to include the new call-argument source information.
  • The VS Code and Cursor extension version is now 0.2.0. The extension is released separately from the library.

Full changelog

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 15 Sep 07:15
Immutable release. Only release title and notes can be modified.

Keep rules beside the code they check

You can put a Bylaws.swift in any folder, including an Xcode app or a Bazel project without a Package.swift. Keep shared rules at the project root and add feature-specific rules in folders such as Features/Checkout. Parent rules continue to apply unless you replace one with an Override.

To skip rules and baselines in vendor or generated folders, add this to the root Bylaws.swift:

RuleDiscovery(excluding: ["Vendor", "**/Generated"])

This controls where Bylaws searches for rules and baselines. Each rule's Codebase selects the source files to check.

Check architecture during Bazel builds

You can add a bylaws_lint target to make architectural checks part of your build. After adding the swift-bylaws module, define a target in BUILD.bazel:

load("@swift-bylaws//bazel:defs.bzl", "bylaws_lint")

bylaws_lint(
    name = "architecture",
    srcs = ["//Features/Checkout:lint_sources"],
    rules = ["Bylaws.swift"],
    data = ["MODULE.bazel"],
)

Run bazel build //:architecture to check the files exposed by the lint_sources filegroup. Enforced violations fail the build, and Bazel can reuse successful results from its local or remote cache. You can include generated files and directories in the checks too. See the Bazel setup guide.

Rules can also read an exported Bazel dependency graph in Swift Testing or the CLI. For example, you can select feature targets by their Bazel tags and prevent them from depending on a database target, directly or through another target. The dependency guide shows how to export the graph and write the rule.

For existing Bazel users: change the module name from bylaws to swift-bylaws. The integration is also tested with Bazel 9.

Use your project's Swift language mode

Bylaws reads SwiftPM language settings for each target instead of parsing every file in Swift 6 mode. This fixes syntax errors reported for code that compiles in Swift 5 mode.

You can also read settings from an Xcode project and its local packages:

let codebase = Codebase(
  swiftLanguageMode: .automatic([.swiftPM, .xcode])
)

To set the mode yourself, pass .v5 or .v6 instead. See the language-mode guide for the limits of Xcode settings discovery.

Save reports from the CLI

You can save a report for CI or another tool while seeing violations in the terminal:

bylaws lint --format json --output report.json

When you check a project with --root, relative --rules and --baseline paths now start from that project root. The output path starts from your working directory.

Reuse the parse cache across machines

You can reuse saved parse data after moving a project or copying its cache to another CI worker. Bylaws checks the source text and language mode before reusing each entry and reports violations at the current file paths.

Other changes

  • The editor update raises the minimum supported VS Code version to 1.137 and updates the language client. The extension is released separately from the library.
  • The README and guides have clearer setup instructions, corrected links and an updated feature comparison.
  • Swift Package Index can evaluate the package manifest without the release configuration file.

Full changelog

VS Code and Cursor v0.2.0

Choose a tag to compare

@github-actions github-actions released this 15 Sep 19:11
Immutable release. Only release title and notes can be modified.
8f7a39a
Merge pull request #34 from theblixguy/chore/vscode-0.2.0

Bump the VS Code extension to 0.2.0

v0.1.1

Choose a tag to compare

@github-actions github-actions released this 13 Sep 07:25
Immutable release. Only release title and notes can be modified.

This patch fixes editor publishing and Bazel release verification. It does not change how you write or run rules.

  • The VS Code and Cursor installation instructions now use suyashsrijan.bylaws, matching the publisher used for Visual Studio Marketplace and Open VSX.
  • A failed editor publication can resume using the saved extension package even when its GitHub release is a draft.
  • Bazel releases now include build records that the Bazel Central Registry verifier can check. The release workflow verifies these records against the generated files before publishing.

Full changelog

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 13 Sep 05:27
Immutable release. Only release title and notes can be modified.