diff --git a/src/feeds/atom/parse/index.test.ts b/src/feeds/atom/parse/index.test.ts index c767fc4..392aa24 100644 --- a/src/feeds/atom/parse/index.test.ts +++ b/src/feeds/atom/parse/index.test.ts @@ -393,6 +393,7 @@ describe('parse', () => { updated: '2024-01-01T00:00:00Z', dc: { creator: 'John Doe', + creators: ['John Doe'], }, }, ], @@ -433,7 +434,9 @@ describe('parse', () => { updated: '2024-01-01T00:00:00Z', dc: { creator: 'John Doe', + creators: ['John Doe'], date: '2023-01-01', + dates: ['2023-01-01'], }, }, { @@ -473,6 +476,7 @@ describe('parse', () => { updated: '2024-01-01T00:00:00Z', dc: { creator: 'John Doe', + creators: ['John Doe'], }, }, ], @@ -565,7 +569,9 @@ describe('parse', () => { updated: '2024-01-01T00:00:00Z', dc: { creator: 'John Doe', + creators: ['John Doe'], date: '2023-01-01', + dates: ['2023-01-01'], }, media: { title: { value: 'Media Title' }, @@ -615,6 +621,7 @@ describe('parse', () => { updated: '2024-01-01T00:00:00Z', dc: { creator: 'Should not normalize (empty URI)', + creators: ['Should not normalize (empty URI)'], }, }, ], @@ -668,6 +675,7 @@ describe('parse', () => { title: 'Incomplete Entry', dc: { creator: 'John Doe', + creators: ['John Doe'], }, }, ], @@ -737,6 +745,7 @@ describe('parse', () => { updated: '2024-01-01T00:00:00Z', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -771,6 +780,7 @@ describe('parse', () => { updated: '2024-01-01T00:00:00Z', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -805,6 +815,7 @@ describe('parse', () => { updated: '2024-01-01T00:00:00Z', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -839,6 +850,7 @@ describe('parse', () => { updated: '2024-01-01T00:00:00Z', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -873,6 +885,7 @@ describe('parse', () => { updated: '2024-01-01T00:00:00Z', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -907,6 +920,7 @@ describe('parse', () => { updated: '2024-01-01T00:00:00Z', dc: { creator: 'John', + creators: ['John'], }, }, ], diff --git a/src/feeds/atom/parse/utils.test.ts b/src/feeds/atom/parse/utils.test.ts index 0e79d02..6e38202 100644 --- a/src/feeds/atom/parse/utils.test.ts +++ b/src/feeds/atom/parse/utils.test.ts @@ -992,7 +992,10 @@ describe('parseEntry', () => { const expected = { id: 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a', title: 'Example Entry', - dc: { creator: 'John Doe' }, + dc: { + creator: 'John Doe', + creators: ['John Doe'], + }, } expect(parseEntry(value)).toEqual(expected) @@ -1493,7 +1496,10 @@ describe('parseFeed', () => { const expected = { id: 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a', title: 'Example Feed', - dc: { creator: 'John Doe' }, + dc: { + creator: 'John Doe', + creators: ['John Doe'], + }, } expect(parseFeed(value)).toEqual(expected) diff --git a/src/feeds/atom/references/atom-ns.json b/src/feeds/atom/references/atom-ns.json index ac235cc..7b9b8de 100644 --- a/src/feeds/atom/references/atom-ns.json +++ b/src/feeds/atom/references/atom-ns.json @@ -6,13 +6,27 @@ "id": "example-entry", "title": "Example Entry", "dc": { - "creator": "Jack Jackson", - "contributor": "Assistant Editor Mike Thompson", - "date": "2022-01-01T12:00:00.000Z", - "description": "Detailed description of the example entry content", + "titles": ["Dublin Core Enhanced Entry Title"], + "creators": ["Jack Jackson"], + "subjects": ["Article, Tutorial, Example"], + "descriptions": ["Detailed description of the example entry content"], + "publishers": ["Example News Organization"], + "contributors": ["Assistant Editor Mike Thompson"], + "dates": ["2022-01-01T12:00:00.000Z"], + "types": ["Article"], + "formats": ["application/xhtml+xml"], + "identifiers": ["urn:uuid:98765432-9876-9876-9876-987654321def"], + "sources": ["https://example.org/entry-source"], + "languages": ["en-US"], + "relations": ["https://example.org/related-entry"], + "coverages": ["United States"], "title": "Dublin Core Enhanced Entry Title", + "creator": "Jack Jackson", "subject": "Article, Tutorial, Example", + "description": "Detailed description of the example entry content", "publisher": "Example News Organization", + "contributor": "Assistant Editor Mike Thompson", + "date": "2022-01-01T12:00:00.000Z", "type": "Article", "format": "application/xhtml+xml", "identifier": "urn:uuid:98765432-9876-9876-9876-987654321def", @@ -695,13 +709,27 @@ } ], "dc": { - "creator": "John Doe", - "contributor": "Jane Smith", - "date": "2022-01-01T12:00:00.000Z", - "description": "This is an example of description.", + "titles": ["Dublin Core Enhanced Feed Title"], + "creators": ["John Doe"], + "subjects": ["Technology, Programming, Web Development"], + "descriptions": ["This is an example of description."], + "publishers": ["Example Publishing Company"], + "contributors": ["Jane Smith"], + "dates": ["2022-01-01T12:00:00.000Z"], + "types": ["Text"], + "formats": ["application/atom+xml"], + "identifiers": ["urn:uuid:12345678-1234-1234-1234-123456789abc"], + "sources": ["https://example.org/original-source"], + "languages": ["en-US"], + "relations": ["https://example.org/related-content"], + "coverages": ["Global"], "title": "Dublin Core Enhanced Feed Title", + "creator": "John Doe", "subject": "Technology, Programming, Web Development", + "description": "This is an example of description.", "publisher": "Example Publishing Company", + "contributor": "Jane Smith", + "date": "2022-01-01T12:00:00.000Z", "type": "Text", "format": "application/atom+xml", "identifier": "urn:uuid:12345678-1234-1234-1234-123456789abc", diff --git a/src/feeds/rdf/parse/index.test.ts b/src/feeds/rdf/parse/index.test.ts index bc4dee5..7700b20 100644 --- a/src/feeds/rdf/parse/index.test.ts +++ b/src/feeds/rdf/parse/index.test.ts @@ -278,6 +278,7 @@ describe('parse', () => { description: 'Item Description', dc: { creator: 'John Doe', + creators: ['John Doe'], }, }, ], @@ -320,7 +321,9 @@ describe('parse', () => { description: 'Item Description', dc: { creator: 'John Doe', + creators: ['John Doe'], date: '2023-01-01', + dates: ['2023-01-01'], }, }, { @@ -362,6 +365,7 @@ describe('parse', () => { description: 'Item Description', dc: { creator: 'John Doe', + creators: ['John Doe'], }, }, ], @@ -453,6 +457,7 @@ describe('parse', () => { description: 'RDF Feed Description', dc: { creator: 'Feed Author', + creators: ['Feed Author'], }, sy: { updatePeriod: 'hourly', @@ -464,7 +469,9 @@ describe('parse', () => { description: 'Item Description', dc: { creator: 'John Doe', + creators: ['John Doe'], date: '2023-01-01', + dates: ['2023-01-01'], }, slash: { comments: 42, @@ -506,6 +513,7 @@ describe('parse', () => { title: 'Item Title', dc: { creator: 'Should not normalize (empty URI)', + creators: ['Should not normalize (empty URI)'], }, }, ], @@ -565,12 +573,14 @@ describe('parse', () => { const expected = { dc: { creator: 'Channel Author', + creators: ['Channel Author'], }, items: [ { title: 'Item without about', dc: { creator: 'Item Author', + creators: ['Item Author'], }, }, ], @@ -642,6 +652,7 @@ describe('parse', () => { title: 'Item', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -678,6 +689,7 @@ describe('parse', () => { title: 'Item', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -714,6 +726,7 @@ describe('parse', () => { title: 'Item', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -750,6 +763,7 @@ describe('parse', () => { title: 'Item', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -786,6 +800,7 @@ describe('parse', () => { title: 'Item', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -822,6 +837,7 @@ describe('parse', () => { title: 'Item', dc: { creator: 'John', + creators: ['John'], }, }, ], diff --git a/src/feeds/rdf/parse/utils.test.ts b/src/feeds/rdf/parse/utils.test.ts index be7e84b..9f340cd 100644 --- a/src/feeds/rdf/parse/utils.test.ts +++ b/src/feeds/rdf/parse/utils.test.ts @@ -411,7 +411,10 @@ describe('parseItem', () => { const expected = { title: 'Example Entry', link: 'http://example.com', - dc: { creator: 'John Doe' }, + dc: { + creator: 'John Doe', + creators: ['John Doe'], + }, } expect(parseItem(value)).toEqual(expected) @@ -960,7 +963,10 @@ describe('parseFeed', () => { link: 'https://example.com/item1', }, ], - dc: { creator: 'John Doe' }, + dc: { + creator: 'John Doe', + creators: ['John Doe'], + }, } expect(parseFeed(value)).toEqual(expected) diff --git a/src/feeds/rdf/references/rdf-ns.json b/src/feeds/rdf/references/rdf-ns.json index f18f7e5..1f1b7b4 100644 --- a/src/feeds/rdf/references/rdf-ns.json +++ b/src/feeds/rdf/references/rdf-ns.json @@ -9,13 +9,27 @@ "encoded": "This is an example of content." }, "dc": { - "creator": "Jack Jackson", - "contributor": "Assistant Editor Mike Thompson", - "date": "2022-01-01T12:00+00:00", - "description": "This article explores advanced concepts in technology", + "titles": ["Dublin Core Enhanced Item Title"], + "creators": ["Jack Jackson"], + "subjects": ["Article, Tutorial, Example"], + "descriptions": ["This article explores advanced concepts in technology"], + "publishers": ["Example News Organization"], + "contributors": ["Assistant Editor Mike Thompson"], + "dates": ["2022-01-01T12:00+00:00"], + "types": ["Article"], + "formats": ["text/html"], + "identifiers": ["urn:uuid:item-98765432-9876-9876-9876-987654321def"], + "sources": ["https://example.org/item-source"], + "languages": ["en-US"], + "relations": ["https://example.org/related-article"], + "coverages": ["United States"], "title": "Dublin Core Enhanced Item Title", + "creator": "Jack Jackson", "subject": "Article, Tutorial, Example", + "description": "This article explores advanced concepts in technology", "publisher": "Example News Organization", + "contributor": "Assistant Editor Mike Thompson", + "date": "2022-01-01T12:00+00:00", "type": "Article", "format": "text/html", "identifier": "urn:uuid:item-98765432-9876-9876-9876-987654321def", @@ -623,13 +637,27 @@ } ], "dc": { - "creator": "John Doe", - "contributor": "Jane Smith", - "date": "2022-01-01T12:00+00:00", - "description": "This is an example of description.", + "titles": ["Dublin Core Enhanced Feed Title"], + "creators": ["John Doe"], + "subjects": ["Technology, Programming, Web Development"], + "descriptions": ["This is an example of description."], + "publishers": ["Example Publishing Company"], + "contributors": ["Jane Smith"], + "dates": ["2022-01-01T12:00+00:00"], + "types": ["Text"], + "formats": ["application/rdf+xml"], + "identifiers": ["urn:uuid:12345678-1234-1234-1234-123456789abc"], + "sources": ["https://example.org/original-source"], + "languages": ["en-US"], + "relations": ["https://example.org/related-content"], + "coverages": ["Global"], "title": "Dublin Core Enhanced Feed Title", + "creator": "John Doe", "subject": "Technology, Programming, Web Development", + "description": "This is an example of description.", "publisher": "Example Publishing Company", + "contributor": "Jane Smith", + "date": "2022-01-01T12:00+00:00", "type": "Text", "format": "application/rdf+xml", "identifier": "urn:uuid:12345678-1234-1234-1234-123456789abc", diff --git a/src/feeds/rss/parse/index.test.ts b/src/feeds/rss/parse/index.test.ts index e18ab84..8f1bc09 100644 --- a/src/feeds/rss/parse/index.test.ts +++ b/src/feeds/rss/parse/index.test.ts @@ -288,6 +288,7 @@ describe('parse', () => { description: 'Item Description', dc: { creator: 'John Doe', + creators: ['John Doe'], }, }, ], @@ -330,7 +331,9 @@ describe('parse', () => { description: 'Item Description', dc: { creator: 'John Doe', + creators: ['John Doe'], date: '2023-01-01', + dates: ['2023-01-01'], }, }, { @@ -372,6 +375,7 @@ describe('parse', () => { description: 'Item Description', dc: { creator: 'John Doe', + creators: ['John Doe'], }, }, ], @@ -466,7 +470,9 @@ describe('parse', () => { description: 'Item Description', dc: { creator: 'John Doe', + creators: ['John Doe'], date: '2023-01-01', + dates: ['2023-01-01'], }, media: { title: { @@ -513,6 +519,7 @@ describe('parse', () => { title: 'Item Title', dc: { creator: 'Should not be normalized (empty URI)', + creators: ['Should not be normalized (empty URI)'], }, }, ], @@ -585,7 +592,9 @@ describe('parse', () => { { dc: { creator: 'John Doe', + creators: ['John Doe'], date: '2023-01-01', + dates: ['2023-01-01'], }, }, ], @@ -619,6 +628,7 @@ describe('parse', () => { title: 'Item', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -651,6 +661,7 @@ describe('parse', () => { title: 'Item', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -683,6 +694,7 @@ describe('parse', () => { title: 'Item', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -715,6 +727,7 @@ describe('parse', () => { title: 'Item', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -747,6 +760,7 @@ describe('parse', () => { title: 'Item', dc: { creator: 'John', + creators: ['John'], }, }, ], @@ -779,6 +793,7 @@ describe('parse', () => { title: 'Item', dc: { creator: 'John', + creators: ['John'], }, }, ], diff --git a/src/feeds/rss/parse/utils.test.ts b/src/feeds/rss/parse/utils.test.ts index e99ecd3..3041a26 100644 --- a/src/feeds/rss/parse/utils.test.ts +++ b/src/feeds/rss/parse/utils.test.ts @@ -811,7 +811,10 @@ describe('parseItem', () => { } const expected = { title: 'Example Entry', - dc: { creator: 'John Doe' }, + dc: { + creator: 'John Doe', + creators: ['John Doe'], + }, } expect(parseItem(value)).toEqual(expected) @@ -1391,7 +1394,10 @@ describe('parseFeed', () => { const expected = { title: 'Feed Title', link: 'https://example.com', - dc: { creator: 'John Doe' }, + dc: { + creator: 'John Doe', + creators: ['John Doe'], + }, } expect(parseFeed(value)).toEqual(expected) diff --git a/src/feeds/rss/references/rss-ns.json b/src/feeds/rss/references/rss-ns.json index 1742723..b818c31 100644 --- a/src/feeds/rss/references/rss-ns.json +++ b/src/feeds/rss/references/rss-ns.json @@ -10,6 +10,20 @@ "encoded": "This is an example of content." }, "dc": { + "titles": ["Dublin Core Enhanced Item Title"], + "creators": ["Jack Jackson"], + "subjects": ["Article, Tutorial, Example"], + "descriptions": ["Detailed description of the example item content"], + "publishers": ["Example News Organization"], + "contributors": ["Assistant Editor Mike Thompson"], + "dates": ["2022-01-01T12:00:00.000Z"], + "types": ["Article"], + "formats": ["text/html"], + "identifiers": ["urn:uuid:98765432-9876-9876-9876-987654321def"], + "sources": ["https://example.org/item-source"], + "languages": ["en-US"], + "relations": ["https://example.org/related-article"], + "coverages": ["United States"], "title": "Dublin Core Enhanced Item Title", "creator": "Jack Jackson", "subject": "Article, Tutorial, Example", @@ -927,6 +941,20 @@ } ], "dc": { + "titles": ["Dublin Core Enhanced Feed Title"], + "creators": ["John Doe"], + "subjects": ["Technology, Programming, Web Development"], + "descriptions": ["This is an example of description."], + "publishers": ["Example Publishing Company"], + "contributors": ["Jane Smith"], + "dates": ["2022-01-01T12:00:00.000Z"], + "types": ["Text"], + "formats": ["application/rss+xml"], + "identifiers": ["urn:uuid:12345678-1234-1234-1234-123456789abc"], + "sources": ["https://example.org/original-source"], + "languages": ["en-US"], + "relations": ["https://example.org/related-content"], + "coverages": ["Global"], "title": "Dublin Core Enhanced Feed Title", "creator": "John Doe", "subject": "Technology, Programming, Web Development", diff --git a/src/namespaces/dc/common/types.ts b/src/namespaces/dc/common/types.ts index 58f300e..63c1e94 100644 --- a/src/namespaces/dc/common/types.ts +++ b/src/namespaces/dc/common/types.ts @@ -3,20 +3,50 @@ import type { DateLike } from '../../../common/types.js' // #region reference export namespace DcNs { export type ItemOrFeed = { + titles?: Array + creators?: Array + subjects?: Array + descriptions?: Array + publishers?: Array + contributors?: Array + dates?: Array + types?: Array + formats?: Array + identifiers?: Array + sources?: Array + languages?: Array + relations?: Array + coverages?: Array + + /** @deprecated Use `titles` (array) instead. Dublin Core fields are repeatable. */ title?: string + /** @deprecated Use `creators` (array) instead. Dublin Core fields are repeatable. */ creator?: string + /** @deprecated Use `subjects` (array) instead. Dublin Core fields are repeatable. */ subject?: string + /** @deprecated Use `descriptions` (array) instead. Dublin Core fields are repeatable. */ description?: string + /** @deprecated Use `publishers` (array) instead. Dublin Core fields are repeatable. */ publisher?: string + /** @deprecated Use `contributors` (array) instead. Dublin Core fields are repeatable. */ contributor?: string + /** @deprecated Use `dates` (array) instead. Dublin Core fields are repeatable. */ date?: TDate + /** @deprecated Use `types` (array) instead. Dublin Core fields are repeatable. */ type?: string + /** @deprecated Use `formats` (array) instead. Dublin Core fields are repeatable. */ format?: string + /** @deprecated Use `identifiers` (array) instead. Dublin Core fields are repeatable. */ identifier?: string + /** @deprecated Use `sources` (array) instead. Dublin Core fields are repeatable. */ source?: string + /** @deprecated Use `languages` (array) instead. Dublin Core fields are repeatable. */ language?: string + /** @deprecated Use `relations` (array) instead. Dublin Core fields are repeatable. */ relation?: string + /** @deprecated Use `coverages` (array) instead. Dublin Core fields are repeatable. */ coverage?: string + /** @deprecated This field type will be changed to array in the next major version of the package. Dublin Core fields are repeatable. */ rights?: string } } diff --git a/src/namespaces/dc/generate/utils.test.ts b/src/namespaces/dc/generate/utils.test.ts index 993b0d1..ae17bdc 100644 --- a/src/namespaces/dc/generate/utils.test.ts +++ b/src/namespaces/dc/generate/utils.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'bun:test' import { generateItemOrFeed } from './utils.js' describe('generateItemOrFeed', () => { - it('should generate valid itemOrFeed object with all properties', () => { + it('should generate valid itemOrFeed object with all singular (deprecated) properties', () => { const value = { title: 'Test Title', creator: 'John Doe', @@ -41,6 +41,95 @@ describe('generateItemOrFeed', () => { expect(generateItemOrFeed(value)).toEqual(expected) }) + it('should generate valid itemOrFeed object with all plural properties (single values)', () => { + const value = { + titles: ['Test Title'], + creators: ['John Doe'], + subjects: ['Technology'], + descriptions: ['A test description'], + publishers: ['Test Publisher'], + contributors: ['Jane Smith'], + dates: [new Date('2023-01-01T00:00:00Z')], + types: ['Text'], + formats: ['text/html'], + identifiers: ['test-id-123'], + sources: ['Test Source'], + languages: ['en-US'], + relations: ['https://example.com/related'], + coverages: ['Global'], + } + const expected = { + 'dc:title': ['Test Title'], + 'dc:creator': ['John Doe'], + 'dc:subject': ['Technology'], + 'dc:description': ['A test description'], + 'dc:publisher': ['Test Publisher'], + 'dc:contributor': ['Jane Smith'], + 'dc:date': ['2023-01-01T00:00:00.000Z'], + 'dc:type': ['Text'], + 'dc:format': ['text/html'], + 'dc:identifier': ['test-id-123'], + 'dc:source': ['Test Source'], + 'dc:language': ['en-US'], + 'dc:relation': ['https://example.com/related'], + 'dc:coverage': ['Global'], + } + + expect(generateItemOrFeed(value)).toEqual(expected) + }) + + it('should generate valid itemOrFeed object with plural properties (multiple values)', () => { + const value = { + titles: ['Test Title', 'Alternative Title'], + creators: ['John Doe', 'Jane Smith'], + subjects: ['Technology', 'Science'], + descriptions: ['A test description', 'Another description'], + publishers: ['Test Publisher', 'Secondary Publisher'], + contributors: ['Alice', 'Bob'], + dates: [new Date('2023-01-01T00:00:00Z'), new Date('2023-06-15T12:00:00Z')], + types: ['Text', 'Article'], + formats: ['text/html', 'application/pdf'], + identifiers: ['test-id-123', 'test-id-456'], + sources: ['Test Source', 'Another Source'], + languages: ['en-US', 'fr-FR'], + relations: ['https://example.com/related', 'https://example.com/also-related'], + coverages: ['Global', 'North America'], + } + const expected = { + 'dc:title': ['Test Title', 'Alternative Title'], + 'dc:creator': ['John Doe', 'Jane Smith'], + 'dc:subject': ['Technology', 'Science'], + 'dc:description': ['A test description', 'Another description'], + 'dc:publisher': ['Test Publisher', 'Secondary Publisher'], + 'dc:contributor': ['Alice', 'Bob'], + 'dc:date': ['2023-01-01T00:00:00.000Z', '2023-06-15T12:00:00.000Z'], + 'dc:type': ['Text', 'Article'], + 'dc:format': ['text/html', 'application/pdf'], + 'dc:identifier': ['test-id-123', 'test-id-456'], + 'dc:source': ['Test Source', 'Another Source'], + 'dc:language': ['en-US', 'fr-FR'], + 'dc:relation': ['https://example.com/related', 'https://example.com/also-related'], + 'dc:coverage': ['Global', 'North America'], + } + + expect(generateItemOrFeed(value)).toEqual(expected) + }) + + it('should prefer plural fields over singular when both are provided', () => { + const value = { + title: 'Singular Title', + titles: ['Plural Title 1', 'Plural Title 2'], + creator: 'Singular Creator', + creators: ['Plural Creator'], + } + const expected = { + 'dc:title': ['Plural Title 1', 'Plural Title 2'], + 'dc:creator': ['Plural Creator'], + } + + expect(generateItemOrFeed(value)).toEqual(expected) + }) + it('should generate itemOrFeed with minimal properties', () => { const value = { title: 'Minimal Title', @@ -68,12 +157,24 @@ describe('generateItemOrFeed', () => { language: undefined, relation: undefined, coverage: undefined, - rights: undefined, } expect(generateItemOrFeed(value)).toBeUndefined() }) + it('should handle empty arrays in plural fields', () => { + const value = { + titles: [], + creators: ['John Doe'], + subjects: [], + } + const expected = { + 'dc:creator': ['John Doe'], + } + + expect(generateItemOrFeed(value)).toEqual(expected) + }) + it('should handle empty object', () => { const value = {} diff --git a/src/namespaces/dc/generate/utils.ts b/src/namespaces/dc/generate/utils.ts index 8703e06..5f43bac 100644 --- a/src/namespaces/dc/generate/utils.ts +++ b/src/namespaces/dc/generate/utils.ts @@ -1,5 +1,6 @@ import type { DateLike, GenerateUtil } from '../../../common/types.js' import { + generateArrayOrSingular, generateCdataString, generateRfc3339Date, isObject, @@ -13,20 +14,64 @@ export const generateItemOrFeed: GenerateUtil> = (item } const value = { - 'dc:title': generateCdataString(itemOrFeed.title), - 'dc:creator': generateCdataString(itemOrFeed.creator), - 'dc:subject': generateCdataString(itemOrFeed.subject), - 'dc:description': generateCdataString(itemOrFeed.description), - 'dc:publisher': generateCdataString(itemOrFeed.publisher), - 'dc:contributor': generateCdataString(itemOrFeed.contributor), - 'dc:date': generateRfc3339Date(itemOrFeed.date), - 'dc:type': generateCdataString(itemOrFeed.type), - 'dc:format': generateCdataString(itemOrFeed.format), - 'dc:identifier': generateCdataString(itemOrFeed.identifier), - 'dc:source': generateCdataString(itemOrFeed.source), - 'dc:language': generateCdataString(itemOrFeed.language), - 'dc:relation': generateCdataString(itemOrFeed.relation), - 'dc:coverage': generateCdataString(itemOrFeed.coverage), + 'dc:title': generateArrayOrSingular(itemOrFeed.titles, itemOrFeed.title, generateCdataString), + 'dc:creator': generateArrayOrSingular( + itemOrFeed.creators, + itemOrFeed.creator, + generateCdataString, + ), + 'dc:subject': generateArrayOrSingular( + itemOrFeed.subjects, + itemOrFeed.subject, + generateCdataString, + ), + 'dc:description': generateArrayOrSingular( + itemOrFeed.descriptions, + itemOrFeed.description, + generateCdataString, + ), + 'dc:publisher': generateArrayOrSingular( + itemOrFeed.publishers, + itemOrFeed.publisher, + generateCdataString, + ), + 'dc:contributor': generateArrayOrSingular( + itemOrFeed.contributors, + itemOrFeed.contributor, + generateCdataString, + ), + 'dc:date': generateArrayOrSingular(itemOrFeed.dates, itemOrFeed.date, generateRfc3339Date), + 'dc:type': generateArrayOrSingular(itemOrFeed.types, itemOrFeed.type, generateCdataString), + 'dc:format': generateArrayOrSingular( + itemOrFeed.formats, + itemOrFeed.format, + generateCdataString, + ), + 'dc:identifier': generateArrayOrSingular( + itemOrFeed.identifiers, + itemOrFeed.identifier, + generateCdataString, + ), + 'dc:source': generateArrayOrSingular( + itemOrFeed.sources, + itemOrFeed.source, + generateCdataString, + ), + 'dc:language': generateArrayOrSingular( + itemOrFeed.languages, + itemOrFeed.language, + generateCdataString, + ), + 'dc:relation': generateArrayOrSingular( + itemOrFeed.relations, + itemOrFeed.relation, + generateCdataString, + ), + 'dc:coverage': generateArrayOrSingular( + itemOrFeed.coverages, + itemOrFeed.coverage, + generateCdataString, + ), 'dc:rights': generateCdataString(itemOrFeed.rights), } diff --git a/src/namespaces/dc/parse/utils.test.ts b/src/namespaces/dc/parse/utils.test.ts index ed0d8eb..b0288f7 100644 --- a/src/namespaces/dc/parse/utils.test.ts +++ b/src/namespaces/dc/parse/utils.test.ts @@ -3,6 +3,20 @@ import { retrieveItemOrFeed } from './utils.js' describe('retrieveItemOrFeed', () => { const expectedFull = { + titles: ['Sample Title'], + creators: ['John Doe'], + subjects: ['Test Subject'], + descriptions: ['This is a description'], + publishers: ['Test Publisher'], + contributors: ['Jane Smith'], + dates: ['2023-05-15T09:30:00Z'], + types: ['Article'], + formats: ['text/html'], + identifiers: ['urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a'], + sources: ['https://example.org/source'], + languages: ['en-US'], + relations: ['https://example.org/related'], + coverages: ['Worldwide'], title: 'Sample Title', creator: 'John Doe', subject: 'Test Subject', @@ -86,7 +100,42 @@ describe('retrieveItemOrFeed', () => { 'dc:rights': ['Copyright 2023, All rights reserved', 'Creative Commons BY-NC-SA 4.0'], } - expect(retrieveItemOrFeed(value)).toEqual(expectedFull) + const expected = { + title: 'Sample Title', + creator: 'John Doe', + subject: 'Test Subject', + description: 'This is a description', + publisher: 'Test Publisher', + contributor: 'Jane Smith', + date: '2023-05-15T09:30:00Z', + type: 'Article', + format: 'text/html', + identifier: 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a', + source: 'https://example.org/source', + language: 'en-US', + relation: 'https://example.org/related', + coverage: 'Worldwide', + titles: ['Sample Title', 'Alternative Title'], + creators: ['John Doe', 'Richard Roe'], + subjects: ['Test Subject', 'Secondary Subject'], + descriptions: ['This is a description', 'This is an alternative description'], + publishers: ['Test Publisher', 'Another Publisher'], + contributors: ['Jane Smith', 'Alice Johnson'], + dates: ['2023-05-15T09:30:00Z', '2023-06-20T14:45:00Z'], + types: ['Article', 'Blog Post'], + formats: ['text/html', 'application/pdf'], + identifiers: [ + 'urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a', + 'urn:uuid:2335d785-dfc9-5fcc-bbbb-90eb455efa7b', + ], + sources: ['https://example.org/source', 'https://example.org/alternate-source'], + languages: ['en-US', 'fr-FR'], + relations: ['https://example.org/related', 'https://example.org/also-related'], + coverages: ['Worldwide', 'North America'], + rights: 'Copyright 2023, All rights reserved', + } + + expect(retrieveItemOrFeed(value)).toEqual(expected) }) it('should handle partial dublincore object with common properties', () => { @@ -99,6 +148,9 @@ describe('retrieveItemOrFeed', () => { title: 'Sample Title', creator: 'John Doe', date: '2023-05-15T09:30:00Z', + titles: ['Sample Title'], + creators: ['John Doe'], + dates: ['2023-05-15T09:30:00Z'], } expect(retrieveItemOrFeed(value)).toEqual(expected) @@ -110,6 +162,7 @@ describe('retrieveItemOrFeed', () => { } const expected = { title: 'Only Title', + titles: ['Only Title'], } expect(retrieveItemOrFeed(value)).toEqual(expected) @@ -124,6 +177,8 @@ describe('retrieveItemOrFeed', () => { const expected = { title: '123', identifier: '456', + titles: ['123'], + identifiers: ['456'], } expect(retrieveItemOrFeed(value)).toEqual(expected) @@ -160,6 +215,8 @@ describe('retrieveItemOrFeed', () => { const expected = { creator: 'John Doe', date: '2023-01-01T12:00:00Z', + creators: ['John Doe'], + dates: ['2023-01-01T12:00:00Z'], } expect(retrieveItemOrFeed(value)).toEqual(expected) @@ -173,6 +230,7 @@ describe('retrieveItemOrFeed', () => { } const expected = { creator: 'John Doe', + creators: ['John Doe'], } expect(retrieveItemOrFeed(value)).toEqual(expected) @@ -186,6 +244,7 @@ describe('retrieveItemOrFeed', () => { } const expected = { creator: 'John Doe', + creators: ['John Doe'], } expect(retrieveItemOrFeed(value)).toEqual(expected) @@ -199,6 +258,8 @@ describe('retrieveItemOrFeed', () => { const expected = { identifier: '12345', language: 'en', + identifiers: ['12345'], + languages: ['en'], } expect(retrieveItemOrFeed(value)).toEqual(expected) diff --git a/src/namespaces/dc/parse/utils.ts b/src/namespaces/dc/parse/utils.ts index 079144a..7713834 100644 --- a/src/namespaces/dc/parse/utils.ts +++ b/src/namespaces/dc/parse/utils.ts @@ -1,6 +1,7 @@ import type { ParsePartialUtil } from '../../../common/types.js' import { isObject, + parseArrayOf, parseDate, parseSingularOf, parseString, @@ -15,6 +16,26 @@ export const retrieveItemOrFeed: ParsePartialUtil> = (va } const itemOrFeed = { + titles: parseArrayOf(value['dc:title'], (value) => parseString(retrieveText(value))), + creators: parseArrayOf(value['dc:creator'], (value) => parseString(retrieveText(value))), + subjects: parseArrayOf(value['dc:subject'], (value) => parseString(retrieveText(value))), + descriptions: parseArrayOf(value['dc:description'], (value) => + parseString(retrieveText(value)), + ), + publishers: parseArrayOf(value['dc:publisher'], (value) => parseString(retrieveText(value))), + contributors: parseArrayOf(value['dc:contributor'], (value) => + parseString(retrieveText(value)), + ), + dates: parseArrayOf(value['dc:date'], (value) => parseDate(retrieveText(value))), + types: parseArrayOf(value['dc:type'], (value) => parseString(retrieveText(value))), + formats: parseArrayOf(value['dc:format'], (value) => parseString(retrieveText(value))), + identifiers: parseArrayOf(value['dc:identifier'], (value) => parseString(retrieveText(value))), + sources: parseArrayOf(value['dc:source'], (value) => parseString(retrieveText(value))), + languages: parseArrayOf(value['dc:language'], (value) => parseString(retrieveText(value))), + relations: parseArrayOf(value['dc:relation'], (value) => parseString(retrieveText(value))), + coverages: parseArrayOf(value['dc:coverage'], (value) => parseString(retrieveText(value))), + + // Deprecated fields for backward compatibility. title: parseSingularOf(value['dc:title'], (value) => parseString(retrieveText(value))), creator: parseSingularOf(value['dc:creator'], (value) => parseString(retrieveText(value))), subject: parseSingularOf(value['dc:subject'], (value) => parseString(retrieveText(value))),