Class: RailsAiContext::Serializers::ContextFileSerializer

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_ai_context/serializers/context_file_serializer.rb

Overview

Orchestrates writing context files to disk in various formats. Supports: CLAUDE.md, AGENTS.md, .github/copilot-instructions.md, JSON Also generates split rule files for AI tools that support them.

Root files (CLAUDE.md, etc.) are wrapped in section markers so user content outside the markers is preserved on re-generation. Set config.generate_root_files = false to skip root files entirely and only produce split rules.

Constant Summary collapse

FORMAT_MAP =
{
  claude:    "CLAUDE.md",
  opencode:  "AGENTS.md",
  codex:     "AGENTS.md",
  copilot:   ".github/copilot-instructions.md",
  json:      ".ai-context.json"
}.freeze
SPLIT_ONLY_FORMATS =

Formats that produce only split rules (no root file).

%i[cursor].freeze
ALL_FORMATS =
(FORMAT_MAP.keys + SPLIT_ONLY_FORMATS).freeze
BEGIN_MARKER =
"<!-- BEGIN rails-ai-context -->"
END_MARKER =
"<!-- END rails-ai-context -->"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context, format: :all) ⇒ ContextFileSerializer

Returns a new instance of ContextFileSerializer.



35
36
37
38
# File 'lib/rails_ai_context/serializers/context_file_serializer.rb', line 35

def initialize(context, format: :all)
  @context = context
  @format  = format
end

Instance Attribute Details

#contextObject (readonly)

Returns the value of attribute context.



17
18
19
# File 'lib/rails_ai_context/serializers/context_file_serializer.rb', line 17

def context
  @context
end

#formatObject (readonly)

Returns the value of attribute format.



17
18
19
# File 'lib/rails_ai_context/serializers/context_file_serializer.rb', line 17

def format
  @format
end

Instance Method Details

#callHash

Write context files, skipping unchanged ones.

Returns:

  • (Hash)

    { written: [paths], skipped: [paths] }



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/rails_ai_context/serializers/context_file_serializer.rb', line 42

def call
  formats = format == :all ? ALL_FORMATS : Array(format)
  output_dir = RailsAiContext.configuration.output_dir_for(Rails.application)
  generate_root = RailsAiContext.configuration.generate_root_files
  written = []
  skipped = []

  seen_root_files = Set.new

  formats.each do |fmt|
    next if SPLIT_ONLY_FORMATS.include?(fmt)

    filename = FORMAT_MAP[fmt]
    unless filename
      valid = ALL_FORMATS.map(&:to_s).join(", ")
      raise ArgumentError, "Unknown format: #{fmt}. Valid formats: #{valid}"
    end

    # Skip root files when generate_root_files is false
    next unless generate_root

    # Deduplicate: skip if this root file was already written (e.g. AGENTS.md for both :opencode and :codex)
    next if seen_root_files.include?(filename)
    seen_root_files << filename

    filepath = File.join(output_dir, filename)
    FileUtils.mkdir_p(File.dirname(filepath))
    content = serialize(fmt)

    if fmt == :json
      write_plain(filepath, content, written, skipped)
    else
      write_with_markers(filepath, content, written, skipped)
    end
  end

  # Split rules are always generated regardless of generate_root_files
  generate_split_rules(formats, output_dir, written, skipped)

  { written: written, skipped: skipped }
end