Module: Enconvert::Formats

Defined in:
lib/enconvert/formats.rb

Overview

Format tables mirroring the gateway's CONVERTER_MAP (api/v1/convert.py).

IMPLEMENTED_CONVERSIONS is the client-side gate: the gateway returns 503 for any {input}-to-{output} endpoint not in its CONVERTER_MAP, so we reject unsupported pairs here with a useful message instead of paying a network round-trip for a guaranteed failure.

Constant Summary collapse

IMPLEMENTED_CONVERSIONS =

The 43 implemented {input}-to-{output} conversion endpoints.

Set.new(
  [
    # Structured text (13)
    "json-to-xml",
    "xml-to-json",
    "json-to-yaml",
    "yaml-to-json",
    "csv-to-json",
    "json-to-csv",
    "json-to-toml",
    "toml-to-json",
    "csv-to-xml",
    "xml-to-csv",
    "markdown-to-html",
    "markdown-to-pdf",
    "html-to-pdf",
    # Documents (9) — EPUB→PDF now flows through anything-to-pdf, not a dedicated pair.
    "doc-to-pdf",
    "excel-to-pdf",
    "ppt-to-pdf",
    "odt-to-pdf",
    "ods-to-pdf",
    "odp-to-pdf",
    "ots-to-pdf",
    "pages-to-pdf",
    "numbers-to-pdf",
    # Images (21)
    "jpeg-to-png",
    "png-to-jpeg",
    "jpeg-to-svg",
    "svg-to-jpeg",
    "jpeg-to-heic",
    "heic-to-jpeg",
    "jpeg-to-webp",
    "webp-to-jpeg",
    "png-to-svg",
    "svg-to-png",
    "png-to-heic",
    "heic-to-png",
    "png-to-webp",
    "webp-to-png",
    "svg-to-heic",
    "heic-to-svg",
    "svg-to-webp",
    "webp-to-svg",
    "heic-to-webp",
    "webp-to-heic",
    "pdf-to-jpeg"
  ]
).freeze
IMAGE_FORMATS =

Extension -> API format name (input side).

{
  ".jpg" => "jpeg",
  ".jpeg" => "jpeg",
  ".png" => "png",
  ".svg" => "svg",
  ".heic" => "heic",
  ".webp" => "webp",
  # PDF is an image input solely for pdf-to-jpeg (rasterization).
  ".pdf" => "pdf"
}.freeze
DOCUMENT_FORMATS =
{
  ".doc" => "doc",
  ".docx" => "doc",
  ".xls" => "excel",
  ".xlsx" => "excel",
  ".ppt" => "ppt",
  ".pptx" => "ppt",
  ".html" => "html",
  ".htm" => "html",
  ".odt" => "odt",
  ".ods" => "ods",
  ".odp" => "odp",
  ".ots" => "ots",
  ".pages" => "pages",
  ".numbers" => "numbers",
  # .epub has no dedicated document pair — use convert_to_pdf / convert_to_markdown.
  ".md" => "markdown",
  ".markdown" => "markdown",
  ".csv" => "csv",
  ".json" => "json",
  ".xml" => "xml",
  ".yaml" => "yaml",
  ".yml" => "yaml",
  ".toml" => "toml"
}.freeze
MIME_BY_EXT =
{
  ".jpg" => "image/jpeg",
  ".jpeg" => "image/jpeg",
  ".png" => "image/png",
  ".svg" => "image/svg+xml",
  ".heic" => "image/heic",
  ".webp" => "image/webp",
  ".pdf" => "application/pdf",
  ".doc" => "application/msword",
  ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  ".xls" => "application/vnd.ms-excel",
  ".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  ".ppt" => "application/vnd.ms-powerpoint",
  ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation",
  ".html" => "text/html",
  ".htm" => "text/html",
  ".odt" => "application/vnd.oasis.opendocument.text",
  ".ods" => "application/vnd.oasis.opendocument.spreadsheet",
  ".odp" => "application/vnd.oasis.opendocument.presentation",
  ".epub" => "application/epub+zip",
  ".md" => "text/markdown",
  ".markdown" => "text/markdown",
  ".csv" => "text/csv",
  ".json" => "application/json",
  ".xml" => "application/xml",
  ".yaml" => "application/x-yaml",
  ".yml" => "application/x-yaml",
  ".toml" => "application/toml"
}.freeze
OUTPUT_FORMAT_ALIASES =

Common aliases users pass that differ from the API's canonical format names.

{
  "jpg" => "jpeg",
  "yml" => "yaml",
  "htm" => "html",
  "md" => "markdown"
}.freeze

Class Method Summary collapse

Class Method Details

.assert_conversion_implemented(input_format, output_format) ⇒ Object

Assert {input}-to-{output} is an implemented endpoint and return its name. Raises with the list of valid outputs for that input otherwise.



181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/enconvert/formats.rb', line 181

def assert_conversion_implemented(input_format, output_format)
  endpoint = "#{input_format}-to-#{output_format}"
  unless IMPLEMENTED_CONVERSIONS.include?(endpoint)
    outputs = valid_outputs_for(input_format)
    hint = if outputs.empty?
             "No conversions are available for input format '#{input_format}'"
           else
             "Supported outputs for '#{input_format}': #{outputs.join(', ')}"
           end
    raise Enconvert::Error, "Conversion '#{input_format}' to '#{output_format}' is not supported. #{hint}."
  end
  endpoint
end

.ext_of(name) ⇒ Object



143
144
145
146
147
# File 'lib/enconvert/formats.rb', line 143

def ext_of(name)
  s = name.to_s
  i = s.rindex(".")
  i.nil? ? "" : s[i..].downcase
end

.mime_for(name) ⇒ Object



149
150
151
# File 'lib/enconvert/formats.rb', line 149

def mime_for(name)
  MIME_BY_EXT[ext_of(name)] || "application/octet-stream"
end

.normalize_output_format(fmt) ⇒ Object

Lowercase, strip a leading dot, and resolve aliases (jpg, yml, htm, md).



165
166
167
168
# File 'lib/enconvert/formats.rb', line 165

def normalize_output_format(fmt)
  f = fmt.to_s.downcase.sub(/\A\./, "")
  OUTPUT_FORMAT_ALIASES[f] || f
end

.resolve_input_format(name, map) ⇒ Object

Map a filename's extension to its API input format, or raise.



154
155
156
157
158
159
160
161
162
# File 'lib/enconvert/formats.rb', line 154

def resolve_input_format(name, map)
  ext = ext_of(name)
  fmt = map[ext]
  if fmt.nil?
    supported = map.keys.sort.join(", ")
    raise Enconvert::Error, "Unsupported file extension '#{ext}'. Supported: #{supported}"
  end
  fmt
end

.valid_outputs_for(input_format) ⇒ Object

List the output formats the API implements for a given input format.



171
172
173
174
175
176
177
# File 'lib/enconvert/formats.rb', line 171

def valid_outputs_for(input_format)
  prefix = "#{input_format}-to-"
  IMPLEMENTED_CONVERSIONS.to_a
                         .select { |name| name.start_with?(prefix) }
                         .map { |name| name[prefix.length..] }
                         .sort
end