2021-03-11 19:13:27 +05:30
# frozen_string_literal: true
module RuboCop
module Cop
module Gitlab
# Cop that enforces use of namespaced classes in order to better identify
# high level domains within the codebase.
2022-07-16 23:28:13 +05:30
#
2021-03-11 19:13:27 +05:30
# @example
# # bad
# class MyClass
# end
#
2022-07-16 23:28:13 +05:30
# module Gitlab
# class MyClass
# end
# end
#
# class Gitlab::MyClass
# end
#
2021-03-11 19:13:27 +05:30
# # good
# module MyDomain
# class MyClass
# end
# end
2022-07-16 23:28:13 +05:30
#
# module Gitlab
# module MyDomain
# class MyClass
# end
# end
# end
#
# class Gitlab::MyDomain::MyClass
# end
2022-08-13 15:12:31 +05:30
class NamespacedClass < RuboCop :: Cop :: Base
2022-07-23 23:45:48 +05:30
MSG = 'Classes must be declared inside a module indicating a product domain namespace. For more info: https://gitlab.com/gitlab-org/gitlab/-/issues/321982'
2021-03-11 19:13:27 +05:30
2022-07-16 23:28:13 +05:30
# These namespaces are considered top-level semantically.
# Note: Nested namespace like Foo::Bar are also supported.
PSEUDO_TOPLEVEL = %w[ Gitlab ]
. map { _1 . split ( '::' ) } . freeze
2021-03-11 19:13:27 +05:30
def on_module ( node )
2022-07-16 23:28:13 +05:30
add_potential_domain_namespace ( node )
2021-03-11 19:13:27 +05:30
end
def on_class ( node )
2022-07-16 23:28:13 +05:30
# Add potential namespaces from compact definitions like `class Foo::Bar`.
# Remove class name because it's not a domain namespace.
add_potential_domain_namespace ( node ) { _1 . pop }
2022-08-13 15:12:31 +05:30
add_offense ( node . loc . name ) if domain_namespaces . none?
2022-07-16 23:28:13 +05:30
end
private
def domain_namespaces
@domain_namespaces || = [ ]
end
def add_potential_domain_namespace ( node )
return if domain_namespaces . any?
identifiers = identifiers_for ( node )
yield ( identifiers ) if block_given?
PSEUDO_TOPLEVEL . each do | namespaces |
identifiers . shift ( namespaces . size ) if namespaces == identifiers . first ( namespaces . size )
end
domain_namespaces . concat ( identifiers )
end
2021-03-11 19:13:27 +05:30
2022-07-16 23:28:13 +05:30
def identifiers_for ( node )
node . identifier . source . sub ( / ^:: / , '' ) . split ( '::' )
2021-03-11 19:13:27 +05:30
end
end
end
end
end