Skip to content

Implement doap exporter for software metadata - #4

Open
mmaelicke wants to merge 1 commit into
mainfrom
feat-doap-exporter-aEBzp
Open

Implement doap exporter for software metadata#4
mmaelicke wants to merge 1 commit into
mainfrom
feat-doap-exporter-aEBzp

Conversation

@mmaelicke

@mmaelicke mmaelicke commented Nov 21, 2025

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

Release Notes

  • New Features
    • Added DOAP (Description of a Project) as a new export format for RDF-based project metadata.
    • Choose between Turtle and RDF/XML serialization formats for DOAP exports.
    • Configure maintainer information directly in the export settings.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Nov 21, 2025

Copy link
Copy Markdown

Walkthrough

These changes introduce DOAP (Description of a Project) RDF export functionality to the application. They add a new exporter class supporting Turtle and RDF/XML serialization formats, integrate it into the export registry, extend the unified metadata type with DOAP configuration, and add UI controls for maintainer and format selection in the Svelte route component.

Changes

Cohort / File(s) Summary
Dependency Management
package.json
Added runtime dependency n3 (^1.21.0) for RDF handling.
DOAP Exporter Implementation
src/lib/exporters/doap-exporter.ts
New exporter module with DoapConfig interface and DoapExporter class. Implements RDF triple generation for project metadata (name, description, maintainer, homepage, license, repository, etc.), serialization to Turtle or RDF/XML, license-to-SPDX normalization, URI generation, and maintainer resolution via fallback chain (config → repo owner → first author). Includes validation, download with format-appropriate extension, and XML/QName escaping utilities.
Export System Integration
src/lib/exporters/export-registry.ts
Registered new DOAP export format (id: 'doap') with DoapExporter instance in the exportFormats registry.
Metadata Type Extension
src/lib/unified-metadata.ts
Added optional doapConfig field to UnifiedSoftwareMetadata with computed maintainer (resolved from repo owner or first author). Initialized in createUnifiedMetadata alongside existing galaxyConfig.
UI & Export Flow
src/routes/+page.svelte
Added type imports for Author and DoapConfig; introduced UI state for DOAP maintainer details and output format selection. Extended export logic to construct and pass doapConfig when format is 'doap'. Added DOAP input group in export panel with maintainer fields (name, givenNames, familyNames, email, orcid) and format selector (Turtle/RDF/XML). Updated export/download and preview flows to include DOAP configuration.

Sequence Diagram

sequenceDiagram
    participant User
    participant UI as Svelte Component
    participant Metadata as Unified Metadata
    participant Exporter as DOAP Exporter
    participant RDF as RDF Serializer

    User->>UI: Select DOAP format & configure maintainer
    UI->>Metadata: Read doapConfig with resolved maintainer
    User->>UI: Click Export
    UI->>Exporter: export(data, doapConfig)
    Exporter->>Exporter: Validate metadata & maintainer
    Exporter->>Exporter: Build RDF triples<br/>(project, metadata fields)
    Exporter->>Exporter: Normalize licenses to SPDX
    Exporter->>Exporter: Generate URIs & person triples
    alt Format = Turtle
        Exporter->>RDF: serializeToTurtle(triples)
        RDF->>Exporter: Turtle string
    else Format = RDF/XML
        Exporter->>RDF: serializeToRdfXml(triples)
        RDF->>Exporter: RDF/XML string
    end
    Exporter->>UI: Return serialized string
    UI->>UI: Trigger download with<br/>extension (.ttl or .rdf)
    UI->>User: File downloaded
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Areas requiring extra attention:

  • RDF serialization logic (doap-exporter.ts): Verify correctness of triple generation, URI formatting, and QName handling in RDF/XML output; validate prefix usage and XML escaping.
  • License normalization (convertLicenseToSpdxUri): Confirm SPDX URI mapping is accurate and handles edge cases (multiple licenses, unknown licenses).
  • Maintainer resolution (resolveMaintainer): Review fallback chain logic and ensure consistent behavior with metadata types.
  • Svelte state & binding consistency (+page.svelte): Verify doapConfig initialization on analysis completion, form field bindings, and state synchronization during export flow.
  • Integration with export registry & metadata: Confirm no unintended side effects on existing CodeMeta or Galaxy export paths.

Poem

🐰 A new format hops into sight,
DOAP triples gleaming, RDF so bright!
With Turtle and XML in our burrow,
Projects described from today through tomorrow! 🌿

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Implement doap exporter for software metadata' directly and clearly summarizes the main changes—adding a DOAP exporter to handle software metadata export.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-doap-exporter-aEBzp

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
src/lib/unified-metadata.ts (1)

227-241: Consider centralizing maintainer resolution to avoid drift

createUnifiedMetadata now infers doapConfig.maintainer (repo owner → first author), while DoapExporter.resolveMaintainer has its own fallback chain (config → repo owner via fullName → first author). This duplication could diverge over time.

You might extract a shared helper (or rely solely on DoapExporter.resolveMaintainer at export time) so that maintainer resolution rules live in one place.

src/routes/+page.svelte (1)

161-169: Handle “empty maintainer” so fallback behavior matches the UI text

The DOAP branch builds:

  • doapConfig.maintainer = doapMaintainer || undefined
  • doapMaintainer is updated via { ...(doapMaintainer || {}), field: value }

This means that after the user edits and then clears all maintainer fields, doapMaintainer becomes {} (truthy). The exporter then treats this as an explicit maintainer, producing a FOAF person with essentially no data (falling back to "unknown"), instead of using the repository owner or first author as promised by the UI text (“will be automatically resolved … if not specified”).

Consider normalizing doapMaintainer so that an object with no non-empty fields is treated as null/undefined, e.g.:

- const doapConfig: DoapConfig = {
-   maintainer: doapMaintainer || undefined,
-   format: doapOutputFormat
- };
+ const effectiveMaintainer =
+   doapMaintainer &&
+   (doapMaintainer.name ||
+    doapMaintainer.givenNames ||
+    doapMaintainer.familyNames ||
+    doapMaintainer.email ||
+    doapMaintainer.orcid)
+     ? doapMaintainer
+     : undefined;
+
+ const doapConfig: DoapConfig = {
+   maintainer: effectiveMaintainer,
+   format: doapOutputFormat
+ };

and reuse the same logic in getCurrentExportData. Alternatively, adjust the oninput handlers to set doapMaintainer back to null when all fields are emptied.

Also applies to: 177-204, 592-672

src/lib/exporters/doap-exporter.ts (1)

428-516: Turtle/RDF‑XML serializers are fine, but consider future deduplication

The Turtle and RDF/XML serializers both group triples by subject and then format predicates/objects with proper prefixes/escaping. The logic is clear and should be easy to extend if you add more DOAP/FOAF fields later. There's some duplicated “group by subject” code between the two serializers, but that’s mostly cosmetic.

If you end up extending this exporter further, you could factor the grouping into a small shared helper to avoid repeating the Map-building loop.

Also applies to: 521-571, 575-582

package.json (1)

29-30: Remove unused n3 dependency from package.json

Verification confirms n3 is not referenced anywhere in the codebase. Either integrate it into the DOAP exporter or remove it to keep dependencies lean.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ef6109 and e0ba20e.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • package.json (1 hunks)
  • src/lib/exporters/doap-exporter.ts (1 hunks)
  • src/lib/exporters/export-registry.ts (2 hunks)
  • src/lib/unified-metadata.ts (2 hunks)
  • src/routes/+page.svelte (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/lib/exporters/export-registry.ts (1)
src/lib/exporters/doap-exporter.ts (1)
  • DoapExporter (11-633)
src/lib/exporters/doap-exporter.ts (1)
src/lib/unified-metadata.ts (2)
  • Author (7-14)
  • UnifiedSoftwareMetadata (91-129)
🔇 Additional comments (7)
src/lib/exporters/export-registry.ts (1)

5-30: DOAP exporter is correctly integrated into the registry

The new DoapExporter import and exportFormats entry look consistent (id matches exporter format, description/icon are clear). No issues with the existing helper functions.

src/lib/unified-metadata.ts (1)

124-129: Unified metadata extension for DOAP config is sound

Adding an optional doapConfig with maintainer?: Author cleanly extends the unified model without breaking existing callers, and fits the new exporter’s needs.

src/routes/+page.svelte (2)

6-8: Type imports for DOAP are appropriate

Importing Author from unified metadata and DoapConfig from the exporter aligns the UI with the underlying types; no issues here.


41-44: DOAP state and initialization logic are consistent with unified metadata

The doapMaintainer and doapOutputFormat state plus the completion handler’s initialization (doapConfig → repo owner from fullName → first author) provide sensible defaults and mirror the backend inference strategy.

Also applies to: 67-81

src/lib/exporters/doap-exporter.ts (3)

6-107: Core DOAP triple construction looks solid

The DoapConfig shape and export method cover the expected DOAP fields: project type, name/description/shortdesc, maintainer (with fallback via resolveMaintainer), homepage, license (normalized to SPDX URIs), language, keywords, repository info, developers, and release metadata. The structure matches common DOAP/FOAF patterns and should interoperate well with RDF consumers.


229-327: Maintainer resolution and FOAF person modeling are reasonable

resolveMaintainer’s priority (config → repository owner from fullName → first author) is a pragmatic chain, and addPersonTriples correctly populates FOAF Person nodes with name, given/family names, mbox, and ORCID-based account links when available.


332-366: License normalization and URI helpers are pragmatic and safe

convertLicenseToSpdxUri’s normalization plus common-license map is a good compromise: well-known IDs get canonicalized, and unknown strings still become SPDX URIs under the namespace. The project/person/repo/release URI generators produce stable identifiers even without repo URLs, which is helpful for offline use.

Also applies to: 371-423

Comment on lines +584 to +603
validate(data: UnifiedSoftwareMetadata, doapConfig?: DoapConfig): string[] {
const errors = super.validate(data);

// DOAP specific validations
const maintainer = this.resolveMaintainer(data, doapConfig);
if (!maintainer) {
errors.push('Maintainer is required for DOAP (could not resolve from repository owner or authors)');
}

// Validate URIs if present
if (data.citation.url && !this.isValidUri(data.citation.url)) {
errors.push('Invalid URL in citation');
}

if (data.repository.htmlUrl && !this.isValidUri(data.repository.htmlUrl)) {
errors.push('Invalid repository URL');
}

return errors;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Align MIME type with selected output format for downloads

mimeType is fixed as 'application/rdf+xml', while export defaults to Turtle and download chooses the extension based on doapConfig.format (ttl vs rdf). For Turtle downloads this yields a .ttl file with an RDF/XML content type, which may confuse some tools.

You can compute the MIME type per call while keeping the class default as-is, for example:

download(data: UnifiedSoftwareMetadata, filename?: string, doapConfig?: DoapConfig): void {
-  const content = this.export(data, doapConfig);
-  const blob = new Blob([content], { type: this.mimeType });
+  const content = this.export(data, doapConfig);
+  const isTurtle = (doapConfig?.format || 'turtle') === 'turtle';
+  const mimeType = isTurtle ? 'text/turtle' : this.mimeType;
+  const blob = new Blob([content], { type: mimeType });
   const url = URL.createObjectURL(blob);
   const link = document.createElement('a');
   link.href = url;
-  const ext = doapConfig?.format === 'turtle' ? 'ttl' : 'rdf';
+  const ext = isTurtle ? 'ttl' : 'rdf';
   link.download = filename || `${data.name.replace(/[^a-zA-Z0-9]/g, '_')}.${ext}`;
   ...
}

This keeps RDF/XML behavior unchanged while making Turtle downloads more self-describing.

Also applies to: 620-627

🤖 Prompt for AI Agents
In src/lib/exporters/doap-exporter.ts around lines 584-603 (and also apply same
change at 620-627), the MIME type is hardcoded to 'application/rdf+xml' which
mismatches when format is Turtle; compute the mimeType per call using the
selected doapConfig.format (if format === 'ttl' or 'turtle' use 'text/turtle',
otherwise use 'application/rdf+xml'), and use that computed mimeType for the
download/response so the file extension and Content-Type align with the chosen
output format.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant