Skip to content

Phase 3.2: Format Detector Extensions #15

@Sam-Bolling

Description

@Sam-Bolling

Task

Extend the existing format detector (src/shared/mime-type.ts) with CSAPI media type detection functions and add routing logic that maps detected media types to the appropriate format handlers.

ROADMAP Reference: Phase 3, Task 2 — Format Detector Extensions (~1-2 hours, Low complexity)


Files to Create or Modify

File Action Est. Lines Purpose
src/shared/mime-type.ts Modify ~30-40 (add ~20-28) Add isMimeTypeSmlJson, isMimeTypeSweJson, isMimeTypeSweText, isMimeTypeSweCsv, isMimeTypeSweBinary detection functions
src/shared/mime-type.spec.ts Modify ~100-130 (add ~65-95) Add tests for all new detection functions, routing logic, and fallback detection

Blueprint Reference

Follow the existing pattern in src/shared/mime-type.ts (12 lines) — each detection function is a pure function taking a mimeType: string parameter and returning boolean. The existing functions use indexOf for simple substring matching and regex for more complex patterns. Follow the existing test pattern in src/shared/mime-type.spec.ts (35 lines) — each function gets a describe block with positive and negative test cases including variations (with/without application/ prefix, case variations).

Usage blueprint: src/ogc-api/endpoint.ts (lines 45-47, 550-552) — shows how isMimeType* functions are used for content negotiation: link selection by testing link.type against each detector in priority order.

Scope — What to Implement

New Detection Functions

Add these pure functions to src/shared/mime-type.ts, following the existing isMimeType* pattern:

  1. isMimeTypeSmlJson(mimeType: string): boolean — Detects application/sml+json (SensorML JSON encoding)
  2. isMimeTypeSweJson(mimeType: string): boolean — Detects application/swe+json (SWE Common JSON encoding)
  3. isMimeTypeSweText(mimeType: string): boolean — Detects application/swe+text (SWE Common Text encoding)
  4. isMimeTypeSweCsv(mimeType: string): boolean — Detects application/swe+csv (SWE Common CSV encoding — note: this is a constrained variant of SWE Text with tokenSeparator="," and blockSeparator="\n")
  5. isMimeTypeSweBinary(mimeType: string): boolean — Detects application/swe+binary (SWE Common Binary encoding)

Each function should:

  • Match the canonical IANA media type (e.g., application/sml+json)
  • Handle case-insensitive matching
  • Handle common shorthand forms (e.g., sml+json, swe+json)
  • Return false for unrelated types

Media Type Routing Logic

Document (via JSDoc comments on each function) which handler each media type routes to:

The routing documentation prepares for future integration (Issue #30 — Format Index). The actual routing implementation happens in formats/constants.ts (Issue #29) and formats/index.ts (Issue #30). This issue only adds the detection functions.

JSDoc Requirements

  • Document each function with its media type, what format it detects, and the encoding type
  • Add @see links to OGC API - Connected Systems Part 1 (23-001) for application/sml+json and Part 2 (23-002) for application/swe+* types
  • Add @see link to RFC 6838 (Media Type Specifications)
  • Follow the JSDoc style in existing src/shared/mime-type.ts (currently undocumented — add JSDoc to existing functions as well if touching them, but do NOT refactor the function implementations)

Testing Requirements

  • Extend src/shared/mime-type.spec.ts (~65-95 new lines)
  • Test each new detection function with:
    • Canonical media type (e.g., application/sml+jsontrue)
    • Shorthand (e.g., sml+jsontrue)
    • Case variation (e.g., APPLICATION/SML+JSONtrue)
    • Negative: unrelated JSON types (e.g., application/jsonfalse, application/geo+jsonfalse)
    • Negative: other SWE types don't cross-match (e.g., isMimeTypeSweText('application/swe+json')false)
  • Test CSV vs Text distinction: isMimeTypeSweCsv('application/swe+text')false and vice versa
  • Follow test patterns from src/shared/mime-type.spec.ts

Scope — What NOT to Touch

Acceptance Criteria

  • src/shared/mime-type.ts exports 5 new detection functions: isMimeTypeSmlJson, isMimeTypeSweJson, isMimeTypeSweText, isMimeTypeSweCsv, isMimeTypeSweBinary
  • Each function correctly detects its canonical media type and common shorthand forms
  • Each function handles case-insensitive matching
  • All new code has complete JSDoc documentation with @see spec references
  • src/shared/mime-type.spec.ts has tests for all 5 new functions with positive and negative cases
  • CSV vs Text detectors do not cross-match
  • Existing tests still pass (npm test)
  • No lint errors

Dependencies

Blocked by: Nothing — detection functions are standalone utilities
Blocks: Issue #29 (Format Constants — uses these detectors for routing table), Issue #30 (Format Index — wires detectors to handlers)


Operational Constraints

⚠️ MANDATORY: Before starting work on this issue, review docs/governance/AI_OPERATIONAL_CONSTRAINTS.md.

Key constraints for this task:

  • Precedence: OGC specifications → AI Collaboration Agreement → This issue description → Existing code → Conversational context
  • No scope expansion: Do not infer unstated requirements or add unrequested features
  • No refactoring: Do not rename, restructure, or "improve" code outside this issue's scope
  • Minimal diffs: Prefer the smallest change that satisfies the acceptance criteria
  • Ask when unclear: If intent is ambiguous, stop and ask for clarification

References

Read these documents before starting implementation. They are ordered by priority.

Primary References (must read)

# Document Section/Lines What It Provides
1 docs/planning/csapi-implementation-guide.md §7 Format Detector (Lines 3088-3115) Detection strategy, media type routing table, detection methods (Content-Type parsing, Accept negotiation, structure fallback)
2 src/shared/mime-type.ts Full file (12 lines) Blueprint — existing isMimeType* function pattern
3 src/shared/mime-type.spec.ts Full file (35 lines) Blueprint — test pattern for media type detection
4 src/ogc-api/endpoint.ts Lines 42-48, 550-552 Usage pattern — how isMimeType* functions are called for content negotiation

Upstream Type/Import References (files this task imports from)

# Document What to Import
No imports needed Detection functions are standalone (string → boolean)

Research References (context, not required reading)

# Document What It Provides
1 docs/planning/ROADMAP.md (Lines 358-370) Task scope definition
2 docs/planning/csapi-implementation-guide.md (Lines 2065-2080) Directory structure showing where formats/constants.ts will live (Issue #29)

Specification References (for @see links and field accuracy)

# Document Use
1 OGC API - Connected Systems Part 1 (23-001) application/sml+json media type definition
2 docs/research/standards/ogcapi-connectedsystems-1.bundled.oas31.yaml (Lines 5121, 5167, 5236) Part 1 application/sml+json usage in OpenAPI spec
3 OGC API - Connected Systems Part 2 (23-002) application/swe+json, application/swe+text, application/swe+csv, application/swe+binary media type definitions
4 docs/research/standards/ogcapi-connectedsystems-2.bundled.oas31.yaml (Lines 1598-1636) Part 2 encoding discriminator showing all 5 SWE format variants (JSON, Text, CSV, Binary, Protobuf)
5 RFC 6838 (Media Type Specifications) Media type format and registration rules

Convention Quick Reference

Rule Example
Use .js extension for relative imports import { X } from './file.js'
Use import type for interfaces/types import type { Y } from './model.js'
Three-tier hierarchy: import from lower tiers only shared → ogc-api → csapi
Named exports for types and utilities export function isMimeTypeSmlJson(...) { ... }
HTTP mocking: globalThis.fetch = jest.fn() Never use nock, msw, or other libraries
Meaningful tests only Verify behavior, not that code runs without throwing

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions