Class: Ace::Lint::Atoms::TypeDetector

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/lint/atoms/type_detector.rb

Overview

Pure function to detect file type from extension or content

Constant Summary collapse

BASENAME_MAP =
{
  "Gemfile" => :ruby,
  "Rakefile" => :ruby
}.freeze
EXTENSION_MAP =
{
  ".md" => :markdown,
  ".markdown" => :markdown,
  ".yml" => :yaml,
  ".yaml" => :yaml,
  ".rb" => :ruby,
  ".rake" => :ruby,
  ".gemspec" => :ruby
}.freeze
SKILL_BASENAME_PATTERN =

Patterns for markdown subtype detection SKILL.md or SKILLS.md (case-insensitive)

/\ASKILLS?\.md\z/i
WORKFLOW_SUFFIX =

*.wf.md for workflow files

".wf.md"
AGENT_SUFFIX =

*.ag.md for agent files

".ag.md"

Class Method Summary collapse

Class Method Details

.detect(file_path, content: nil) ⇒ Symbol

Detect file type from file path and optional content

Parameters:

  • file_path (String)

    Path to the file

  • content (String, nil) (defaults to: nil)

    File content for content-based detection

Returns:

  • (Symbol)

    File type (:skill, :workflow, :agent, :markdown, :yaml, :ruby, :unknown)



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/ace/lint/atoms/type_detector.rb', line 37

def self.detect(file_path, content: nil)
  return :unknown if file_path.nil? || file_path.to_s.empty?

  # Try basename-based detection for known Ruby entrypoints
  basename = File.basename(file_path)
  type = BASENAME_MAP[basename]
  return type if type

  # Try extension-based detection
  ext = File.extname(file_path).downcase
  type = EXTENSION_MAP[ext]

  # For markdown files, check for skill/workflow/agent subtypes
  if type == :markdown
    subtype = detect_markdown_subtype(file_path, basename)
    return subtype if subtype
    return :markdown
  end

  return type if type

  # Try content-based detection if content provided
  return detect_from_content(content) if content

  :unknown
end

.detect_from_content(content) ⇒ Object



90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/ace/lint/atoms/type_detector.rb', line 90

def self.detect_from_content(content)
  return :unknown if content.nil? || content.empty?

  # Check for markdown indicators
  if markdown_content?(content)
    :markdown
  # Check for YAML indicators
  elsif yaml_content?(content)
    :yaml
  else
    :unknown
  end
end

.detect_markdown_subtype(file_path, basename) ⇒ Symbol?

Detect markdown subtype based on filename patterns

Parameters:

  • file_path (String)

    Full path to the file

  • basename (String)

    File basename

Returns:

  • (Symbol, nil)

    :skill, :workflow, :agent, or nil for regular markdown



68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/ace/lint/atoms/type_detector.rb', line 68

def self.detect_markdown_subtype(file_path, basename)
  # Check for SKILL.md or SKILLS.md (case-insensitive)
  return :skill if basename.match?(SKILL_BASENAME_PATTERN)

  # Check for *.wf.md (workflow files)
  return :workflow if file_path.downcase.end_with?(WORKFLOW_SUFFIX)

  # Check for *.ag.md (agent files)
  return :agent if file_path.downcase.end_with?(AGENT_SUFFIX)

  nil
end

.has_frontmatter?(content) ⇒ Boolean

Detect if file has frontmatter

Parameters:

  • content (String)

    File content

Returns:

  • (Boolean)

    True if frontmatter detected



84
85
86
87
88
# File 'lib/ace/lint/atoms/type_detector.rb', line 84

def self.has_frontmatter?(content)
  return false if content.nil? || content.empty?

  content.start_with?("---\n") && content.include?("\n---\n")
end

.markdown_content?(content) ⇒ Boolean

Returns:

  • (Boolean)


104
105
106
107
108
109
110
111
# File 'lib/ace/lint/atoms/type_detector.rb', line 104

def self.markdown_content?(content)
  # Look for common markdown patterns
  content.match?(/^\#{1,6}\s+\S/) || # Headers
    content.match?(/^\*\s+\S/) || # Unordered lists
    content.match?(/^\d+\.\s+\S/) || # Ordered lists
    content.match?(/```/) || # Code blocks
    has_frontmatter?(content) # Frontmatter indicates markdown
end

.yaml_content?(content) ⇒ Boolean

Returns:

  • (Boolean)


113
114
115
116
117
# File 'lib/ace/lint/atoms/type_detector.rb', line 113

def self.yaml_content?(content)
  # Look for YAML patterns (key: value)
  content.match?(/^\w+:\s*\S/) ||
    content.match?(/^-\s+\w+:/) # Array of objects
end