packwerk 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/exe/packwerk +1 -1
- data/lib/packwerk.rb +3 -1
- data/lib/packwerk/application_load_paths.rb +3 -2
- data/lib/packwerk/application_validator.rb +78 -57
- data/lib/packwerk/association_inspector.rb +23 -8
- data/lib/packwerk/cache_deprecated_references.rb +10 -2
- data/lib/packwerk/checker.rb +3 -0
- data/lib/packwerk/checking_deprecated_references.rb +5 -2
- data/lib/packwerk/cli.rb +12 -2
- data/lib/packwerk/commands/detect_stale_violations_command.rb +1 -1
- data/lib/packwerk/const_node_inspector.rb +13 -12
- data/lib/packwerk/dependency_checker.rb +13 -5
- data/lib/packwerk/deprecated_references.rb +5 -1
- data/lib/packwerk/formatters/offenses_formatter.rb +4 -5
- data/lib/packwerk/formatters/progress_formatter.rb +6 -2
- data/lib/packwerk/node.rb +3 -0
- data/lib/packwerk/offense.rb +4 -6
- data/lib/packwerk/output_style.rb +20 -0
- data/lib/packwerk/output_styles/coloured.rb +29 -0
- data/lib/packwerk/output_styles/plain.rb +26 -0
- data/lib/packwerk/package_set.rb +2 -1
- data/lib/packwerk/privacy_checker.rb +23 -5
- data/lib/packwerk/version.rb +1 -1
- metadata +5 -3
- data/lib/packwerk/output_styles.rb +0 -41
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: cd008f86d84fd0224aac9d8f92bc104123f23869e9381c947b3e51864523c947
         | 
| 4 | 
            +
              data.tar.gz: debf7f89ce8f8419a02f2af84c3f1900c7bc2f2ac79cce535284e3e697133d74
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 2bf12776a5e5cd4f3f9d06f3bbabb3d9b0c6d873325dba9a7bc43dc49ffedbc119678b77a2087cface6428bf564e037b75386abb8fca2d06a313e617461db53a
         | 
| 7 | 
            +
              data.tar.gz: d6ca7a42dea1c5338c40e89b6fe6b14baa43372cf44e22af3f19763ee1048c03629e34f4466b632e7f5b6d82932b8e05b2d02d5e26ebf91852334b9f2ca6d5b2
         | 
    
        data/Gemfile.lock
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -3,7 +3,7 @@ | |
| 3 3 | 
             
            Packwerk is a Ruby gem used to enforce boundaries and modularize Rails applications.
         | 
| 4 4 |  | 
| 5 5 | 
             
            Packwerk can be used to:
         | 
| 6 | 
            -
            * Combine  | 
| 6 | 
            +
            * Combine groups of files into packages
         | 
| 7 7 | 
             
            * Define package-level constant visibility (i.e. have publicly accessible constants)
         | 
| 8 8 | 
             
            * Enforce privacy (inbound) and dependency (outbound) boundaries between packages
         | 
| 9 9 | 
             
            * Help existing codebases to become more modular without obstructing development
         | 
    
        data/exe/packwerk
    CHANGED
    
    
    
        data/lib/packwerk.rb
    CHANGED
    
    | @@ -27,7 +27,9 @@ require "packwerk/graph" | |
| 27 27 | 
             
            require "packwerk/inflector"
         | 
| 28 28 | 
             
            require "packwerk/node_processor"
         | 
| 29 29 | 
             
            require "packwerk/node_visitor"
         | 
| 30 | 
            -
            require "packwerk/ | 
| 30 | 
            +
            require "packwerk/output_style"
         | 
| 31 | 
            +
            require "packwerk/output_styles/plain"
         | 
| 32 | 
            +
            require "packwerk/output_styles/coloured"
         | 
| 31 33 | 
             
            require "packwerk/package"
         | 
| 32 34 | 
             
            require "packwerk/package_set"
         | 
| 33 35 | 
             
            require "packwerk/parsers"
         | 
| @@ -28,8 +28,9 @@ module Packwerk | |
| 28 28 | 
             
                      .select { |railtie| railtie.is_a?(Rails::Engine) }
         | 
| 29 29 | 
             
                      .push(Rails.application)
         | 
| 30 30 | 
             
                      .flat_map do |engine|
         | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 31 | 
            +
                        paths = (engine.config.autoload_paths + engine.config.eager_load_paths + engine.config.autoload_once_paths)
         | 
| 32 | 
            +
                        paths.map(&:to_s).uniq
         | 
| 33 | 
            +
                      end
         | 
| 33 34 | 
             
                  end
         | 
| 34 35 |  | 
| 35 36 | 
             
                  sig do
         | 
| @@ -35,16 +35,7 @@ module Packwerk | |
| 35 35 | 
             
                    check_root_package_exists,
         | 
| 36 36 | 
             
                  ]
         | 
| 37 37 |  | 
| 38 | 
            -
                  results | 
| 39 | 
            -
             | 
| 40 | 
            -
                  if results.empty?
         | 
| 41 | 
            -
                    Result.new(true)
         | 
| 42 | 
            -
                  else
         | 
| 43 | 
            -
                    Result.new(
         | 
| 44 | 
            -
                      false,
         | 
| 45 | 
            -
                      results.map(&:error_value).join("\n===\n")
         | 
| 46 | 
            -
                    )
         | 
| 47 | 
            -
                  end
         | 
| 38 | 
            +
                  merge_results(results)
         | 
| 48 39 | 
             
                end
         | 
| 49 40 |  | 
| 50 41 | 
             
                def check_autoload_path_cache
         | 
| @@ -65,51 +56,37 @@ module Packwerk | |
| 65 56 | 
             
                def check_package_manifests_for_privacy
         | 
| 66 57 | 
             
                  privacy_settings = package_manifests_settings_for("enforce_privacy")
         | 
| 67 58 |  | 
| 68 | 
            -
                  autoload_paths = @configuration.load_paths
         | 
| 69 | 
            -
             | 
| 70 59 | 
             
                  resolver = ConstantResolver.new(
         | 
| 71 60 | 
             
                    root_path: @configuration.root_path,
         | 
| 72 | 
            -
                    load_paths:  | 
| 61 | 
            +
                    load_paths: @configuration.load_paths
         | 
| 73 62 | 
             
                  )
         | 
| 74 63 |  | 
| 75 | 
            -
                   | 
| 64 | 
            +
                  results = []
         | 
| 76 65 |  | 
| 77 | 
            -
                  privacy_settings.each do | | 
| 66 | 
            +
                  privacy_settings.each do |config_file_path, setting|
         | 
| 78 67 | 
             
                    next unless setting.is_a?(Array)
         | 
| 68 | 
            +
                    constants = setting
         | 
| 79 69 |  | 
| 80 | 
            -
                     | 
| 81 | 
            -
                      # make sure the constant can be loaded
         | 
| 82 | 
            -
                      constant.constantize # rubocop:disable Sorbet/ConstantsFromStrings
         | 
| 83 | 
            -
                      context = resolver.resolve(constant)
         | 
| 70 | 
            +
                    assert_constants_can_be_loaded(constants)
         | 
| 84 71 |  | 
| 85 | 
            -
             | 
| 86 | 
            -
                        errors << "#{constant}, listed in #{filepath.inspect}, could not be resolved"
         | 
| 87 | 
            -
                        next
         | 
| 88 | 
            -
                      end
         | 
| 89 | 
            -
             | 
| 90 | 
            -
                      expected_filename = constant.underscore + ".rb"
         | 
| 72 | 
            +
                    constant_locations = constants.map { |c| [c, resolver.resolve(c)&.location] }
         | 
| 91 73 |  | 
| 92 | 
            -
             | 
| 93 | 
            -
                       | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
                        "It should be in something like #{expected_filename.inspect}"
         | 
| 74 | 
            +
                    constant_locations.each do |name, location|
         | 
| 75 | 
            +
                      results << if location
         | 
| 76 | 
            +
                        check_private_constant_location(name, location, config_file_path)
         | 
| 77 | 
            +
                      else
         | 
| 78 | 
            +
                        private_constant_unresolvable(name, config_file_path)
         | 
| 79 | 
            +
                      end
         | 
| 99 80 | 
             
                    end
         | 
| 100 81 | 
             
                  end
         | 
| 101 82 |  | 
| 102 | 
            -
                   | 
| 103 | 
            -
                    Result.new(true)
         | 
| 104 | 
            -
                  else
         | 
| 105 | 
            -
                    Result.new(false, errors.join("\n---\n"))
         | 
| 106 | 
            -
                  end
         | 
| 83 | 
            +
                  merge_results(results, separator: "\n---\n")
         | 
| 107 84 | 
             
                end
         | 
| 108 85 |  | 
| 109 86 | 
             
                def check_package_manifest_syntax
         | 
| 110 87 | 
             
                  errors = []
         | 
| 111 88 |  | 
| 112 | 
            -
                  package_manifests | 
| 89 | 
            +
                  package_manifests.each do |f|
         | 
| 113 90 | 
             
                    hash = YAML.load_file(f)
         | 
| 114 91 | 
             
                    next unless hash
         | 
| 115 92 |  | 
| @@ -193,24 +170,16 @@ module Packwerk | |
| 193 170 | 
             
                    end
         | 
| 194 171 | 
             
                  end
         | 
| 195 172 |  | 
| 196 | 
            -
                   | 
| 197 | 
            -
             | 
| 198 | 
            -
             | 
| 199 | 
            -
                     | 
| 200 | 
            -
                   | 
| 201 | 
            -
                    Result.new(
         | 
| 202 | 
            -
                      false,
         | 
| 203 | 
            -
                      "Inflections specified in #{inflections_file} don't line up with application!\n" +
         | 
| 204 | 
            -
                        errors.map(&:error_value).join("\n")
         | 
| 205 | 
            -
                    )
         | 
| 206 | 
            -
                  end
         | 
| 173 | 
            +
                  merge_results(
         | 
| 174 | 
            +
                    results,
         | 
| 175 | 
            +
                    separator: "\n",
         | 
| 176 | 
            +
                    errors_headline: "Inflections specified in #{inflections_file} don't line up with application!\n"
         | 
| 177 | 
            +
                  )
         | 
| 207 178 | 
             
                end
         | 
| 208 179 |  | 
| 209 180 | 
             
                def check_acyclic_graph
         | 
| 210 | 
            -
                   | 
| 211 | 
            -
             | 
| 212 | 
            -
                  edges = packages.flat_map do |package|
         | 
| 213 | 
            -
                    package.dependencies.map { |dependency| [package, packages.fetch(dependency)] }
         | 
| 181 | 
            +
                  edges = package_set.flat_map do |package|
         | 
| 182 | 
            +
                    package.dependencies.map { |dependency| [package, package_set.fetch(dependency)] }
         | 
| 214 183 | 
             
                  end
         | 
| 215 184 | 
             
                  dependency_graph = Packwerk::Graph.new(*edges)
         | 
| 216 185 |  | 
| @@ -316,8 +285,7 @@ module Packwerk | |
| 316 285 | 
             
                private
         | 
| 317 286 |  | 
| 318 287 | 
             
                def package_manifests_settings_for(setting)
         | 
| 319 | 
            -
                  package_manifests( | 
| 320 | 
            -
                    .map { |f| [f, (YAML.load_file(File.join(f)) || {})[setting]] }
         | 
| 288 | 
            +
                  package_manifests.map { |f| [f, (YAML.load_file(File.join(f)) || {})[setting]] }
         | 
| 321 289 | 
             
                end
         | 
| 322 290 |  | 
| 323 291 | 
             
                def format_yaml_strings(list)
         | 
| @@ -328,13 +296,17 @@ module Packwerk | |
| 328 296 | 
             
                  @configuration.package_paths || "**"
         | 
| 329 297 | 
             
                end
         | 
| 330 298 |  | 
| 331 | 
            -
                def package_manifests(glob_pattern)
         | 
| 299 | 
            +
                def package_manifests(glob_pattern = package_glob)
         | 
| 332 300 | 
             
                  PackageSet.package_paths(@configuration.root_path, glob_pattern)
         | 
| 333 301 | 
             
                    .map { |f| File.realpath(f) }
         | 
| 334 302 | 
             
                end
         | 
| 335 303 |  | 
| 336 304 | 
             
                def relative_paths(paths)
         | 
| 337 | 
            -
                  paths.map { |path|  | 
| 305 | 
            +
                  paths.map { |path| relative_path(path) }
         | 
| 306 | 
            +
                end
         | 
| 307 | 
            +
             | 
| 308 | 
            +
                def relative_path(path)
         | 
| 309 | 
            +
                  Pathname.new(path).relative_path_from(@configuration.root_path)
         | 
| 338 310 | 
             
                end
         | 
| 339 311 |  | 
| 340 312 | 
             
                def invalid_package_path?(path)
         | 
| @@ -344,5 +316,54 @@ module Packwerk | |
| 344 316 | 
             
                  package_path = File.join(@configuration.root_path, path, Packwerk::PackageSet::PACKAGE_CONFIG_FILENAME)
         | 
| 345 317 | 
             
                  !File.file?(package_path)
         | 
| 346 318 | 
             
                end
         | 
| 319 | 
            +
             | 
| 320 | 
            +
                def assert_constants_can_be_loaded(constants)
         | 
| 321 | 
            +
                  constants.each(&:constantize)
         | 
| 322 | 
            +
                  nil
         | 
| 323 | 
            +
                end
         | 
| 324 | 
            +
             | 
| 325 | 
            +
                def private_constant_unresolvable(name, config_file_path)
         | 
| 326 | 
            +
                  explicit_filepath = (name.start_with?("::") ? name[2..-1] : name).underscore + ".rb"
         | 
| 327 | 
            +
             | 
| 328 | 
            +
                  Result.new(
         | 
| 329 | 
            +
                    false,
         | 
| 330 | 
            +
                    "'#{name}', listed in #{config_file_path}, could not be resolved.\n"\
         | 
| 331 | 
            +
                    "This is probably because it is an autovivified namespace - a namespace module that doesn't have a\n"\
         | 
| 332 | 
            +
                    "file explicitly defining it. Packwerk currently doesn't support declaring autovivified namespaces as\n"\
         | 
| 333 | 
            +
                    "private. Add a #{explicit_filepath} file to explicitly define the constant."
         | 
| 334 | 
            +
                  )
         | 
| 335 | 
            +
                end
         | 
| 336 | 
            +
             | 
| 337 | 
            +
                def check_private_constant_location(name, location, config_file_path)
         | 
| 338 | 
            +
                  declared_package = package_set.package_from_path(relative_path(config_file_path))
         | 
| 339 | 
            +
                  constant_package = package_set.package_from_path(location)
         | 
| 340 | 
            +
             | 
| 341 | 
            +
                  if constant_package == declared_package
         | 
| 342 | 
            +
                    Result.new(true)
         | 
| 343 | 
            +
                  else
         | 
| 344 | 
            +
                    Result.new(
         | 
| 345 | 
            +
                      false,
         | 
| 346 | 
            +
                      "'#{name}' is declared as private in the '#{declared_package}' package but appears to be "\
         | 
| 347 | 
            +
                      "defined\nin the '#{constant_package}' package. Packwerk resolved it to #{location}."
         | 
| 348 | 
            +
                    )
         | 
| 349 | 
            +
                  end
         | 
| 350 | 
            +
                end
         | 
| 351 | 
            +
             | 
| 352 | 
            +
                def package_set
         | 
| 353 | 
            +
                  @package_set ||= Packwerk::PackageSet.load_all_from(@configuration.root_path, package_pathspec: package_glob)
         | 
| 354 | 
            +
                end
         | 
| 355 | 
            +
             | 
| 356 | 
            +
                def merge_results(results, separator: "\n===\n", errors_headline: "")
         | 
| 357 | 
            +
                  results.reject!(&:ok?)
         | 
| 358 | 
            +
             | 
| 359 | 
            +
                  if results.empty?
         | 
| 360 | 
            +
                    Result.new(true)
         | 
| 361 | 
            +
                  else
         | 
| 362 | 
            +
                    Result.new(
         | 
| 363 | 
            +
                      false,
         | 
| 364 | 
            +
                      errors_headline + results.map(&:error_value).join(separator)
         | 
| 365 | 
            +
                    )
         | 
| 366 | 
            +
                  end
         | 
| 367 | 
            +
                end
         | 
| 347 368 | 
             
              end
         | 
| 348 369 | 
             
            end
         | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # typed:  | 
| 1 | 
            +
            # typed: strict
         | 
| 2 2 | 
             
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 4 | 
             
            require "packwerk/constant_name_inspector"
         | 
| @@ -7,20 +7,32 @@ require "packwerk/node" | |
| 7 7 | 
             
            module Packwerk
         | 
| 8 8 | 
             
              # Extracts the implicit constant reference from an active record association
         | 
| 9 9 | 
             
              class AssociationInspector
         | 
| 10 | 
            +
                extend T::Sig
         | 
| 10 11 | 
             
                include ConstantNameInspector
         | 
| 11 12 |  | 
| 12 | 
            -
                 | 
| 13 | 
            -
                  belongs_to
         | 
| 14 | 
            -
                  has_many
         | 
| 15 | 
            -
                  has_one
         | 
| 16 | 
            -
                  has_and_belongs_to_many
         | 
| 17 | 
            -
                ).to_set
         | 
| 13 | 
            +
                CustomAssociations = T.type_alias { T.any(T::Array[Symbol], T::Set[Symbol]) }
         | 
| 18 14 |  | 
| 15 | 
            +
                RAILS_ASSOCIATIONS = T.let(
         | 
| 16 | 
            +
                  %i(
         | 
| 17 | 
            +
                    belongs_to
         | 
| 18 | 
            +
                    has_many
         | 
| 19 | 
            +
                    has_one
         | 
| 20 | 
            +
                    has_and_belongs_to_many
         | 
| 21 | 
            +
                  ).to_set,
         | 
| 22 | 
            +
                  CustomAssociations
         | 
| 23 | 
            +
                )
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                sig { params(inflector: Inflector, custom_associations: CustomAssociations).void }
         | 
| 19 26 | 
             
                def initialize(inflector:, custom_associations: Set.new)
         | 
| 20 27 | 
             
                  @inflector = inflector
         | 
| 21 | 
            -
                  @associations = RAILS_ASSOCIATIONS + custom_associations
         | 
| 28 | 
            +
                  @associations = T.let(RAILS_ASSOCIATIONS + custom_associations, CustomAssociations)
         | 
| 22 29 | 
             
                end
         | 
| 23 30 |  | 
| 31 | 
            +
                sig do
         | 
| 32 | 
            +
                  override
         | 
| 33 | 
            +
                    .params(node: AST::Node, ancestors: T::Array[AST::Node])
         | 
| 34 | 
            +
                    .returns(T.nilable(String))
         | 
| 35 | 
            +
                end
         | 
| 24 36 | 
             
                def constant_name_from_node(node, ancestors:)
         | 
| 25 37 | 
             
                  return unless Node.method_call?(node)
         | 
| 26 38 | 
             
                  return unless association?(node)
         | 
| @@ -38,11 +50,13 @@ module Packwerk | |
| 38 50 |  | 
| 39 51 | 
             
                private
         | 
| 40 52 |  | 
| 53 | 
            +
                sig { params(node: AST::Node).returns(T::Boolean) }
         | 
| 41 54 | 
             
                def association?(node)
         | 
| 42 55 | 
             
                  method_name = Node.method_name(node)
         | 
| 43 56 | 
             
                  @associations.include?(method_name)
         | 
| 44 57 | 
             
                end
         | 
| 45 58 |  | 
| 59 | 
            +
                sig { params(arguments: T::Array[AST::Node]).returns(T.nilable(AST::Node)) }
         | 
| 46 60 | 
             
                def custom_class_name(arguments)
         | 
| 47 61 | 
             
                  association_options = arguments.detect { |n| Node.hash?(n) }
         | 
| 48 62 | 
             
                  return unless association_options
         | 
| @@ -50,6 +64,7 @@ module Packwerk | |
| 50 64 | 
             
                  Node.value_from_hash(association_options, :class_name)
         | 
| 51 65 | 
             
                end
         | 
| 52 66 |  | 
| 67 | 
            +
                sig { params(arguments: T::Array[AST::Node]).returns(T.any(T.nilable(Symbol), T.nilable(String))) }
         | 
| 53 68 | 
             
                def association_name(arguments)
         | 
| 54 69 | 
             
                  return unless Node.symbol?(arguments[0])
         | 
| 55 70 |  | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # typed:  | 
| 1 | 
            +
            # typed: strict
         | 
| 2 2 | 
             
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 4 | 
             
            require "sorbet-runtime"
         | 
| @@ -15,9 +15,15 @@ module Packwerk | |
| 15 15 | 
             
                include ReferenceLister
         | 
| 16 16 | 
             
                abstract!
         | 
| 17 17 |  | 
| 18 | 
            +
                sig do
         | 
| 19 | 
            +
                  params(
         | 
| 20 | 
            +
                    root_path: String,
         | 
| 21 | 
            +
                    deprecated_references: T::Hash[Packwerk::Package, Packwerk::DeprecatedReferences]
         | 
| 22 | 
            +
                  ).void
         | 
| 23 | 
            +
                end
         | 
| 18 24 | 
             
                def initialize(root_path, deprecated_references = {})
         | 
| 19 25 | 
             
                  @root_path = root_path
         | 
| 20 | 
            -
                  @deprecated_references = T.let(deprecated_references, T::Hash[ | 
| 26 | 
            +
                  @deprecated_references = T.let(deprecated_references, T::Hash[Packwerk::Package, Packwerk::DeprecatedReferences])
         | 
| 21 27 | 
             
                end
         | 
| 22 28 |  | 
| 23 29 | 
             
                sig do
         | 
| @@ -33,6 +39,7 @@ module Packwerk | |
| 33 39 |  | 
| 34 40 | 
             
                private
         | 
| 35 41 |  | 
| 42 | 
            +
                sig { params(package: Packwerk::Package).returns(Packwerk::DeprecatedReferences) }
         | 
| 36 43 | 
             
                def deprecated_references_for(package)
         | 
| 37 44 | 
             
                  @deprecated_references[package] ||= Packwerk::DeprecatedReferences.new(
         | 
| 38 45 | 
             
                    package,
         | 
| @@ -40,6 +47,7 @@ module Packwerk | |
| 40 47 | 
             
                  )
         | 
| 41 48 | 
             
                end
         | 
| 42 49 |  | 
| 50 | 
            +
                sig { params(package: Packwerk::Package).returns(String) }
         | 
| 43 51 | 
             
                def deprecated_references_file_for(package)
         | 
| 44 52 | 
             
                  File.join(@root_path, package.name, "deprecated_references.yml")
         | 
| 45 53 | 
             
                end
         | 
    
        data/lib/packwerk/checker.rb
    CHANGED
    
    | @@ -11,6 +11,9 @@ module Packwerk | |
| 11 11 |  | 
| 12 12 | 
             
                interface!
         | 
| 13 13 |  | 
| 14 | 
            +
                sig { returns(ViolationType).abstract }
         | 
| 15 | 
            +
                def violation_type; end
         | 
| 16 | 
            +
             | 
| 14 17 | 
             
                sig { params(reference: Reference, reference_lister: ReferenceLister).returns(T::Boolean).abstract }
         | 
| 15 18 | 
             
                def invalid_reference?(reference, reference_lister); end
         | 
| 16 19 |  | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # typed:  | 
| 1 | 
            +
            # typed: strict
         | 
| 2 2 | 
             
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 4 | 
             
            require "sorbet-runtime"
         | 
| @@ -10,9 +10,10 @@ module Packwerk | |
| 10 10 | 
             
                extend T::Sig
         | 
| 11 11 | 
             
                include ReferenceLister
         | 
| 12 12 |  | 
| 13 | 
            +
                sig { params(root_path: String).void }
         | 
| 13 14 | 
             
                def initialize(root_path)
         | 
| 14 15 | 
             
                  @root_path = root_path
         | 
| 15 | 
            -
                  @deprecated_references = {}
         | 
| 16 | 
            +
                  @deprecated_references = T.let({}, T::Hash[Packwerk::Package, Packwerk::DeprecatedReferences])
         | 
| 16 17 | 
             
                end
         | 
| 17 18 |  | 
| 18 19 | 
             
                sig do
         | 
| @@ -26,6 +27,7 @@ module Packwerk | |
| 26 27 |  | 
| 27 28 | 
             
                private
         | 
| 28 29 |  | 
| 30 | 
            +
                sig { params(source_package: Packwerk::Package).returns(Packwerk::DeprecatedReferences) }
         | 
| 29 31 | 
             
                def deprecated_references_for(source_package)
         | 
| 30 32 | 
             
                  @deprecated_references[source_package] ||= Packwerk::DeprecatedReferences.new(
         | 
| 31 33 | 
             
                    source_package,
         | 
| @@ -33,6 +35,7 @@ module Packwerk | |
| 33 35 | 
             
                  )
         | 
| 34 36 | 
             
                end
         | 
| 35 37 |  | 
| 38 | 
            +
                sig { params(package: Packwerk::Package).returns(String) }
         | 
| 36 39 | 
             
                def deprecated_references_file_for(package)
         | 
| 37 40 | 
             
                  File.join(@root_path, package.name, "deprecated_references.yml")
         | 
| 38 41 | 
             
                end
         | 
    
        data/lib/packwerk/cli.rb
    CHANGED
    
    | @@ -10,7 +10,8 @@ require "packwerk/files_for_processing" | |
| 10 10 | 
             
            require "packwerk/formatters/offenses_formatter"
         | 
| 11 11 | 
             
            require "packwerk/formatters/progress_formatter"
         | 
| 12 12 | 
             
            require "packwerk/inflector"
         | 
| 13 | 
            -
            require "packwerk/ | 
| 13 | 
            +
            require "packwerk/output_style"
         | 
| 14 | 
            +
            require "packwerk/output_styles/plain"
         | 
| 14 15 | 
             
            require "packwerk/run_context"
         | 
| 15 16 | 
             
            require "packwerk/updating_deprecated_references"
         | 
| 16 17 | 
             
            require "packwerk/checking_deprecated_references"
         | 
| @@ -23,7 +24,16 @@ module Packwerk | |
| 23 24 | 
             
                extend T::Sig
         | 
| 24 25 | 
             
                include OffenseProgressMarker
         | 
| 25 26 |  | 
| 26 | 
            -
                 | 
| 27 | 
            +
                sig do
         | 
| 28 | 
            +
                  params(
         | 
| 29 | 
            +
                    run_context: T.nilable(Packwerk::RunContext),
         | 
| 30 | 
            +
                    configuration: T.nilable(Configuration),
         | 
| 31 | 
            +
                    out: T.any(StringIO, IO),
         | 
| 32 | 
            +
                    err_out: T.any(StringIO, IO),
         | 
| 33 | 
            +
                    style: Packwerk::OutputStyle
         | 
| 34 | 
            +
                  ).void
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
                def initialize(run_context: nil, configuration: nil, out: $stdout, err_out: $stderr, style: OutputStyles::Plain.new)
         | 
| 27 37 | 
             
                  @out = out
         | 
| 28 38 | 
             
                  @err_out = err_out
         | 
| 29 39 | 
             
                  @style = style
         | 
| @@ -49,7 +49,7 @@ module Packwerk | |
| 49 49 | 
             
                  sig { returns(Result) }
         | 
| 50 50 | 
             
                  def calculate_result
         | 
| 51 51 | 
             
                    result_status = !reference_lister.stale_violations?
         | 
| 52 | 
            -
                    message = "There were stale violations found, please run `packwerk update`"
         | 
| 52 | 
            +
                    message = "There were stale violations found, please run `packwerk update-deprecations`"
         | 
| 53 53 | 
             
                    if result_status
         | 
| 54 54 | 
             
                      message = "No stale violations detected"
         | 
| 55 55 | 
             
                    end
         | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # typed:  | 
| 1 | 
            +
            # typed: strict
         | 
| 2 2 | 
             
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 4 | 
             
            require "packwerk/constant_name_inspector"
         | 
| @@ -6,15 +6,21 @@ require "packwerk/constant_name_inspector" | |
| 6 6 | 
             
            module Packwerk
         | 
| 7 7 | 
             
              # Extracts a constant name from an AST node of type :const
         | 
| 8 8 | 
             
              class ConstNodeInspector
         | 
| 9 | 
            +
                extend T::Sig
         | 
| 9 10 | 
             
                include ConstantNameInspector
         | 
| 10 11 |  | 
| 12 | 
            +
                sig do
         | 
| 13 | 
            +
                  override
         | 
| 14 | 
            +
                    .params(node: AST::Node, ancestors: T::Array[AST::Node])
         | 
| 15 | 
            +
                    .returns(T.nilable(String))
         | 
| 16 | 
            +
                end
         | 
| 11 17 | 
             
                def constant_name_from_node(node, ancestors:)
         | 
| 12 18 | 
             
                  return nil unless Node.constant?(node)
         | 
| 13 19 | 
             
                  parent = ancestors.first
         | 
| 14 20 | 
             
                  return nil unless root_constant?(parent)
         | 
| 15 21 |  | 
| 16 22 | 
             
                  if parent && constant_in_module_or_class_definition?(node, parent: parent)
         | 
| 17 | 
            -
                    fully_qualify_constant( | 
| 23 | 
            +
                    fully_qualify_constant(ancestors)
         | 
| 18 24 | 
             
                  else
         | 
| 19 25 | 
             
                    begin
         | 
| 20 26 | 
             
                      Node.constant_name(node)
         | 
| @@ -28,27 +34,22 @@ module Packwerk | |
| 28 34 |  | 
| 29 35 | 
             
                # Only process the root `const` node for namespaced constant references. For example, in the
         | 
| 30 36 | 
             
                # reference `Spam::Eggs::Thing`, we only process the const node associated with `Spam`.
         | 
| 37 | 
            +
                sig { params(parent: T.nilable(AST::Node)).returns(T::Boolean) }
         | 
| 31 38 | 
             
                def root_constant?(parent)
         | 
| 32 39 | 
             
                  !(parent && Node.constant?(parent))
         | 
| 33 40 | 
             
                end
         | 
| 34 41 |  | 
| 42 | 
            +
                sig { params(node: AST::Node, parent: AST::Node).returns(T.nilable(T::Boolean)) }
         | 
| 35 43 | 
             
                def constant_in_module_or_class_definition?(node, parent:)
         | 
| 36 44 | 
             
                  parent_name = Node.module_name_from_definition(parent)
         | 
| 37 45 | 
             
                  parent_name && parent_name == Node.constant_name(node)
         | 
| 38 46 | 
             
                end
         | 
| 39 47 |  | 
| 40 | 
            -
                 | 
| 48 | 
            +
                sig { params(ancestors: T::Array[AST::Node]).returns(String) }
         | 
| 49 | 
            +
                def fully_qualify_constant(ancestors)
         | 
| 41 50 | 
             
                  # We're defining a class with this name, in which case the constant is implicitly fully qualified by its
         | 
| 42 51 | 
             
                  # enclosing namespace
         | 
| 43 | 
            -
                   | 
| 44 | 
            -
                  name ||= generate_qualified_constant(node, ancestors)
         | 
| 45 | 
            -
                  "::" + name
         | 
| 46 | 
            -
                end
         | 
| 47 | 
            -
             | 
| 48 | 
            -
                def generate_qualified_constant(node, ancestors:)
         | 
| 49 | 
            -
                  namespace_path = Node.enclosing_namespace_path(node, ancestors: ancestors)
         | 
| 50 | 
            -
                  constant_name = Node.constant_name(node)
         | 
| 51 | 
            -
                  namespace_path.push(constant_name).join("::")
         | 
| 52 | 
            +
                  "::" + Node.parent_module_name(ancestors: ancestors)
         | 
| 52 53 | 
             
                end
         | 
| 53 54 | 
             
              end
         | 
| 54 55 | 
             
            end
         | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # typed:  | 
| 1 | 
            +
            # typed: strict
         | 
| 2 2 | 
             
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 4 | 
             
            require "packwerk/violation_type"
         | 
| @@ -6,20 +6,28 @@ require "packwerk/checker" | |
| 6 6 |  | 
| 7 7 | 
             
            module Packwerk
         | 
| 8 8 | 
             
              class DependencyChecker
         | 
| 9 | 
            +
                extend T::Sig
         | 
| 9 10 | 
             
                include Checker
         | 
| 10 11 |  | 
| 12 | 
            +
                sig { override.returns(ViolationType) }
         | 
| 11 13 | 
             
                def violation_type
         | 
| 12 14 | 
             
                  ViolationType::Dependency
         | 
| 13 15 | 
             
                end
         | 
| 14 16 |  | 
| 17 | 
            +
                sig do
         | 
| 18 | 
            +
                  override
         | 
| 19 | 
            +
                    .params(reference: Packwerk::Reference, reference_lister: Packwerk::ReferenceLister)
         | 
| 20 | 
            +
                    .returns(T::Boolean)
         | 
| 21 | 
            +
                end
         | 
| 15 22 | 
             
                def invalid_reference?(reference, reference_lister)
         | 
| 16 | 
            -
                  return unless reference.source_package
         | 
| 17 | 
            -
                  return unless reference.source_package.enforce_dependencies?
         | 
| 18 | 
            -
                  return if reference.source_package.dependency?(reference.constant.package)
         | 
| 19 | 
            -
                  return if reference_lister.listed?(reference, violation_type: violation_type)
         | 
| 23 | 
            +
                  return false unless reference.source_package
         | 
| 24 | 
            +
                  return false unless reference.source_package.enforce_dependencies?
         | 
| 25 | 
            +
                  return false if reference.source_package.dependency?(reference.constant.package)
         | 
| 26 | 
            +
                  return false if reference_lister.listed?(reference, violation_type: violation_type)
         | 
| 20 27 | 
             
                  true
         | 
| 21 28 | 
             
                end
         | 
| 22 29 |  | 
| 30 | 
            +
                sig { override.params(reference: Packwerk::Reference).returns(String) }
         | 
| 23 31 | 
             
                def message_for(reference)
         | 
| 24 32 | 
             
                  "Dependency violation: #{reference.constant.name} belongs to '#{reference.constant.package}', but " \
         | 
| 25 33 | 
             
                    "'#{reference.source_package}' does not specify a dependency on " \
         | 
| @@ -3,7 +3,6 @@ | |
| 3 3 |  | 
| 4 4 | 
             
            require "sorbet-runtime"
         | 
| 5 5 | 
             
            require "yaml"
         | 
| 6 | 
            -
            require "sorbet-runtime"
         | 
| 7 6 |  | 
| 8 7 | 
             
            require "packwerk/reference"
         | 
| 9 8 | 
             
            require "packwerk/reference_lister"
         | 
| @@ -14,6 +13,7 @@ module Packwerk | |
| 14 13 | 
             
                extend T::Sig
         | 
| 15 14 | 
             
                include ReferenceLister
         | 
| 16 15 |  | 
| 16 | 
            +
                sig { params(package: Packwerk::Package, filepath: String).void }
         | 
| 17 17 | 
             
                def initialize(package, filepath)
         | 
| 18 18 | 
             
                  @package = package
         | 
| 19 19 | 
             
                  @filepath = filepath
         | 
| @@ -35,6 +35,7 @@ module Packwerk | |
| 35 35 | 
             
                  violated_constants_found.fetch("violations", []).include?(violation_type.serialize)
         | 
| 36 36 | 
             
                end
         | 
| 37 37 |  | 
| 38 | 
            +
                sig { params(reference: Packwerk::Reference, violation_type: String).void }
         | 
| 38 39 | 
             
                def add_entries(reference, violation_type)
         | 
| 39 40 | 
             
                  package_violations = @new_entries.fetch(reference.constant.package.name, {})
         | 
| 40 41 | 
             
                  entries_for_file = package_violations[reference.constant.name] ||= {}
         | 
| @@ -66,6 +67,7 @@ module Packwerk | |
| 66 67 | 
             
                  end
         | 
| 67 68 | 
             
                end
         | 
| 68 69 |  | 
| 70 | 
            +
                sig { void }
         | 
| 69 71 | 
             
                def dump
         | 
| 70 72 | 
             
                  if @new_entries.empty?
         | 
| 71 73 | 
             
                    File.delete(@filepath) if File.exist?(@filepath)
         | 
| @@ -88,6 +90,7 @@ module Packwerk | |
| 88 90 |  | 
| 89 91 | 
             
                private
         | 
| 90 92 |  | 
| 93 | 
            +
                sig { returns(Hash) }
         | 
| 91 94 | 
             
                def prepare_entries_for_dump
         | 
| 92 95 | 
             
                  @new_entries.each do |package_name, package_violations|
         | 
| 93 96 | 
             
                    package_violations.each do |_, entries_for_file|
         | 
| @@ -100,6 +103,7 @@ module Packwerk | |
| 100 103 | 
             
                  @new_entries = @new_entries.sort.to_h
         | 
| 101 104 | 
             
                end
         | 
| 102 105 |  | 
| 106 | 
            +
                sig { returns(Hash) }
         | 
| 103 107 | 
             
                def deprecated_references
         | 
| 104 108 | 
             
                  @deprecated_references ||= if File.exist?(@filepath)
         | 
| 105 109 | 
             
                    YAML.load_file(@filepath) || {}
         | 
| @@ -5,17 +5,16 @@ require "benchmark" | |
| 5 5 | 
             
            require "sorbet-runtime"
         | 
| 6 6 |  | 
| 7 7 | 
             
            require "packwerk/inflector"
         | 
| 8 | 
            -
            require "packwerk/ | 
| 8 | 
            +
            require "packwerk/output_style"
         | 
| 9 | 
            +
            require "packwerk/output_styles/plain"
         | 
| 9 10 |  | 
| 10 11 | 
             
            module Packwerk
         | 
| 11 12 | 
             
              module Formatters
         | 
| 12 13 | 
             
                class OffensesFormatter
         | 
| 13 14 | 
             
                  extend T::Sig
         | 
| 14 15 |  | 
| 15 | 
            -
                  sig  | 
| 16 | 
            -
             | 
| 17 | 
            -
                  end
         | 
| 18 | 
            -
                  def initialize(style: OutputStyles::Plain)
         | 
| 16 | 
            +
                  sig { params(style: OutputStyle).void }
         | 
| 17 | 
            +
                  def initialize(style: OutputStyles::Plain.new)
         | 
| 19 18 | 
             
                    @style = style
         | 
| 20 19 | 
             
                  end
         | 
| 21 20 |  | 
| @@ -4,12 +4,16 @@ | |
| 4 4 | 
             
            require "benchmark"
         | 
| 5 5 |  | 
| 6 6 | 
             
            require "packwerk/inflector"
         | 
| 7 | 
            -
            require "packwerk/ | 
| 7 | 
            +
            require "packwerk/output_style"
         | 
| 8 | 
            +
            require "packwerk/output_styles/plain"
         | 
| 8 9 |  | 
| 9 10 | 
             
            module Packwerk
         | 
| 10 11 | 
             
              module Formatters
         | 
| 11 12 | 
             
                class ProgressFormatter
         | 
| 12 | 
            -
                   | 
| 13 | 
            +
                  extend T::Sig
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  sig { params(out: T.any(StringIO, IO), style: OutputStyle).void }
         | 
| 16 | 
            +
                  def initialize(out, style: OutputStyles::Plain.new)
         | 
| 13 17 | 
             
                    @out = out
         | 
| 14 18 | 
             
                    @style = style
         | 
| 15 19 | 
             
                  end
         | 
    
        data/lib/packwerk/node.rb
    CHANGED
    
    | @@ -9,6 +9,8 @@ module Packwerk | |
| 9 9 | 
             
                Location = Struct.new(:line, :column)
         | 
| 10 10 |  | 
| 11 11 | 
             
                class << self
         | 
| 12 | 
            +
                  extend T::Sig
         | 
| 13 | 
            +
             | 
| 12 14 | 
             
                  def class_or_module_name(class_or_module_node)
         | 
| 13 15 | 
             
                    case type_of(class_or_module_node)
         | 
| 14 16 | 
             
                    when CLASS, MODULE
         | 
| @@ -178,6 +180,7 @@ module Packwerk | |
| 178 180 | 
             
                    class_node.children[1]
         | 
| 179 181 | 
             
                  end
         | 
| 180 182 |  | 
| 183 | 
            +
                  sig { params(ancestors: T::Array[AST::Node]).returns(String) }
         | 
| 181 184 | 
             
                  def parent_module_name(ancestors:)
         | 
| 182 185 | 
             
                    definitions = ancestors
         | 
| 183 186 | 
             
                      .select { |n| [CLASS, MODULE, CONSTANT_ASSIGNMENT, BLOCK].include?(type_of(n)) }
         | 
    
        data/lib/packwerk/offense.rb
    CHANGED
    
    | @@ -4,7 +4,8 @@ | |
| 4 4 | 
             
            require "parser/source/map"
         | 
| 5 5 | 
             
            require "sorbet-runtime"
         | 
| 6 6 |  | 
| 7 | 
            -
            require "packwerk/ | 
| 7 | 
            +
            require "packwerk/output_style"
         | 
| 8 | 
            +
            require "packwerk/output_styles/plain"
         | 
| 8 9 |  | 
| 9 10 | 
             
            module Packwerk
         | 
| 10 11 | 
             
              class Offense
         | 
| @@ -23,11 +24,8 @@ module Packwerk | |
| 23 24 | 
             
                  @message = message
         | 
| 24 25 | 
             
                end
         | 
| 25 26 |  | 
| 26 | 
            -
                sig  | 
| 27 | 
            -
             | 
| 28 | 
            -
                    .returns(String)
         | 
| 29 | 
            -
                end
         | 
| 30 | 
            -
                def to_s(style = OutputStyles::Plain)
         | 
| 27 | 
            +
                sig { params(style: OutputStyle).returns(String) }
         | 
| 28 | 
            +
                def to_s(style = OutputStyles::Plain.new)
         | 
| 31 29 | 
             
                  if location
         | 
| 32 30 | 
             
                    <<~EOS
         | 
| 33 31 | 
             
                      #{style.filename}#{file}#{style.reset}:#{location.line}:#{location.column}
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            # typed: strict
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Packwerk
         | 
| 5 | 
            +
              module OutputStyle
         | 
| 6 | 
            +
                extend T::Sig
         | 
| 7 | 
            +
                extend T::Helpers
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                interface!
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                sig { abstract.returns(String) }
         | 
| 12 | 
            +
                def reset; end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                sig { abstract.returns(String) }
         | 
| 15 | 
            +
                def filename; end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                sig { abstract.returns(String) }
         | 
| 18 | 
            +
                def error; end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            # typed: strict
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Packwerk
         | 
| 5 | 
            +
              module OutputStyles
         | 
| 6 | 
            +
                # See https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit for ANSI escape colour codes
         | 
| 7 | 
            +
                class Coloured
         | 
| 8 | 
            +
                  extend T::Sig
         | 
| 9 | 
            +
                  include OutputStyle
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  sig { override.returns(String) }
         | 
| 12 | 
            +
                  def reset
         | 
| 13 | 
            +
                    "\033[m"
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  sig { override.returns(String) }
         | 
| 17 | 
            +
                  def filename
         | 
| 18 | 
            +
                    # 36 is foreground cyan
         | 
| 19 | 
            +
                    "\033[36m"
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  sig { override.returns(String) }
         | 
| 23 | 
            +
                  def error
         | 
| 24 | 
            +
                    # 31 is foreground red
         | 
| 25 | 
            +
                    "\033[31m"
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            # typed: strict
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Packwerk
         | 
| 5 | 
            +
              module OutputStyles
         | 
| 6 | 
            +
                class Plain
         | 
| 7 | 
            +
                  extend T::Sig
         | 
| 8 | 
            +
                  include OutputStyle
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  sig { override.returns(String) }
         | 
| 11 | 
            +
                  def reset
         | 
| 12 | 
            +
                    ""
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  sig { override.returns(String) }
         | 
| 16 | 
            +
                  def filename
         | 
| 17 | 
            +
                    ""
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  sig { override.returns(String) }
         | 
| 21 | 
            +
                  def error
         | 
| 22 | 
            +
                    ""
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
    
        data/lib/packwerk/package_set.rb
    CHANGED
    
    | @@ -60,7 +60,8 @@ module Packwerk | |
| 60 60 | 
             
                end
         | 
| 61 61 |  | 
| 62 62 | 
             
                def package_from_path(file_path)
         | 
| 63 | 
            -
                   | 
| 63 | 
            +
                  path_string = file_path.to_s
         | 
| 64 | 
            +
                  @packages.values.find { |package| package.package_path?(path_string) }
         | 
| 64 65 | 
             
                end
         | 
| 65 66 | 
             
              end
         | 
| 66 67 | 
             
            end
         | 
| @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # typed:  | 
| 1 | 
            +
            # typed: strict
         | 
| 2 2 | 
             
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 4 | 
             
            require "packwerk/violation_type"
         | 
| @@ -6,26 +6,34 @@ require "packwerk/checker" | |
| 6 6 |  | 
| 7 7 | 
             
            module Packwerk
         | 
| 8 8 | 
             
              class PrivacyChecker
         | 
| 9 | 
            +
                extend T::Sig
         | 
| 9 10 | 
             
                include Checker
         | 
| 10 11 |  | 
| 12 | 
            +
                sig { override.returns(Packwerk::ViolationType) }
         | 
| 11 13 | 
             
                def violation_type
         | 
| 12 14 | 
             
                  ViolationType::Privacy
         | 
| 13 15 | 
             
                end
         | 
| 14 16 |  | 
| 17 | 
            +
                sig do
         | 
| 18 | 
            +
                  override
         | 
| 19 | 
            +
                    .params(reference: Packwerk::Reference, reference_lister: Packwerk::ReferenceLister)
         | 
| 20 | 
            +
                    .returns(T::Boolean)
         | 
| 21 | 
            +
                end
         | 
| 15 22 | 
             
                def invalid_reference?(reference, reference_lister)
         | 
| 16 | 
            -
                  return if reference.constant.public?
         | 
| 23 | 
            +
                  return false if reference.constant.public?
         | 
| 17 24 |  | 
| 18 25 | 
             
                  privacy_option = reference.constant.package.enforce_privacy
         | 
| 19 | 
            -
                  return if enforcement_disabled?(privacy_option)
         | 
| 26 | 
            +
                  return false if enforcement_disabled?(privacy_option)
         | 
| 20 27 |  | 
| 21 | 
            -
                  return unless privacy_option == true ||
         | 
| 28 | 
            +
                  return false unless privacy_option == true ||
         | 
| 22 29 | 
             
                    explicitly_private_constant?(reference.constant, explicitly_private_constants: privacy_option)
         | 
| 23 30 |  | 
| 24 | 
            -
                  return if reference_lister.listed?(reference, violation_type: violation_type)
         | 
| 31 | 
            +
                  return false if reference_lister.listed?(reference, violation_type: violation_type)
         | 
| 25 32 |  | 
| 26 33 | 
             
                  true
         | 
| 27 34 | 
             
                end
         | 
| 28 35 |  | 
| 36 | 
            +
                sig { override.params(reference: Packwerk::Reference).returns(String) }
         | 
| 29 37 | 
             
                def message_for(reference)
         | 
| 30 38 | 
             
                  source_desc = reference.source_package ? "'#{reference.source_package}'" : "here"
         | 
| 31 39 | 
             
                  "Privacy violation: '#{reference.constant.name}' is private to '#{reference.constant.package}' but " \
         | 
| @@ -35,12 +43,22 @@ module Packwerk | |
| 35 43 |  | 
| 36 44 | 
             
                private
         | 
| 37 45 |  | 
| 46 | 
            +
                sig do
         | 
| 47 | 
            +
                  params(
         | 
| 48 | 
            +
                    constant: ConstantDiscovery::ConstantContext,
         | 
| 49 | 
            +
                    explicitly_private_constants: T::Array[String]
         | 
| 50 | 
            +
                  ).returns(T::Boolean)
         | 
| 51 | 
            +
                end
         | 
| 38 52 | 
             
                def explicitly_private_constant?(constant, explicitly_private_constants:)
         | 
| 39 53 | 
             
                  explicitly_private_constants.include?(constant.name) ||
         | 
| 40 54 | 
             
                    # nested constants
         | 
| 41 55 | 
             
                    explicitly_private_constants.any? { |epc| constant.name.start_with?(epc + "::") }
         | 
| 42 56 | 
             
                end
         | 
| 43 57 |  | 
| 58 | 
            +
                sig do
         | 
| 59 | 
            +
                  params(privacy_option: T.nilable(T.any(T::Boolean, T::Array[String])))
         | 
| 60 | 
            +
                    .returns(T::Boolean)
         | 
| 61 | 
            +
                end
         | 
| 44 62 | 
             
                def enforcement_disabled?(privacy_option)
         | 
| 45 63 | 
             
                  [false, nil].include?(privacy_option)
         | 
| 46 64 | 
             
                end
         | 
    
        data/lib/packwerk/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: packwerk
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1.1. | 
| 4 | 
            +
              version: 1.1.2
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Shopify Inc.
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2021-01-12 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: activesupport
         | 
| @@ -223,7 +223,9 @@ files: | |
| 223 223 | 
             
            - lib/packwerk/node_processor_factory.rb
         | 
| 224 224 | 
             
            - lib/packwerk/node_visitor.rb
         | 
| 225 225 | 
             
            - lib/packwerk/offense.rb
         | 
| 226 | 
            -
            - lib/packwerk/ | 
| 226 | 
            +
            - lib/packwerk/output_style.rb
         | 
| 227 | 
            +
            - lib/packwerk/output_styles/coloured.rb
         | 
| 228 | 
            +
            - lib/packwerk/output_styles/plain.rb
         | 
| 227 229 | 
             
            - lib/packwerk/package.rb
         | 
| 228 230 | 
             
            - lib/packwerk/package_set.rb
         | 
| 229 231 | 
             
            - lib/packwerk/parsed_constant_definitions.rb
         | 
| @@ -1,41 +0,0 @@ | |
| 1 | 
            -
            # typed: true
         | 
| 2 | 
            -
            # frozen_string_literal: true
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            module Packwerk
         | 
| 5 | 
            -
              module OutputStyles
         | 
| 6 | 
            -
                class Plain
         | 
| 7 | 
            -
                  class << self
         | 
| 8 | 
            -
                    def reset
         | 
| 9 | 
            -
                      ""
         | 
| 10 | 
            -
                    end
         | 
| 11 | 
            -
             | 
| 12 | 
            -
                    def filename
         | 
| 13 | 
            -
                      ""
         | 
| 14 | 
            -
                    end
         | 
| 15 | 
            -
             | 
| 16 | 
            -
                    def error
         | 
| 17 | 
            -
                      ""
         | 
| 18 | 
            -
                    end
         | 
| 19 | 
            -
                  end
         | 
| 20 | 
            -
                end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                # See https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit for ANSI escape colour codes
         | 
| 23 | 
            -
                class Coloured
         | 
| 24 | 
            -
                  class << self
         | 
| 25 | 
            -
                    def reset
         | 
| 26 | 
            -
                      "\033[m"
         | 
| 27 | 
            -
                    end
         | 
| 28 | 
            -
             | 
| 29 | 
            -
                    def filename
         | 
| 30 | 
            -
                      # 36 is foreground cyan
         | 
| 31 | 
            -
                      "\033[36m"
         | 
| 32 | 
            -
                    end
         | 
| 33 | 
            -
             | 
| 34 | 
            -
                    def error
         | 
| 35 | 
            -
                      # 31 is foreground red
         | 
| 36 | 
            -
                      "\033[31m"
         | 
| 37 | 
            -
                    end
         | 
| 38 | 
            -
                  end
         | 
| 39 | 
            -
                end
         | 
| 40 | 
            -
              end
         | 
| 41 | 
            -
            end
         |