typelizer 0.4.1 → 0.5.0

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.
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Typelizer
4
+ # Context for a single writer during a generation pass.
5
+ # - Caches one Interface per serializer class (prevents duplicates/loops)
6
+ # - Computes per-serializer effective Config:
7
+ # library defaults < global (flat setters) < writer < DSL (parent → child)
8
+ class WriterContext
9
+ attr_reader :writer_config, :writer_name
10
+
11
+ def initialize(writer_name: nil, configuration: Typelizer.configuration)
12
+ @configuration = configuration
13
+ @writer_name = (writer_name || Configuration::DEFAULT_WRITER_NAME).to_sym
14
+ @writer_config = configuration.writer_config(@writer_name)
15
+
16
+ @interface_cache = {}
17
+ @config_cache = {}
18
+ @dsl_cache = {}
19
+ end
20
+
21
+ # Returns a memoized Interface for the given serializer class within this writer context
22
+ # Guarantees a single Interface instance per serializer (in this context), which:
23
+ # - preserves object identity across associations,
24
+ # - prevents infinite loops on cyclic relations,
25
+ # - and avoids redundant recomputation
26
+ # The cache is scoped to WriterContext (i.e., per writer and per generation run)
27
+ def interface_for(serializer_class)
28
+ raise ArgumentError, "Serializer class cannot be nil" if serializer_class.nil?
29
+
30
+ @interface_cache[serializer_class] ||= Interface.new(
31
+ serializer: serializer_class,
32
+ context: self
33
+ )
34
+ end
35
+
36
+ # Resolves the effective configuration for a serializer class by merging
37
+ # configuration layers in priority order:
38
+ # Library defaults
39
+ # Global configuration settings
40
+ # Writer-specific configuration
41
+ # DSL configuration with inheritance (highest priority)
42
+ def config_for(serializer_class)
43
+ raise ArgumentError, "Serializer class cannot be nil" unless serializer_class
44
+
45
+ @config_cache[serializer_class] ||= build_config(serializer_class)
46
+ end
47
+
48
+ private
49
+
50
+ # Builds the correct configuration by merging all configuration layers
51
+ def build_config(serializer_class)
52
+ global_settings = @configuration.global_settings
53
+ writer_settings = @writer_config.to_h
54
+ dsl_settings = dsl_config_for(serializer_class)
55
+
56
+ # Merge in priority order: global < writer < DSL
57
+ merged_config = deep_merge(global_settings, writer_settings)
58
+ merged_config = deep_merge(merged_config, dsl_settings)
59
+
60
+ Config.build(**merged_config).freeze
61
+ end
62
+
63
+ def dsl_config_for(klass)
64
+ return @dsl_cache[klass] if @dsl_cache.key?(klass)
65
+
66
+ # Recursively get the parent's DSL config. If no parent or parent is not
67
+ # a Typelizer serializer, the base is an empty hash.
68
+ parent_dsl = (parent = klass.superclass).respond_to?(:typelizer_config) ? dsl_config_for(parent) : {}
69
+
70
+ # Get this class's own local overrides.
71
+ local_dsl = klass.respond_to?(:typelizer_config) ? klass.typelizer_config.to_h : {}
72
+
73
+ @dsl_cache[klass] = deep_merge(parent_dsl, local_dsl).freeze
74
+ end
75
+
76
+ def deep_merge(hash_one, hash_two)
77
+ # If Active Support's `deep_merge` exists, use it
78
+ return hash_one.deep_merge(hash_two) if hash_one.respond_to?(:deep_merge)
79
+
80
+ return hash_one if hash_one == hash_two
81
+ return hash_one if hash_two.empty?
82
+ return hash_two if hash_one.empty?
83
+
84
+ hash_one.merge(hash_two) do |_, old_v, new_v|
85
+ (old_v.is_a?(Hash) && new_v.is_a?(Hash)) ? deep_merge(old_v, new_v) : new_v
86
+ end
87
+ end
88
+ end
89
+ end
data/lib/typelizer/dsl.rb CHANGED
@@ -14,18 +14,16 @@ module Typelizer
14
14
  end
15
15
 
16
16
  module ClassMethods
17
- def typelizer_config
18
- @typelizer_config ||=
19
- begin
20
- parent_config = superclass.respond_to?(:typelizer_config) ? superclass.typelizer_config : Config
21
- Config.new(parent_config.to_h.transform_values(&:dup))
22
- end
23
- yield @typelizer_config if block_given?
24
- @typelizer_config
25
- end
17
+ def typelizer_config(&block)
18
+ # Lazily initializes and memoizes the hash for local overrides at the class level.
19
+ # This ensures that all subsequent DSL calls for this specific serializer class
20
+ # modify the same single hash, allowing settings to be accumulated
21
+ @serializer_overrides ||= {}
22
+
23
+ @config_layer ||= SerializerConfigLayer.new(@serializer_overrides)
24
+ @config_layer.instance_eval(&block) if block
26
25
 
27
- def typelizer_interface
28
- @typelizer_interface ||= Interface.new(serializer: self)
26
+ @config_layer
29
27
  end
30
28
 
31
29
  # save association of serializer to model
@@ -6,24 +6,26 @@ module Typelizer
6
6
  new.call(**args)
7
7
  end
8
8
 
9
- def initialize(config = Typelizer::Config)
10
- @config = config
11
- @writer = Writer.new
12
- end
13
-
14
- attr_reader :config, :writer
15
-
16
9
  def call(force: false)
17
- return unless Typelizer.enabled?
10
+ return [] unless Typelizer.enabled?
18
11
 
19
- found_interfaces = interfaces
20
- writer.call(found_interfaces, force: force)
21
- found_interfaces
22
- end
12
+ # plugin scan per run cache
13
+ @scan_plugin_cache = {}
23
14
 
24
- def interfaces
25
15
  read_serializers
26
- target_serializers.map(&:typelizer_interface).reject(&:empty?)
16
+ serializers = target_serializers
17
+
18
+ # For each writer, build a dedicated WriterContext. The context holds that writer's
19
+ # configuration and resolves the effective Config for every Interface (per serializer)
20
+ # by merging global, writer, and per-serializer (DSL) overrides
21
+ Typelizer.configuration.writers.each do |writer_name, writer_config|
22
+ context = WriterContext.new(writer_name: writer_name)
23
+ interfaces = serializers.map { |klass| context.interface_for(klass) }
24
+
25
+ Writer.new(writer_config).call(interfaces, force: force)
26
+ end
27
+
28
+ serializers
27
29
  end
28
30
 
29
31
  private
@@ -44,9 +46,10 @@ module Typelizer
44
46
  files ||= Typelizer.dirs.flat_map { |dir| Dir["#{dir}/**/*.rb"] }
45
47
  files.each do |file|
46
48
  trace = TracePoint.new(:call) do |tp|
47
- next unless tp.self.is_a?(Class) && tp.self.respond_to?(:typelizer_interface) && tp.self.typelizer_interface.is_a?(Interface)
49
+ next unless tp.self.is_a?(Class) && tp.self.respond_to?(:typelizer_config)
48
50
 
49
- serializer_plugin = tp.self.typelizer_interface.serializer_plugin
51
+ serializer_plugin = build_scan_plugin_for(tp.self)
52
+ next unless serializer_plugin
50
53
 
51
54
  if tp.callee_id.in?(serializer_plugin.methods_to_typelize)
52
55
  type, attrs = tp.self.keyless_type
@@ -61,5 +64,22 @@ module Typelizer
61
64
  trace.disable
62
65
  end
63
66
  end
67
+
68
+ # Builds a minimal plugin instance used only during scan time for TracePoint
69
+ def build_scan_plugin_for(serializer_klass)
70
+ return @scan_plugin_cache[serializer_klass] if @scan_plugin_cache&.key?(serializer_klass)
71
+
72
+ base = Typelizer.configuration.writer_config(:default)
73
+ local_configuration = serializer_klass.typelizer_config.to_h.slice(:serializer_plugin, :plugin_configs)
74
+ cfg = base.with_overrides(**local_configuration)
75
+
76
+ @scan_plugin_cache[serializer_klass] = cfg.serializer_plugin.new(
77
+ serializer: serializer_klass,
78
+ config: cfg,
79
+ context: Typelizer::ScanContext
80
+ )
81
+ rescue NameError
82
+ nil
83
+ end
64
84
  end
65
85
  end
@@ -1,14 +1,22 @@
1
1
  module Typelizer
2
2
  class Interface
3
- attr_reader :serializer, :serializer_plugin
3
+ attr_reader :serializer, :context
4
+
5
+ def initialize(serializer:, context:)
6
+ @serializer = serializer
7
+ @context = context
8
+ end
4
9
 
5
10
  def config
6
- serializer.typelizer_config
11
+ context.config_for(serializer)
7
12
  end
8
13
 
9
- def initialize(serializer:)
10
- @serializer = serializer
11
- @serializer_plugin = config.serializer_plugin.new(serializer: serializer, config: config)
14
+ def serializer_plugin
15
+ @serializer_plugin ||= config.serializer_plugin.new(
16
+ serializer: serializer,
17
+ config: config,
18
+ context: context
19
+ )
12
20
  end
13
21
 
14
22
  def inline?
@@ -69,12 +77,14 @@ module Typelizer
69
77
 
70
78
  def parent_interface
71
79
  return if config.inheritance_strategy == :none
72
- return unless serializer.superclass.respond_to?(:typelizer_interface)
73
80
 
74
- interface = serializer.superclass.typelizer_interface
75
- return if interface.empty?
81
+ parent_class = serializer.superclass
82
+ return unless parent_class.respond_to?(:typelizer_config)
83
+
84
+ parent_interface = context.interface_for(parent_class)
85
+ return if parent_interface.empty?
76
86
 
77
- interface
87
+ parent_interface
78
88
  end
79
89
 
80
90
  def imports
@@ -140,8 +150,12 @@ module Typelizer
140
150
  def model_class
141
151
  return serializer._typelizer_model_name if serializer.respond_to?(:_typelizer_model_name)
142
152
 
143
- config.serializer_model_mapper.call(serializer)
144
- rescue NameError
153
+ # Execute the `serializer_model_mapper` lambda in the context of the `config` object
154
+ # This giving a possibility to access other lambdas, for example, `serializer_name_mapper`
155
+ config.instance_exec(serializer, &config.serializer_model_mapper)
156
+ rescue NameError => e
157
+ Typelizer.logger.debug("model_mapper failed for serializer #{serializer.name}: #{e.class}: #{e.message}")
158
+
145
159
  nil
146
160
  end
147
161
 
@@ -9,33 +9,61 @@ module Typelizer
9
9
  attr_reader :model_class, :config
10
10
 
11
11
  def infer_types(prop)
12
- if (association = model_class&.reflect_on_association(prop.column_name.to_sym))
13
- case association.macro
14
- when :belongs_to
15
- foreign_key = association.foreign_key
16
- column = model_class&.columns_hash&.dig(foreign_key.to_s)
17
- if config.associations_strategy == :database
18
- prop.nullable = column.null if column
19
- elsif config.associations_strategy == :active_record
20
- prop.nullable = association.options[:optional] === true || association.options[:required] === false
21
- else
22
- raise "Unknown associations strategy: #{config.associations_strategy}"
23
- end
24
- when :has_one
25
- if config.associations_strategy == :database
26
- prop.nullable = true
27
- elsif config.associations_strategy == :active_record
28
- prop.nullable = !association.options[:required]
29
- else
30
- raise "Unknown associations strategy: #{config.associations_strategy}"
31
- end
12
+ infer_types_for_association(prop) ||
13
+ infer_types_for_column(prop) ||
14
+ infer_types_for_attribute(prop)
15
+
16
+ prop
17
+ end
18
+
19
+ def comment_for(prop)
20
+ column = model_class&.columns_hash&.dig(prop.column_name.to_s)
21
+ return nil unless column
22
+
23
+ prop.comment = column.comment
24
+ end
25
+
26
+ def enum_for(prop)
27
+ return unless model_class&.defined_enums&.key?(prop.column_name.to_s)
28
+
29
+ prop.enum = model_class.defined_enums[prop.column_name.to_s].keys
30
+ end
31
+
32
+ private
33
+
34
+ def infer_types_for_association(prop)
35
+ association = model_class&.reflect_on_association(prop.column_name.to_sym)
36
+ return nil unless association
37
+
38
+ case association.macro
39
+ when :belongs_to
40
+ foreign_key = association.foreign_key
41
+ column = model_class&.columns_hash&.dig(foreign_key.to_s)
42
+ if config.associations_strategy == :database
43
+ prop.nullable = column.null if column
44
+ elsif config.associations_strategy == :active_record
45
+ prop.nullable = association.options[:optional] === true || association.options[:required] === false
46
+ else
47
+ raise "Unknown associations strategy: #{config.associations_strategy}"
48
+ end
49
+ when :has_one
50
+ if config.associations_strategy == :database
51
+ prop.nullable = true
52
+ elsif config.associations_strategy == :active_record
53
+ prop.nullable = !association.options[:required]
54
+ else
55
+ raise "Unknown associations strategy: #{config.associations_strategy}"
32
56
  end
33
- return prop
34
57
  end
35
58
 
59
+ prop
60
+ end
61
+
62
+ def infer_types_for_column(prop)
36
63
  column = model_class&.columns_hash&.dig(prop.column_name.to_s)
37
- return prop unless column
64
+ return nil unless column
38
65
 
66
+ column = model_class&.columns_hash&.dig(prop.column_name.to_s)
39
67
  prop.multi = !!column.try(:array)
40
68
  case config.null_strategy
41
69
  when :nullable
@@ -57,17 +85,20 @@ module Typelizer
57
85
  prop
58
86
  end
59
87
 
60
- def comment_for(prop)
61
- column = model_class&.columns_hash&.dig(prop.column_name.to_s)
62
- return nil unless column
88
+ def infer_types_for_attribute(prop)
89
+ return nil unless model_class.respond_to?(:attribute_types)
63
90
 
64
- prop.comment = column.comment
65
- end
91
+ attribute_type_obj = model_class.attribute_types[prop.column_name.to_s]
92
+ return nil unless attribute_type_obj
66
93
 
67
- def enum_for(prop)
68
- return unless model_class&.defined_enums&.key?(prop.column_name.to_s)
94
+ if attribute_type_obj.respond_to?(:subtype)
95
+ prop.type = @config.type_mapping[attribute_type_obj.subtype.type]
96
+ prop.multi = true
97
+ elsif attribute_type_obj.respond_to?(:type)
98
+ prop.type = @config.type_mapping[attribute_type_obj.type]
99
+ end
69
100
 
70
- prop.enum = model_class.defined_enums[prop.column_name.to_s].keys
101
+ prop
71
102
  end
72
103
  end
73
104
  end
@@ -26,8 +26,9 @@ module Typelizer
26
26
  def fingerprint
27
27
  props = to_h
28
28
  props[:type] = type_name
29
- props = props.filter_map { |k, v| "#{k}=#{v.inspect}" unless v.nil? }
30
- "<#{self.class.name} #{props.join(" ")}>"
29
+ props.each_with_object(+"<#{self.class.name}") do |(k, v), fp|
30
+ fp << " #{k}=#{v.inspect}" unless v.nil?
31
+ end << ">"
31
32
  end
32
33
 
33
34
  private
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Typelizer
4
+ # SerializerConfigLayer
5
+ #
6
+ # Lightweight, validated container for per-serializer overrides defined via the DSL.
7
+ #
8
+ # - Backed by a plain Hash for cheap deep-merge later (see WriterContext).
9
+ # - Only keys from Config.members are allowed; unknown keys raise NoMethodError.
10
+ # - Supports flat setters/getters in the DSL (e.g., c.null_strategy = :nullable_and_optional).
11
+ # - Mutable only via the DSL; #to_h returns a frozen hash to prevent external mutation.
12
+ #
13
+ # Rationale: we don't allocate another Config here; this layer is merged on top of
14
+ # library/global/writer settings when computing the effective config.
15
+ class SerializerConfigLayer
16
+ VALID_KEYS = Config.members.to_set
17
+
18
+ def initialize(target_hash)
19
+ @target_hash = target_hash
20
+ end
21
+
22
+ def to_h
23
+ @target_hash.dup.freeze
24
+ end
25
+
26
+ private
27
+
28
+ def method_missing(name, *args)
29
+ name = name.to_s
30
+ key = name.chomp("=").to_sym
31
+
32
+ raise NoMethodError, "Unknown configuration key: '#{key}'" unless VALID_KEYS.include?(key)
33
+
34
+ return @target_hash[key] = args.first if name.end_with?("=") && args.length == 1
35
+
36
+ return @target_hash[key] if args.empty?
37
+
38
+ super
39
+ end
40
+
41
+ def respond_to_missing?(name, include_private = false)
42
+ VALID_KEYS.include?(name.to_s.chomp("=").to_sym) || super
43
+ end
44
+ end
45
+ end
@@ -92,13 +92,14 @@ module Typelizer
92
92
  )
93
93
  when ::Alba::Association
94
94
  resource = attr.instance_variable_get(:@resource)
95
+
95
96
  Property.new(
96
97
  name: name,
97
- type: Interface.new(serializer: resource),
98
+ type: context.interface_for(resource),
98
99
  optional: false,
99
100
  nullable: false,
100
101
  multi: false, # we override this in typelize_method_transform
101
- column_name: column_name,
102
+ column_name: attr.name.is_a?(Symbol) ? attr.name.name : attr.name,
102
103
  **options
103
104
  )
104
105
  when ::Alba::TypedAttribute
@@ -18,7 +18,7 @@ module Typelizer
18
18
 
19
19
  def properties
20
20
  serializer._attributes_data.merge(serializer._reflections).flat_map do |key, association|
21
- type = association.options[:serializer] ? Interface.new(serializer: association.options[:serializer]) : nil
21
+ type = association.options[:serializer] ? context.interface_for(association.options[:serializer]) : nil
22
22
  adapter = ActiveModelSerializers::Adapter.configured_adapter
23
23
  Property.new(
24
24
  name: adapter.transform_key_casing!(key.to_s, association.options),
@@ -2,8 +2,8 @@ module Typelizer
2
2
  module SerializerPlugins
3
3
  module Auto
4
4
  class << self
5
- def new(serializer:, config:)
6
- plugin(serializer).new(serializer: serializer, config: config)
5
+ def new(serializer:, config:, context:)
6
+ plugin(serializer).new(serializer: serializer, config: config, context: context)
7
7
  end
8
8
 
9
9
  def plugin(serializer)
@@ -1,9 +1,10 @@
1
1
  module Typelizer
2
2
  module SerializerPlugins
3
3
  class Base
4
- def initialize(serializer:, config:)
4
+ def initialize(serializer:, config:, context:)
5
5
  @serializer = serializer
6
6
  @config = config
7
+ @context = context
7
8
  end
8
9
 
9
10
  def root_key
@@ -28,7 +29,7 @@ module Typelizer
28
29
 
29
30
  private
30
31
 
31
- attr_reader :serializer, :config
32
+ attr_reader :serializer, :config, :context
32
33
  end
33
34
  end
34
35
  end
@@ -18,9 +18,9 @@ module Typelizer
18
18
  attributes
19
19
  .flat_map do |key, options|
20
20
  if options[:association] == :flat
21
- Interface.new(serializer: options.fetch(:serializer)).properties
21
+ context.interface_for(options.fetch(:serializer)).properties
22
22
  else
23
- type = options[:serializer] ? Interface.new(serializer: options[:serializer]) : options[:type]
23
+ type = options[:serializer] ? context.interface_for(options[:serializer]) : options[:type]
24
24
  Property.new(
25
25
  name: key,
26
26
  type: type,
@@ -48,7 +48,7 @@ module Typelizer
48
48
  def association_property(assoc, multi: false)
49
49
  key = assoc.name_str
50
50
  serializer = assoc.descriptor.type
51
- type = serializer ? Interface.new(serializer: serializer) : nil
51
+ type = serializer ? context.interface_for(serializer) : nil
52
52
  Property.new(
53
53
  name: key,
54
54
  type: type,
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Typelizer
4
- VERSION = "0.4.1"
4
+ VERSION = "0.5.0"
5
5
  end
@@ -4,27 +4,51 @@ require "fileutils"
4
4
 
5
5
  module Typelizer
6
6
  class Writer
7
- def initialize
7
+ class WriterError < StandardError; end
8
+
9
+ def initialize(config)
8
10
  @template_cache = {}
9
- @config = Config
11
+ @config = config
10
12
  end
11
13
 
12
- attr_reader :config, :template_cache
13
-
14
14
  def call(interfaces, force:)
15
15
  cleanup_output_dir if force
16
16
 
17
- written_files = interfaces.map { |interface| write_interface(interface) }
18
- written_files << write_index(interfaces)
17
+ valid_interfaces = interfaces.reject(&:empty?)
18
+ return [] if valid_interfaces.empty?
19
19
 
20
- existing_files = Dir[File.join(config.output_dir, "**/*.ts")]
21
- files_to_delete = existing_files - written_files
20
+ written_files = []
21
+
22
+ begin
23
+ written_files.concat(valid_interfaces.map { |interface| write_interface(interface) })
22
24
 
23
- File.delete(*files_to_delete) unless files_to_delete.empty?
25
+ written_files << write_index(valid_interfaces)
26
+
27
+ cleanup_stale_files(written_files) unless force
28
+
29
+ Typelizer.logger.debug("Generated #{written_files.size} TypeScript files in #{config.output_dir}")
30
+
31
+ written_files
32
+ rescue => e
33
+ # if during the file generations an error appears, we remove generated files
34
+ cleanup_partial_writes(written_files)
35
+ raise WriterError, "Failed to write TypeScript files (#{e.class}): #{e.message}"
36
+ end
24
37
  end
25
38
 
26
39
  private
27
40
 
41
+ attr_reader :config, :template_cache
42
+
43
+ def cleanup_stale_files(written_files)
44
+ return unless File.directory?(config.output_dir)
45
+
46
+ existing_files = Dir[File.join(config.output_dir, "**/*.ts")]
47
+ stale_files = existing_files - written_files
48
+
49
+ File.delete(*stale_files) unless stale_files.empty?
50
+ end
51
+
28
52
  def write_index(interfaces)
29
53
  write_file("index.ts", interfaces.map(&:filename).join) do
30
54
  render_template("index.ts.erb", interfaces: interfaces)
@@ -60,5 +84,9 @@ module Typelizer
60
84
  def cleanup_output_dir
61
85
  FileUtils.rm_rf(config.output_dir)
62
86
  end
87
+
88
+ def cleanup_partial_writes(partial_files)
89
+ File.delete(*partial_files) unless partial_files.empty?
90
+ end
63
91
  end
64
92
  end
data/lib/typelizer.rb CHANGED
@@ -1,16 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "typelizer/version"
4
- require_relative "typelizer/config"
5
4
  require_relative "typelizer/property"
5
+ require_relative "typelizer/model_plugins/auto"
6
+ require_relative "typelizer/serializer_plugins/auto"
7
+
8
+ require_relative "typelizer/config"
9
+ require_relative "typelizer/configuration"
10
+ require_relative "typelizer/serializer_config_layer"
11
+
12
+ require_relative "typelizer/contexts/writer_context"
13
+ require_relative "typelizer/contexts/scan_context"
6
14
  require_relative "typelizer/interface"
7
15
  require_relative "typelizer/renderer"
8
16
  require_relative "typelizer/writer"
9
17
  require_relative "typelizer/generator"
10
-
11
18
  require_relative "typelizer/dsl"
12
19
 
13
- require_relative "typelizer/serializer_plugins/auto"
14
20
  require_relative "typelizer/serializer_plugins/oj_serializers"
15
21
  require_relative "typelizer/serializer_plugins/alba"
16
22
  require_relative "typelizer/serializer_plugins/ams"
@@ -18,30 +24,39 @@ require_relative "typelizer/serializer_plugins/panko"
18
24
 
19
25
  require_relative "typelizer/model_plugins/active_record"
20
26
  require_relative "typelizer/model_plugins/poro"
21
- require_relative "typelizer/model_plugins/auto"
22
27
 
23
28
  require_relative "typelizer/railtie" if defined?(Rails)
24
29
 
25
30
  require "logger"
31
+ require "forwardable"
26
32
 
27
33
  module Typelizer
28
34
  class << self
35
+ extend Forwardable
36
+
37
+ # readers
38
+ def_delegators :configuration, :dirs, :reject_class, :listen, :writer
39
+
40
+ # writers
41
+ def_delegators :configuration, :dirs=, :reject_class=, :listen=
42
+
29
43
  def enabled?
30
44
  return false if ENV["DISABLE_TYPELIZER"] == "true" || ENV["DISABLE_TYPELIZER"] == "1"
31
45
 
32
46
  ENV["RAILS_ENV"] == "development" || ENV["RACK_ENV"] == "development" || ENV["DISABLE_TYPELIZER"] == "false"
33
47
  end
34
48
 
35
- attr_accessor :dirs
36
- attr_accessor :reject_class
37
49
  attr_accessor :logger
38
- attr_accessor :listen
39
50
 
40
51
  # @private
41
52
  attr_reader :base_classes
42
53
 
54
+ def configuration
55
+ @configuration ||= Configuration.new
56
+ end
57
+
43
58
  def configure
44
- yield Config
59
+ yield configuration
45
60
  end
46
61
 
47
62
  private
@@ -50,10 +65,7 @@ module Typelizer
50
65
  end
51
66
 
52
67
  # Set in the Railtie
53
- self.dirs = []
54
- self.reject_class = ->(serializer:) { false }
55
68
  self.logger = Logger.new($stdout, level: :info)
56
- self.listen = nil
57
69
 
58
70
  self.base_classes = Set.new
59
71
  end