Branch: phase-6
Date: 2025
Scope: All 28+ source files in src/ogc-api/csapi/, modified upstream files, package configuration
- Executive Summary
- Severity Legend
- Per-File Analysis
- Cross-Cutting Findings
- Findings by Severity
- Metrics Summary
- Recommendations
The CSAPI module is a well-structured, densely documented TypeScript library implementing OGC API — Connected Systems Parts 1 & 2, SensorML 3.0, and SWE Common 3.0. The codebase exhibits strong engineering discipline: correct ESM import conventions, consistent import type usage, a clean three-tier dependency hierarchy, and exceptional JSDoc coverage.
Key findings:
| Severity | Count |
|---|---|
| BUG | 1 |
| DESIGN | 8 |
| GAP | 2 |
| CONSISTENCY | 4 |
| INFORMATIONAL | 5 |
| POSITIVE | 12 |
No runtime-breaking bugs were found. The single BUG-level finding is a planned as any cast in factory.ts that is already tracked (Issue #122). Design-level findings center on code duplication and a structural circular import.
| Level | Meaning |
|---|---|
| BUG | Incorrect behavior, type-safety hole, or runtime risk |
| DESIGN | Architectural concern or code smell that increases maintenance burden |
| GAP | Missing feature, incomplete implementation, or spec deviation |
| CONSISTENCY | Inconsistency in naming, patterns, or conventions |
| INFORMATIONAL | Observation or documentation note; no action needed |
| POSITIVE | Exemplary practice worth preserving |
| Aspect | Assessment |
|---|---|
| Purpose | Creates CSAPIQueryBuilder instances from OgcApiEndpoint + collectionId |
| Imports | import type OgcApiEndpoint (correct), import type { OgcApiCollectionInfo } (correct), value imports from shared/errors.js, url_builder.js, helpers.js — all .js extensions ✅ |
| Exports | createCSAPIBuilder (async function) |
| JSDoc | Complete: @param, @returns, @throws, @example, @see |
| Spec compliance | N/A (factory pattern, no OGC normative behavior) |
Findings:
- [BUG]
as anyon line 46 —const ep = endpoint as any;bypasses TypeScript to accessprivatemembers.rootand.getCollectionDocument()onOgcApiEndpoint. Theas unknown as OgcApiCollectionInfodouble cast on line 57 compounds this. Both are documented with a comment referencing Issue #122 (Task 6) which will make these members public. Risk: IfOgcApiEndpoint's private API changes, this silently breaks with no compile-time error. - [POSITIVE] Comment on lines 44–45 clearly explains the rationale and planned removal timeline.
| Aspect | Assessment |
|---|---|
| Purpose | Barrel re-export file for @camptocamp/ogc-client/csapi sub-path |
| Imports | All re-exports use .js extensions ✅ |
| Exports | ~170 named symbols (values + types), grouped by category |
| JSDoc | @module with usage example |
| Spec compliance | N/A (re-export only) |
Findings:
- [POSITIVE] Uses
export typecorrectly for every type-only re-export. - [POSITIVE] Logical grouping by resource tier (factory → builder → model → formats → SensorML → SWE Common).
- [INFORMATIONAL] At ~170 exports this is one of the larger barrel files; if tree-shaking issues arise, consider splitting.
| Aspect | Assessment |
|---|---|
| Purpose | All CSAPI TypeScript interfaces, types, and const value arrays |
| Imports | import type from ../../shared/models.js, ../model.js, geojson — all correct ✅ |
| Exports | 9 resource interfaces, query option interfaces, collection types, schema response types, CSAPIResourceTypes, CommandStatusCodes, SystemTypeUris |
| JSDoc | Thorough — @see links to spec table numbers throughout |
| Spec compliance | Closely tracks OGC 23-001 & 23-002 table definitions |
Findings:
- [DESIGN]
SystemTypeUris(line ~43) contains only full URI forms (http://www.w3.org/ns/sosa/Sensor, etc.). A differentSystemTypeUrisinformats/constants.tshas both CURIE (sosa:Sensor) and full URI forms. Same exported name, different values, from different modules. See Finding D-1. - [POSITIVE]
Deployment.validTimeis marked optional with a detailed Postel's Law justification comment, despite being "Required" in spec Table 10. - [POSITIVE] Uses inline
import()types for SWE Common references inDatastreamSchemaResponse/ControlStreamSchemaResponse— avoids importing the full SWE Common module at the type level. - [INFORMATIONAL]
CommandStatusCodesincludes both full URIs and CURIEs — consistent with the Part 2 spec's allowance of both.
| Aspect | Assessment |
|---|---|
| Purpose | Utility functions: temporal formatting, validation, link scanning |
| Imports | Value + type imports from ./model.js, ./formats/constants.js — .js extensions ✅ |
| Exports | formatDateTimeParameter, isValidResourceType, assertValidResourceType, encodeResourceId, scanCsapiLinks, validateLimit, validateBbox |
| JSDoc | Complete — every function has @param, @returns, @throws |
| Spec compliance | Handles 3 link-relation conventions (ogc-cs:, plain name, items-with-href) |
Findings:
- [POSITIVE]
scanCsapiLinksnormalizesfeaturesOfInterest→samplingFeatures, handling the alias cleanly. - [POSITIVE]
validateBboxvalidates both 4-element and 6-element bounding boxes with per-elementisFinite()checks. - [INFORMATIONAL] No
as anycasts.
| Aspect | Assessment |
|---|---|
| Purpose | Main CSAPIQueryBuilder class — URL construction for all 9 resource types |
| Imports | Type imports from ./model.js, value import from ./helpers.js — .js extensions ✅ |
| Exports | CSAPIQueryBuilder (default), PARAM_NAME_MAP, TEMPORAL_KEYS, RESOURCE_PATH_OVERRIDES |
| JSDoc | Exceptional — every public method has @param, @returns, @throws, @example, @see |
| Spec compliance | Implements query parameters per Part 1 Table 8 & Part 2 Table 6 |
Findings:
- [CONSISTENCY]
getCommandStatusvs other methods — Most methods delegate query string construction tobuildQueryString(), butgetCommandStatusmanually appends the query string withnew URLSearchParams(). This works correctly but breaks the internal pattern. - [POSITIVE]
PARAM_NAME_MAPcleanly maps TypeScript names to OGC wire names (currentStatus → statusCode,systemId → system,foiId → foi). - [POSITIVE] Comment documents the historical double-encoding bug (F5) and how it was fixed.
- [POSITIVE]
RESOURCE_PATH_OVERRIDEShandles thecontrolStreams → controlstreamsURL lowercasing. - [INFORMATIONAL] At 2,490 lines this is the largest file. The class has ~80 public methods. Consider splitting into sub-classes by resource type in a future refactor, but the current monolith is coherent and well-organized.
| Aspect | Assessment |
|---|---|
| Purpose | Per-server routing fallback for /commands rejection (OSH compatibility) |
| Imports | Value + type imports — .js extensions ✅ |
| Exports | getCommandRoutingPreference, setCommandRoutingPreference, clearCommandRoutingCache, isCommandRouteRejection, buildNestedCommandUrl |
| JSDoc | Complete with @module, @example, @param, @returns |
| Spec compliance | Implements fallback for servers that reject top-level routes |
Findings:
- [DESIGN] Module-level mutable state —
routingCache_is a module-levelMap<string, CommandRoutingPreference>. This is acceptable for a caching layer but means it's shared across all usages in the same JS context. TheclearCommandRoutingCache()export mitigates this for testing. - [POSITIVE] Clean separation of routing logic from the main builder.
| Aspect | Assessment |
|---|---|
| Purpose | Barrel re-export for all format handlers |
| Imports/Exports | Re-exports from 9 sub-modules — .js extensions ✅, export type correct ✅ |
| JSDoc | Module-level comment |
Findings:
- [CONSISTENCY] Some type re-exports are individual lines (e.g.,
export type { Link }on its own) rather than grouped with related types. Minor style inconsistency. - [POSITIVE] Clean separation of concerns across sub-modules.
| Aspect | Assessment |
|---|---|
| Purpose | Media types, vocabulary URIs, asset types, content-type map |
| Imports | import type from ../model.js ✅ |
| Exports | 7 media type constants, *TypeUris objects, CSAPI_CONTENT_TYPES, vocabulary namespace constants |
| JSDoc | Complete with spec references |
| Spec compliance | Closely tracks OGC 23-001 Requirement Classes |
Findings:
- [DESIGN] D-1:
SystemTypeUrisname collision —constants.tsdefinesSystemTypeUriswith both CURIE forms (sosa:Sensor,ssn:System) and full URI forms.model.tsdefinesSystemTypeUriswith only full URI forms. Both are exported from the barrel. Consumer code importing from different modules gets different values under the same name. Recommendation: Rename one — e.g.,SystemTypeVocabularyin constants vsSystemTypeUrisin model, or consolidate into a single source. - [POSITIVE]
CSAPI_CONTENT_TYPEScorrectly maps resource types to appropriateContent-Typeheaders for write operations.
| Aspect | Assessment |
|---|---|
| Purpose | GeoJSON Feature type recognition and Part 1 resource extraction |
| Imports | Type + value imports from model, constants, sensorml — .js extensions ✅ |
| Exports | isCSAPIFeature, getCSAPIResourceType, parseValidTime, isValidUri, extractCSAPIFeature |
| JSDoc | Complete |
| Spec compliance | Implements classification priority: SOSA → SSN → SensorML vocabularies |
Findings:
- [POSITIVE]
extractCSAPIFeaturereturns a typed union and usessatisfiesfor type narrowing — clean pattern. - [POSITIVE] Parses
@linkinline associations (systemKind@link,platform@link,deployedSystems@link,sampledFeature@link) per the OGC extension pattern. - [POSITIVE]
parseResourceRefhandles OSH'stypefallback forrt— good interoperability. - [INFORMATIONAL] Line 492:
as unknown[]appears in a spread context — safe widening, not a type-safety hole.
| Aspect | Assessment |
|---|---|
| Purpose | Endpoint-context fallback for servers returning featureType: null (52North) |
| Imports | Type import from model — .js extension ✅ |
| Exports | inferResourceTypeFromPath, classifyFeature |
| JSDoc | Complete |
Findings:
- [POSITIVE]
classifyFeaturenever overrides a validfeatureType— only fills in when null. Defensive design.
| Aspect | Assessment |
|---|---|
| Purpose | Parse Property (DerivedProperty) — the only Part 1 resource that is NOT a GeoJSON Feature |
| Imports | Type import — .js extension ✅ |
| Exports | parseProperty |
| JSDoc | Complete; notes no live server currently returns Property data |
Findings:
- [GAP] Parser cannot be tested against live data — "No live server currently returns Property data (confirmed Smoke Test #6)". Low risk; the parser is structurally simple.
| Aspect | Assessment |
|---|---|
| Purpose | Normalize FeatureCollection vs Items envelope formats |
| Imports | Value + type imports — .js extensions ✅ |
| Exports | Envelope normalization functions |
| JSDoc | Complete |
Findings:
- [POSITIVE] Handles both
features[](RFC 7946) anditems[](OSH / Part 2) envelope formats.
| Aspect | Assessment |
|---|---|
| Purpose | Parse datastream & control stream schema responses |
| Imports | Delegates to parseSWEComponent() and parseEncoding() — .js extensions ✅ |
| Exports | parseDatastreamSchemaResponse, parseControlStreamSchemaResponse |
| JSDoc | Complete |
Findings:
- [INFORMATIONAL] Clean delegation to SWE Common parsers.
| Aspect | Assessment |
|---|---|
| Purpose | All 5 Part 2 resource parsers |
| Imports | Type + value imports — .js extensions ✅ |
| Exports | parseDatastream, parseObservation, parseControlStream, parseCommand, parseCommandStatus, normalizeStatusCode |
| JSDoc | Complete with spec references |
| Spec compliance | Tracks Part 2 Tables closely |
Findings:
- [CONSISTENCY] Time field asymmetry —
parseObservationpasses time strings through as-is, whileparseDatastream/parseControlStreamparse intervals. Documented in comments, but a future consumer expecting uniform behavior could be surprised. Each approach matches its spec table, so this is spec-driven rather than a bug. - [CONSISTENCY] Default statusCode handling —
parseCommandStatusdefaults to'PENDING'whenstatusCodeis missing, whileparseCommand'scurrentStatusremainsundefinedwhen absent. Both approaches are defensible but inconsistent. - [POSITIVE]
normalizeObservedPropertieshandles both[{definition, label}]and["uri"]forms — good server interoperability. - [POSITIVE] Extracts cross-references (
system@id→systemId,datastream@id,samplingFeature@id,foi@id) per Part 2 convention.
| Aspect | Assessment |
|---|---|
| Purpose | Barrel re-export for SensorML parsers + types |
| Exports | Values + types from parser, sub-parsers, helpers, errors, types |
| JSDoc | Module-level |
Findings:
- [POSITIVE] Clean barrel with correct
export typeusage.
| Aspect | Assessment |
|---|---|
| Purpose | Complete SensorML 3.0 type hierarchy |
| Imports | None (leaf type file) |
| Exports | All SensorML interfaces, types, SENSORML_PROCESS_TYPES const |
| JSDoc | Thorough — @see OAS line references throughout |
Findings:
- [POSITIVE] Clean discriminated union via
SensorMLProcess['type']. - [POSITIVE]
SENSORML_PROCESS_TYPESas const tuple enables runtime validation.
| Aspect | Assessment |
|---|---|
| Purpose | Main SensorML parser — type discrimination + shared property parsers |
| Imports | Type + value imports from types.js, SWE Common types.js, errors.js, _helpers.js, sub-parser files — .js extensions ✅ |
| Exports | parseSensorML30, plus shared parsers for DescribedObject/AbstractProcess/AbstractPhysicalProcess levels |
| JSDoc | Excellent — @module with entry points listed |
Findings:
- [DESIGN] D-2: Circular import —
parser.ts→ sub-parsers →_helpers.ts→parser.ts. The cycle:_helpers.tsline 30 importsparseSensorML30fromparser.tsto support recursive component parsing. Node.js ESM handles this at runtime (deferred binding), but it's a design smell. Recommendation: Use a callback injection pattern (like SWE Common'sComponentParser) instead of a direct circular import. - [POSITIVE] Clean type-discriminator dispatch (
switch (json.type)).
| Aspect | Assessment |
|---|---|
| Purpose | Shared internal parsing helpers consolidating previously-duplicated code (Issue #54) |
| Imports | Types from types.js, SensorMLParseError from errors.js, parseSensorML30 from parser.js — .js extensions ✅ |
| Exports | isRecord, optionalString, parseLink, parseIOList, parseSettings, parseFeatureList, parseModes, parseProcessMethod, parseComponentEntry |
| JSDoc | Complete |
Findings:
- [DESIGN] Source of circular import D-2 — line 30:
import { parseSensorML30 } from './parser.js';. Used only inparseComponentEntry(line ~265) for recursive inline‐process parsing. - [DESIGN]
isRecord()is duplicated — identical function exists inswecommon/_helpers.ts. Could be shared at a common level. - [POSITIVE] Consolidation from previously-duplicated private functions (Issue #54) is a clear improvement.
| Aspect | Assessment |
|---|---|
| Purpose | SensorMLParseError class with optional path |
| JSDoc | Complete |
Findings:
- [POSITIVE] Minimal, focused error class. Parallels
SweCommonParseError.
| Aspect | Assessment |
|---|---|
| Purpose | PhysicalSystem + PhysicalComponent parsers, plus parsePosition |
| Imports | Types from types.js, helpers from _helpers.js — .js extensions ✅ |
| Exports | parsePhysicalSystem, parsePhysicalComponent, parsePosition, parseComponentList, parseConnectionList, parseProcessMethod, parseComponentEntry |
| JSDoc | Complete |
| Spec compliance | Tracks AbstractPhysicalProcess properties (attachedTo, localReferenceFrames, localTimeFrames, position) |
Findings:
- [DESIGN] D-3: Duplicated
parseComponentList+parseConnectionList— Both functions are identically implemented in this file (lines 70–143) and inaggregate-process.ts(lines 62–133). They are functionally the same: null check → array check → map withparseComponentEntry/parseConnection. Recommendation: Consolidate into_helpers.ts(whereparseComponentEntryalready lives) and import from both consumers. - [DESIGN] Also duplicates
parseConnection(private, identical logic in both files). - [DESIGN] Spread-then-delete pattern — Lines 621–640 build the result via
{ ...(json as Record<string, unknown>), type: 'PhysicalComponent' as const }then iteratemanagedKeysto delete raw values before re-assigning parsed versions. This intentionally preserves unknown/pass-through properties but can leak unexpected fields into typed results. The pattern is documented and intentional for DescribedObject pass-through. - [INFORMATIONAL]
as unknown as GeoJsonPoint(line 290) andas unknown as Position(line 390) — used for validated pass-through of GeoJSON structures; safe given preceding validation.
| Aspect | Assessment |
|---|---|
| Purpose | SimpleProcess parser |
| Imports | Types + helpers — .js extensions ✅ |
| Exports | parseSimpleProcess |
| JSDoc | Complete |
Findings:
- [DESIGN] Same spread-then-delete pattern as physical-system.ts — consistent but carries same property-leak risk.
- [INFORMATIONAL] Smallest sub-parser. No
components/connections.
| Aspect | Assessment |
|---|---|
| Purpose | AggregateProcess parser |
| Imports | Types + helpers — .js extensions ✅ |
| Exports | parseAggregateProcess, parseComponentList, parseConnectionList, parseComponentEntry, SensorMLParseError |
| JSDoc | Complete |
Findings:
- [DESIGN] Source of duplication D-3 —
parseComponentListandparseConnectionListduplicated here fromphysical-system.ts. - [DESIGN] Same spread-then-delete pattern.
| Aspect | Assessment |
|---|---|
| Purpose | Barrel re-export for SWE Common parsers + types |
| Exports | Values + types from parser, components, data-array, data-record, helpers, types |
| JSDoc | Module-level |
Findings:
- [POSITIVE] Clean barrel with correct
export typeusage.
| Aspect | Assessment |
|---|---|
| Purpose | Complete SWE Common 3.0 type hierarchy |
| Imports | None (leaf type file) |
| Exports | All SWE Common interfaces and types |
| JSDoc | Thorough with spec references |
Findings:
- [POSITIVE] Clean type definitions matching OGC 24-014 schemas.
| Aspect | Assessment |
|---|---|
| Purpose | Shared helpers (isRecord, parseBaseProperties, parseAssociationAttributeGroup) |
| Imports | Type import from types.js ✅ |
| Exports | 3 functions |
| JSDoc | Complete |
Findings:
- [DESIGN]
isRecord()duplicated fromsensorml/_helpers.ts— see D-4.
| Aspect | Assessment |
|---|---|
| Purpose | Main SWE Common parser: type discrimination, Vector, Matrix, DataChoice, Geometry, validation |
| Imports | Types from types.js, values from components.js, data-record.js, data-array.js, _helpers.js — .js extensions ✅ |
| Exports | parseSWEComponent, parseVector, parseMatrix, parseDataChoice, parseGeometry, detectEncoding, validateAgainstSchema, ValidationResult, ValidationError |
| JSDoc | Exceptional — @module with entry-point list, every function fully documented |
Findings:
- [DESIGN] D-5:
SIMPLE_COMPONENT_TYPESduplicated 3 times — Identicalnew Set([...])inparser.ts(line 99),data-record.ts(line 66),data-array.ts(line 66). Should be a shared constant in_helpers.ts. - [DESIGN] D-6:
isLinkReferenceduplicated 3 times — Identical function inparser.ts(line 129),data-record.ts(line 83),data-array.ts(line 83). Should be consolidated. - [INFORMATIONAL] This pattern of duplication was used to avoid circular imports —
data-record.tsanddata-array.tsuse aComponentParsercallback injection instead of importingparseSWEComponentdirectly, which is the correct approach that avoids the circular issue the SensorML module has. - [POSITIVE]
ComponentParsercallback injection pattern indata-record.ts/data-array.tsavoids circular imports — better than the SensorML approach.
| Aspect | Assessment |
|---|---|
| Purpose | All 10 simple component parsers (6 scalar + 4 range) |
| Imports | Types from types.js, isRecord from _helpers.js — .js extensions ✅ |
| Exports | parseSimpleComponent (discriminator), parseQuantity, parseCount, parseBoolean, parseText, parseTime, parseCategory, plus range variants, parseUnitOfMeasure, SweCommonParseError |
| JSDoc | Complete |
Findings:
- [POSITIVE]
SweCommonParseErrorparallelsSensorMLParseErrorwith samepathpattern. - [POSITIVE] Thorough constraint parsing (AllowedValues, AllowedTokens, AllowedTimes).
| Aspect | Assessment |
|---|---|
| Purpose | DataArray parser with encoding support (JSON, Text, Binary, XML) |
| Imports | Types, components, data-record, _helpers — .js extensions ✅ |
| Exports | parseDataArray, parseEncoding |
| JSDoc | Complete with example |
Findings:
- [DESIGN] Contains duplicated
SIMPLE_COMPONENT_TYPESandisLinkReference— see D-5, D-6. - [POSITIVE] Supports all 4 encoding types per OGC 24-014.
| Aspect | Assessment |
|---|---|
| Purpose | DataRecord parser with recursive field support |
| Imports | Types, components, _helpers — .js extensions ✅ |
| Exports | parseDataRecord, ComponentParser type |
| JSDoc | Complete with nested example |
Findings:
- [DESIGN] Contains duplicated
SIMPLE_COMPONENT_TYPESandisLinkReference— see D-5, D-6. - [POSITIVE]
ComponentParsercallback type is clean — breaks potential circular import.
Findings:
- [POSITIVE] Adds
hasConnectedSystemsgetter andcsapiCollectionsgetter — minimal upstream touch.
Findings:
- [POSITIVE]
checkHasConnectedSystemschecks conformance for Part 1 Core or Part 2 Dynamic Data URIs. - [POSITIVE]
parseCollectionsusesogc-cs:link prefix to sethasConnectedSystemsflag.
Findings:
- [POSITIVE] Adds 5 CSAPI MIME type detectors (sml+json, swe+json, swe+text, swe+csv, swe+binary).
Findings:
- [POSITIVE] Does NOT re-export CSAPI — correct, because CSAPI uses a separate
./csapisub-path export.
Findings:
- [POSITIVE]
"./csapi"sub-path export configured withtypes,import,browser,defaultentries. - [POSITIVE]
"sideEffects": falseenables tree-shaking. - [INFORMATIONAL] The sub-path export correctly points to
dist/outputs, matching the build pipeline.
- All relative imports use
.jsextensions — verified by regex search across all files. 0 violations. import typecorrectly used for all type-only imports throughout the module. 0 violations.- Three-tier dependency hierarchy holds: CSAPI imports from
shared/andogc-api/, never the reverse direction.
| Location | Cast | Justification | Risk |
|---|---|---|---|
factory.ts:46 |
as any |
Access private OgcApiEndpoint members | High — tracked Issue #122 |
factory.ts:57 |
as unknown as OgcApiCollectionInfo |
Double cast on collection doc | Medium — compounds above |
geojson.ts:492 |
as unknown[] |
Safe array widening | None |
physical-system.ts:290 |
as unknown as GeoJsonPoint |
Validated GeoJSON pass-through | Low |
physical-system.ts:390 |
as unknown as Position |
Validated position pass-through | Low |
aggregate-process.ts:233 |
as unknown as Record<string,unknown> |
Delete during spread-then-delete | Low (pattern) |
| All SensorML sub-parsers | as Record<string, unknown> |
Spread-then-delete pattern | Low (intentional) |
_helpers.ts:276 |
as unknown as ComponentEntry |
Unrecognized component pass-through | Low |
All as any casts in .spec.ts files are test-only and acceptable for testing boundary conditions.
| Cycle | Files | Mechanism |
|---|---|---|
| SensorML | parser.ts → sub-parsers → _helpers.ts → parser.ts |
Direct import of parseSensorML30 |
| SWE Common | ✅ None — uses ComponentParser callback injection |
Clean architecture |
| ID | File | Description |
|---|---|---|
| B-1 | factory.ts:46,57 |
as any + double cast accessing private OgcApiEndpoint members. Tracked by Issue #122. |
| ID | File | Description |
|---|---|---|
| G-1 | formats/property.ts |
Parser untested against live server data (no server returns Property) |
| G-2 | SensorML capability/characteristic/IO parsing | Uses as unknown as pass-through; full parsing deferred to Issues #24–#28 |
| ID | File(s) | Description |
|---|---|---|
| C-1 | url_builder.ts |
getCommandStatus manually builds query string instead of using buildQueryString() |
| C-2 | formats/part2.ts |
Time field parsing asymmetry: Observation pass-through vs Datastream/ControlStream interval parsing |
| C-3 | formats/part2.ts |
parseCommandStatus defaults missing statusCode to 'PENDING'; parseCommand leaves currentStatus undefined |
| C-4 | formats/index.ts |
Some type re-exports on individual lines vs grouped |
| ID | File | Description |
|---|---|---|
| I-1 | index.ts |
~170 exports in barrel — monitor for tree-shaking impact |
| I-2 | url_builder.ts |
2,490 lines / ~80 methods — largest file, but coherent |
| I-3 | model.ts |
CommandStatusCodes includes both full URIs and CURIEs (spec-compliant) |
| I-4 | schema-response.ts |
Clean delegation to SWE Common parsers |
| I-5 | package.json |
Sub-path export correctly configured |
| ID | Scope | Description |
|---|---|---|
| P-1 | All files | Zero .js extension violations — every relative import uses .js ✅ |
| P-2 | All files | Correct import type usage throughout ✅ |
| P-3 | All files | Three-tier hierarchy (csapi → ogc-api → shared) never violated ✅ |
| P-4 | All files | Exceptional JSDoc quality — @param, @returns, @throws, @example, @see on nearly every function |
| P-5 | Barrel files | Correct export type for all type-only re-exports |
| P-6 | helpers.ts |
scanCsapiLinks normalizes featuresOfInterest → samplingFeatures alias |
| P-7 | geojson.ts |
Classification priority (SOSA→SSN→SensorML), @link parsing, OSH type fallback |
| P-8 | part2.ts |
normalizeObservedProperties handles both object and string array forms |
| P-9 | SWE Common | ComponentParser callback injection avoids circular imports |
| P-10 | sensorml/types.ts |
Clean discriminated union + SENSORML_PROCESS_TYPES const tuple |
| P-11 | factory.ts |
Clear comment documenting planned as any removal timeline |
| P-12 | package.json |
sideEffects: false + correct sub-path export |
| Metric | Value |
|---|---|
| Total production source files audited | 28 |
| Total production lines (approx.) | ~11,200 |
| Files with complete JSDoc | 28/28 (100%) |
.js extension violations |
0 |
import type violations |
0 |
| Three-tier hierarchy violations | 0 |
as any in production code |
1 (factory.ts) |
| Circular imports | 1 (SensorML) |
| Duplicated function groups | 3 (components/connections, SIMPLE_COMPONENT_TYPES, isLinkReference) |
- Resolve factory.ts
as any(B-1) — Depends on Issue #122 makingroot/getCollectionDocumentpublic. Once resolved, remove both casts.
- Consolidate
parseComponentList/parseConnectionList/parseConnection(D-3) — Move tosensorml/_helpers.tsand import from bothphysical-system.tsandaggregate-process.ts. - Break SensorML circular import (D-2) — Adopt the
ComponentParsercallback injection pattern that SWE Common already uses. PassparseSensorML30as a callback toparseComponentEntryrather than importing directly. - Resolve
SystemTypeUrisname collision (D-1) — Either rename one or consolidate into a single definition with both CURIE and full URI forms.
- Consolidate SWE Common duplicates (D-5, D-6) — Move
SIMPLE_COMPONENT_TYPESandisLinkReferencetoswecommon/_helpers.ts. - Share
isRecord()(D-4) — Create a common utility or have one module re-export from the other. - Standardize
getCommandStatusquery building (C-1) — Refactor to usebuildQueryString()like other methods. - Complete SensorML capability/characteristic/IO parsing (G-2) — Issues #24–#28.