ddex-json-codec 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,1209 @@
1
+ import { XMLBuilder, XMLParser } from "fast-xml-parser";
2
+ //#region src/version/namespaces.ts
3
+ /**
4
+ * namespace URI末尾のバージョン識別子 → ErnVersion のマッピング
5
+ * Ruby実装 (sshaw/ddex) の etc/namespaces.yml を参考に構築
6
+ */
7
+ const NAMESPACE_VERSION_MAP = new Map([
8
+ ["ern/38", "3.8"],
9
+ ["ern/381", "3.8.1"],
10
+ ["ern/382", "3.8.2"],
11
+ ["ern/383", "3.8.3"],
12
+ ["ern/41", "4.1"],
13
+ ["ern/411", "4.1.1"],
14
+ ["ern/42", "4.2"],
15
+ ["ern/43", "4.3"],
16
+ ["ern/431", "4.3.1"],
17
+ ["ern/432", "4.3.2"]
18
+ ]);
19
+ /**
20
+ * ErnVersion → namespace URI のマッピング(JSON→XML変換用)
21
+ */
22
+ const VERSION_NAMESPACE_MAP = new Map([
23
+ ["3.8", "http://ddex.net/xml/ern/38"],
24
+ ["3.8.1", "http://ddex.net/xml/ern/381"],
25
+ ["3.8.2", "http://ddex.net/xml/ern/382"],
26
+ ["3.8.3", "http://ddex.net/xml/ern/383"],
27
+ ["4.1", "http://ddex.net/xml/ern/41"],
28
+ ["4.1.1", "http://service.ddex.net/xml/ern/411"],
29
+ ["4.2", "http://ddex.net/xml/ern/42"],
30
+ ["4.3", "http://ddex.net/xml/ern/43"],
31
+ ["4.3.1", "http://ddex.net/xml/ern/431"],
32
+ ["4.3.2", "http://ddex.net/xml/ern/432"]
33
+ ]);
34
+ //#endregion
35
+ //#region src/version/detect.ts
36
+ /**
37
+ * XMLの先頭部分からERNバージョンを検出する
38
+ *
39
+ * 検出戦略(Ruby実装 sshaw/ddex を参考):
40
+ * 1. namespace URI から検出(4系、3.8系共通)
41
+ * 2. MessageSchemaVersionId 属性から検出(3.8系のフォールバック)
42
+ *
43
+ * 巨大ファイル対策として先頭1024バイトのみ読む
44
+ */
45
+ function detectVersion(xml) {
46
+ const head = xml.slice(0, 1024);
47
+ const nsMatch = head.match(/xmlns(?::\w+)?=["']http:\/\/(?:service\.)?ddex\.net\/xml\/(ern\/\d+)/i);
48
+ if (nsMatch) {
49
+ const versionId = nsMatch[1];
50
+ const version = NAMESPACE_VERSION_MAP.get(versionId);
51
+ if (version) return version;
52
+ }
53
+ const schemaMatch = head.match(/MessageSchemaVersionId=["']([^"']+)["']/);
54
+ if (schemaMatch) {
55
+ const raw = schemaMatch[1].trim().replace(/\/\/+/g, "/").replace(/^\/|\/$/g, "");
56
+ const version = NAMESPACE_VERSION_MAP.get(raw);
57
+ if (version) return version;
58
+ }
59
+ throw new Error(`Unsupported or unrecognized ERN version in XML: ${head.slice(0, 200)}...`);
60
+ }
61
+ /**
62
+ * ErnVersion からメジャー系統を取得(変換ロジックの分岐用)
63
+ */
64
+ function getMajorVersion(version) {
65
+ return version.startsWith("3.") ? "3.8" : "4";
66
+ }
67
+ //#endregion
68
+ //#region src/converter/utils.ts
69
+ /**
70
+ * 単一要素をオブジェクトで返す fast-xml-parser の挙動を防御し、常に配列にする
71
+ */
72
+ function ensureArray(value) {
73
+ if (value == null) return [];
74
+ return Array.isArray(value) ? value : [value];
75
+ }
76
+ /**
77
+ * fast-xml-parser が常に配列として返すべきタグ名
78
+ */
79
+ const ALWAYS_ARRAY_TAGS = new Set([
80
+ "SoundRecording",
81
+ "Image",
82
+ "Release",
83
+ "ReleaseDeal",
84
+ "Deal",
85
+ "DisplayArtist",
86
+ "ResourceContributor",
87
+ "IndirectResourceContributor",
88
+ "ResourceGroupContentItem",
89
+ "ResourceGroup",
90
+ "ReleaseResourceReference",
91
+ "Title",
92
+ "TerritoryCode",
93
+ "UseType",
94
+ "Genre",
95
+ "PLine",
96
+ "CLine",
97
+ "SoundRecordingDetailsByTerritory",
98
+ "ReleaseDetailsByTerritory",
99
+ "ImageDetailsByTerritory",
100
+ "DealReleaseReference",
101
+ "DisplayTitle",
102
+ "AdditionalTitle",
103
+ "DisplayArtistName",
104
+ "Contributor",
105
+ "TrackRelease",
106
+ "Party",
107
+ "LinkedReleaseResourceReference",
108
+ "Video"
109
+ ]);
110
+ /**
111
+ * fast-xml-parser XMLParser 設定
112
+ */
113
+ const PARSER_OPTIONS = {
114
+ ignoreAttributes: false,
115
+ attributeNamePrefix: "@_",
116
+ textNodeName: "#text",
117
+ removeNSPrefix: true,
118
+ parseTagValue: false,
119
+ parseAttributeValue: false,
120
+ trimValues: true,
121
+ isArray: (_name, _jpath, _isLeafNode, isAttribute) => {
122
+ if (isAttribute) return false;
123
+ return ALWAYS_ARRAY_TAGS.has(_name);
124
+ }
125
+ };
126
+ /**
127
+ * fast-xml-parser XMLBuilder 設定
128
+ */
129
+ const BUILDER_OPTIONS = {
130
+ ignoreAttributes: false,
131
+ attributeNamePrefix: "@_",
132
+ textNodeName: "#text",
133
+ format: true,
134
+ indentBy: " ",
135
+ suppressBooleanAttributes: false,
136
+ suppressEmptyNode: true
137
+ };
138
+ //#endregion
139
+ //#region src/converter/xml-to-json/ern38-converter.ts
140
+ var Ern38Converter = class {
141
+ convert(parsed, version) {
142
+ const root = parsed.NewReleaseMessage;
143
+ if (!root) throw new Error("NewReleaseMessage root element not found");
144
+ return {
145
+ ernVersion: version,
146
+ messageHeader: this.parseMessageHeader(root.MessageHeader),
147
+ updateIndicator: root.UpdateIndicator ?? void 0,
148
+ resourceList: this.parseSoundRecordings(root.ResourceList),
149
+ releaseList: this.parseReleases(root.ReleaseList),
150
+ dealList: this.parseDealList(root.DealList)
151
+ };
152
+ }
153
+ parseMessageHeader(raw) {
154
+ return {
155
+ messageThreadId: raw.MessageThreadId ?? void 0,
156
+ messageId: raw.MessageId,
157
+ messageFileName: raw.MessageFileName ?? void 0,
158
+ messageSender: this.parseMessageParty(raw.MessageSender),
159
+ messageRecipient: this.parseMessageParty(raw.MessageRecipient),
160
+ messageCreatedDateTime: raw.MessageCreatedDateTime
161
+ };
162
+ }
163
+ parseMessageParty(raw) {
164
+ if (!raw) return {};
165
+ const partyId = raw.PartyId;
166
+ let partyIdValue;
167
+ let isDpid;
168
+ if (partyId) {
169
+ partyIdValue = typeof partyId === "string" ? partyId : partyId["#text"] || void 0;
170
+ isDpid = partyId["@_IsDPID"] === "true" ? true : void 0;
171
+ }
172
+ const fullName = raw.PartyName?.FullName ?? void 0;
173
+ return {
174
+ partyId: partyIdValue,
175
+ partyIdIsDpid: isDpid,
176
+ fullName,
177
+ tradingName: raw.TradingName ?? void 0
178
+ };
179
+ }
180
+ parseSoundRecordings(resourceList) {
181
+ if (!resourceList) return [];
182
+ return ensureArray(resourceList.SoundRecording).map((sr) => this.parseSoundRecording(sr));
183
+ }
184
+ parseSoundRecording(raw) {
185
+ const detailsByTerritory = ensureArray(raw.SoundRecordingDetailsByTerritory).map((d) => this.parseSoundRecordingDetailsByTerritory(d));
186
+ const displayArtists = detailsByTerritory[0]?.displayArtists ?? [];
187
+ return {
188
+ resourceReference: raw.ResourceReference,
189
+ type: raw.SoundRecordingType ?? void 0,
190
+ soundRecordingId: raw.SoundRecordingId ? {
191
+ isrc: raw.SoundRecordingId.ISRC ?? void 0,
192
+ catalogNumber: raw.SoundRecordingId.CatalogNumber ?? void 0
193
+ } : void 0,
194
+ referenceTitle: this.parseReferenceTitle(raw.ReferenceTitle),
195
+ displayArtists,
196
+ duration: raw.Duration ?? void 0,
197
+ languageOfPerformance: raw.LanguageOfPerformance ?? void 0,
198
+ detailsByTerritory
199
+ };
200
+ }
201
+ parseReferenceTitle(raw) {
202
+ if (!raw) return { titleText: "" };
203
+ return {
204
+ titleText: raw.TitleText ?? "",
205
+ subTitle: raw.SubTitle && raw.SubTitle !== "" ? raw.SubTitle : void 0
206
+ };
207
+ }
208
+ parseSoundRecordingDetailsByTerritory(raw) {
209
+ return {
210
+ territoryCode: ensureArray(raw.TerritoryCode),
211
+ displayArtists: this.parseDisplayArtists(raw.DisplayArtist),
212
+ titles: this.parseTitles(raw.Title),
213
+ labelName: raw.LabelName ?? void 0,
214
+ pLine: raw.PLine ? this.parsePLine(ensureArray(raw.PLine)[0]) : void 0,
215
+ genre: raw.Genre ? this.parseGenre(ensureArray(raw.Genre)[0]) : void 0,
216
+ parentalWarningType: raw.ParentalWarningType ?? void 0,
217
+ sequenceNumber: raw.SequenceNumber ? Number(raw.SequenceNumber) : void 0,
218
+ resourceContributors: this.parseResourceContributors(raw.ResourceContributor),
219
+ indirectResourceContributors: this.parseIndirectResourceContributors(raw.IndirectResourceContributor)
220
+ };
221
+ }
222
+ parseReleases(releaseList) {
223
+ if (!releaseList) return [];
224
+ return ensureArray(releaseList.Release).map((r) => this.parseRelease(r));
225
+ }
226
+ parseRelease(raw) {
227
+ const detailsByTerritory = ensureArray(raw.ReleaseDetailsByTerritory).map((d) => this.parseReleaseDetailsByTerritory(d));
228
+ const firstTerritory = detailsByTerritory[0];
229
+ const displayArtists = firstTerritory?.displayArtists ?? [];
230
+ return {
231
+ releaseReference: raw.ReleaseReference,
232
+ releaseType: raw.ReleaseType ?? void 0,
233
+ releaseId: raw.ReleaseId ? this.parseReleaseId(raw.ReleaseId) : void 0,
234
+ referenceTitle: this.parseReferenceTitle(raw.ReferenceTitle),
235
+ displayArtists,
236
+ releaseResourceReferences: this.parseReleaseResourceReferences(raw.ReleaseResourceReferenceList),
237
+ resourceGroup: firstTerritory?.resourceGroup ?? void 0,
238
+ duration: raw.Duration ?? void 0,
239
+ pLine: raw.PLine ? this.parsePLine(ensureArray(raw.PLine)[0]) : void 0,
240
+ cLine: raw.CLine ? this.parseCLine(ensureArray(raw.CLine)[0]) : void 0,
241
+ detailsByTerritory
242
+ };
243
+ }
244
+ parseReleaseId(raw) {
245
+ const icpnRaw = raw.ICPN;
246
+ if (icpnRaw) return {
247
+ icpn: typeof icpnRaw === "string" ? icpnRaw : icpnRaw["#text"],
248
+ isEan: typeof icpnRaw === "object" && icpnRaw["@_IsEan"] === "true" ? true : void 0
249
+ };
250
+ return {
251
+ isrc: raw.ISRC ?? void 0,
252
+ gridOrIcpn: raw.GRid ?? void 0,
253
+ catalogNumber: raw.CatalogNumber ?? void 0
254
+ };
255
+ }
256
+ parseReleaseResourceReferences(raw) {
257
+ if (!raw) return void 0;
258
+ return ensureArray(raw.ReleaseResourceReference).map((ref) => {
259
+ if (typeof ref === "string") return { value: ref };
260
+ return {
261
+ value: ref["#text"],
262
+ releaseResourceType: ref["@_ReleaseResourceType"] ?? void 0
263
+ };
264
+ });
265
+ }
266
+ parseReleaseDetailsByTerritory(raw) {
267
+ return {
268
+ territoryCode: ensureArray(raw.TerritoryCode),
269
+ displayArtists: this.parseDisplayArtists(raw.DisplayArtist),
270
+ displayArtistName: Array.isArray(raw.DisplayArtistName) ? raw.DisplayArtistName[0] : raw.DisplayArtistName ?? void 0,
271
+ titles: this.parseTitles(raw.Title),
272
+ labelName: raw.LabelName ?? void 0,
273
+ genre: raw.Genre ? this.parseGenre(ensureArray(raw.Genre)[0]) : void 0,
274
+ parentalWarningType: raw.ParentalWarningType ?? void 0,
275
+ originalReleaseDate: raw.OriginalReleaseDate ?? void 0,
276
+ resourceGroup: raw.ResourceGroup ? this.parseResourceGroupWrapper(raw.ResourceGroup) : void 0
277
+ };
278
+ }
279
+ parseResourceGroupWrapper(raw) {
280
+ const outerRaw = Array.isArray(raw) ? raw[0] : raw;
281
+ return this.parseResourceGroup(outerRaw);
282
+ }
283
+ parseResourceGroup(raw) {
284
+ const nestedGroups = raw.ResourceGroup ? ensureArray(raw.ResourceGroup).map((g) => this.parseResourceGroup(g)) : void 0;
285
+ const contentItems = raw.ResourceGroupContentItem ? ensureArray(raw.ResourceGroupContentItem).map((item) => this.parseResourceGroupContentItem(item)) : void 0;
286
+ return {
287
+ sequenceNumber: raw.SequenceNumber ? Number(raw.SequenceNumber) : void 0,
288
+ title: raw.Title ? this.extractTitleText(raw.Title) : void 0,
289
+ resourceGroups: nestedGroups,
290
+ resourceGroupContentItems: contentItems
291
+ };
292
+ }
293
+ extractTitleText(raw) {
294
+ if (Array.isArray(raw)) return raw[0]?.TitleText ?? void 0;
295
+ return raw?.TitleText ?? void 0;
296
+ }
297
+ parseResourceGroupContentItem(raw) {
298
+ const ref = raw.ReleaseResourceReference;
299
+ let releaseResourceRef;
300
+ if (typeof ref === "string") releaseResourceRef = { value: ref };
301
+ else if (Array.isArray(ref)) {
302
+ const first = ref[0];
303
+ releaseResourceRef = typeof first === "string" ? { value: first } : {
304
+ value: first["#text"],
305
+ releaseResourceType: first["@_ReleaseResourceType"] ?? void 0
306
+ };
307
+ } else releaseResourceRef = {
308
+ value: ref["#text"],
309
+ releaseResourceType: ref["@_ReleaseResourceType"] ?? void 0
310
+ };
311
+ return {
312
+ sequenceNumber: raw.SequenceNumber ? Number(raw.SequenceNumber) : void 0,
313
+ resourceType: raw.ResourceType,
314
+ releaseResourceReference: releaseResourceRef
315
+ };
316
+ }
317
+ parseDealList(dealList) {
318
+ if (!dealList) return [];
319
+ return ensureArray(dealList.ReleaseDeal).map((rd) => this.parseReleaseDeal(rd));
320
+ }
321
+ parseReleaseDeal(raw) {
322
+ return {
323
+ dealReleaseReferences: ensureArray(raw.DealReleaseReference),
324
+ deals: ensureArray(raw.Deal).map((d) => this.parseDeal(d)),
325
+ effectiveDate: raw.EffectiveDate ?? void 0
326
+ };
327
+ }
328
+ parseDeal(raw) {
329
+ return {
330
+ dealReference: raw.DealReference ?? void 0,
331
+ dealTerms: this.parseDealTerms(raw.DealTerms)
332
+ };
333
+ }
334
+ parseDealTerms(raw) {
335
+ const usage = raw.Usage;
336
+ return {
337
+ commercialModelType: raw.CommercialModelType ?? void 0,
338
+ usage: usage ? { useTypes: ensureArray(usage.UseType) } : void 0,
339
+ territoryCode: raw.TerritoryCode ? ensureArray(raw.TerritoryCode) : void 0,
340
+ validityPeriod: raw.ValidityPeriod ? {
341
+ startDate: raw.ValidityPeriod.StartDate ?? void 0,
342
+ endDate: raw.ValidityPeriod.EndDate ?? void 0
343
+ } : void 0,
344
+ takeDown: raw.TakeDown === "true" ? true : void 0
345
+ };
346
+ }
347
+ parseDisplayArtists(raw) {
348
+ if (!raw) return void 0;
349
+ const artists = ensureArray(raw);
350
+ if (artists.length === 0) return void 0;
351
+ return artists.map((a) => ({
352
+ artist: {
353
+ name: a.PartyName?.FullName ?? "",
354
+ roles: a.ArtistRole ? ensureArray(a.ArtistRole) : void 0
355
+ },
356
+ sequenceNumber: a["@_SequenceNumber"] ? Number(a["@_SequenceNumber"]) : void 0
357
+ }));
358
+ }
359
+ parseResourceContributors(raw) {
360
+ if (!raw) return void 0;
361
+ const contributors = ensureArray(raw);
362
+ if (contributors.length === 0) return void 0;
363
+ return contributors.map((c) => {
364
+ const roleRaw = c.ResourceContributorRole;
365
+ let role;
366
+ let roleNamespace;
367
+ let roleUserDefinedValue;
368
+ if (!roleRaw) role = c.InstrumentType ?? "";
369
+ else if (typeof roleRaw === "string") role = roleRaw;
370
+ else {
371
+ role = roleRaw["#text"] ?? "";
372
+ roleNamespace = roleRaw["@_Namespace"] ?? void 0;
373
+ roleUserDefinedValue = roleRaw["@_UserDefinedValue"] ?? void 0;
374
+ }
375
+ return {
376
+ name: c.PartyName?.FullName ?? "",
377
+ role,
378
+ sequenceNumber: c["@_SequenceNumber"] ? Number(c["@_SequenceNumber"]) : void 0,
379
+ roleNamespace,
380
+ roleUserDefinedValue
381
+ };
382
+ });
383
+ }
384
+ parseIndirectResourceContributors(raw) {
385
+ if (!raw) return void 0;
386
+ const contributors = ensureArray(raw);
387
+ if (contributors.length === 0) return void 0;
388
+ return contributors.map((c) => ({
389
+ name: c.PartyName?.FullName ?? "",
390
+ role: c.IndirectResourceContributorRole ?? "",
391
+ sequenceNumber: c["@_SequenceNumber"] ? Number(c["@_SequenceNumber"]) : void 0
392
+ }));
393
+ }
394
+ parseTitles(raw) {
395
+ if (!raw) return void 0;
396
+ const titles = ensureArray(raw);
397
+ if (titles.length === 0) return void 0;
398
+ return titles.map((t) => ({
399
+ titleText: t.TitleText ?? "",
400
+ subTitle: t.SubTitle && t.SubTitle !== "" ? t.SubTitle : void 0,
401
+ titleType: t["@_TitleType"] ?? void 0
402
+ }));
403
+ }
404
+ parsePLine(raw) {
405
+ return {
406
+ year: raw.Year ?? void 0,
407
+ pLineText: raw.PLineText ?? ""
408
+ };
409
+ }
410
+ parseCLine(raw) {
411
+ return {
412
+ year: raw.Year ?? void 0,
413
+ cLineText: raw.CLineText ?? ""
414
+ };
415
+ }
416
+ parseGenre(raw) {
417
+ return {
418
+ genreText: raw.GenreText ?? "",
419
+ subGenre: raw.SubGenre ?? void 0
420
+ };
421
+ }
422
+ };
423
+ //#endregion
424
+ //#region src/converter/xml-to-json/ern4-converter.ts
425
+ var Ern4Converter = class {
426
+ partyIndex = /* @__PURE__ */ new Map();
427
+ convert(parsed, version) {
428
+ const root = parsed.NewReleaseMessage;
429
+ if (!root) throw new Error("NewReleaseMessage root element not found");
430
+ const partyList = this.buildPartyIndex(root.PartyList);
431
+ return {
432
+ ernVersion: version,
433
+ messageHeader: this.parseMessageHeader(root.MessageHeader),
434
+ resourceList: this.parseSoundRecordings(root.ResourceList),
435
+ releaseList: this.parseReleases(root.ReleaseList),
436
+ dealList: this.parseDealList(root.DealList),
437
+ partyList,
438
+ trackReleaseList: this.parseTrackReleases(root.ReleaseList)
439
+ };
440
+ }
441
+ buildPartyIndex(partyListRaw) {
442
+ if (!partyListRaw) return [];
443
+ const parties = ensureArray(partyListRaw.Party);
444
+ const result = [];
445
+ for (const p of parties) {
446
+ const party = this.parseParty(p);
447
+ this.partyIndex.set(party.partyReference, party);
448
+ result.push(party);
449
+ }
450
+ return result;
451
+ }
452
+ parseParty(raw) {
453
+ const partyNames = ensureArray(raw.PartyName).map((pn) => {
454
+ return {
455
+ fullName: pn.FullName ?? "",
456
+ fullNameIndexed: pn.FullNameIndexed ?? void 0,
457
+ languageAndScriptCode: pn["@_LanguageAndScriptCode"] ?? void 0
458
+ };
459
+ });
460
+ const partyIds = [];
461
+ if (raw.PartyId) {
462
+ const ids = ensureArray(raw.PartyId);
463
+ for (const id of ids) if (typeof id === "string") partyIds.push(id);
464
+ else if (id.ProprietaryId) {
465
+ const propId = id.ProprietaryId;
466
+ partyIds.push(typeof propId === "string" ? propId : propId["#text"] ?? "");
467
+ } else if (id["#text"]) partyIds.push(id["#text"]);
468
+ }
469
+ return {
470
+ partyReference: raw.PartyReference,
471
+ partyName: partyNames.length > 0 ? partyNames : void 0,
472
+ partyId: partyIds.length > 0 ? partyIds : void 0
473
+ };
474
+ }
475
+ resolveArtistName(partyReference) {
476
+ const party = this.partyIndex.get(partyReference);
477
+ if (!party?.partyName?.length) return partyReference;
478
+ return party.partyName[0].fullName;
479
+ }
480
+ parseMessageHeader(raw) {
481
+ return {
482
+ messageThreadId: raw.MessageThreadId ?? void 0,
483
+ messageId: raw.MessageId,
484
+ messageFileName: raw.MessageFileName ?? void 0,
485
+ messageSender: this.parseMessageParty(raw.MessageSender),
486
+ messageRecipient: this.parseMessageParty(raw.MessageRecipient),
487
+ messageCreatedDateTime: raw.MessageCreatedDateTime
488
+ };
489
+ }
490
+ parseMessageParty(raw) {
491
+ if (!raw) return {};
492
+ const partyId = raw.PartyId;
493
+ let partyIdValue;
494
+ if (partyId) partyIdValue = typeof partyId === "string" ? partyId : partyId["#text"] || void 0;
495
+ const partyName = raw.PartyName;
496
+ let fullName;
497
+ if (partyName) if (Array.isArray(partyName)) fullName = partyName[0]?.FullName ?? void 0;
498
+ else fullName = partyName.FullName ?? void 0;
499
+ return {
500
+ partyId: partyIdValue,
501
+ fullName,
502
+ tradingName: raw.TradingName ?? void 0
503
+ };
504
+ }
505
+ parseSoundRecordings(resourceList) {
506
+ if (!resourceList) return [];
507
+ return ensureArray(resourceList.SoundRecording).map((sr) => this.parseSoundRecording(sr));
508
+ }
509
+ parseSoundRecording(raw) {
510
+ const edition = raw.SoundRecordingEdition;
511
+ let soundRecordingId;
512
+ let pLine;
513
+ if (edition) {
514
+ const editionData = Array.isArray(edition) ? edition[0] : edition;
515
+ soundRecordingId = editionData.ResourceId ? this.parseSoundRecordingId(editionData.ResourceId) : void 0;
516
+ pLine = editionData.PLine ? this.parsePLine(Array.isArray(editionData.PLine) ? editionData.PLine[0] : editionData.PLine) : void 0;
517
+ } else {
518
+ soundRecordingId = raw.ResourceId ? this.parseSoundRecordingId(raw.ResourceId) : void 0;
519
+ pLine = raw.PLine ? this.parsePLine(Array.isArray(raw.PLine) ? raw.PLine[0] : raw.PLine) : void 0;
520
+ }
521
+ return {
522
+ resourceReference: raw.ResourceReference,
523
+ type: raw.Type ?? void 0,
524
+ soundRecordingId,
525
+ displayTitleText: raw.DisplayTitleText ?? void 0,
526
+ displayTitles: this.parseDisplayTitles(raw.DisplayTitle),
527
+ displayArtists: this.parseDisplayArtists(raw.DisplayArtist) ?? [],
528
+ contributors: this.parseContributors(raw.Contributor),
529
+ pLine,
530
+ duration: raw.Duration ?? void 0,
531
+ creationDate: raw.CreationDate ? this.parseDateValue(raw.CreationDate) : void 0,
532
+ languageOfPerformance: raw.LanguageOfPerformance ?? void 0
533
+ };
534
+ }
535
+ parseSoundRecordingId(raw) {
536
+ return {
537
+ isrc: raw.ISRC ?? void 0,
538
+ catalogNumber: raw.CatalogNumber ?? void 0
539
+ };
540
+ }
541
+ parseReleases(releaseList) {
542
+ if (!releaseList) return [];
543
+ return ensureArray(releaseList.Release).map((r) => this.parseRelease(r));
544
+ }
545
+ parseRelease(raw) {
546
+ return {
547
+ releaseReference: raw.ReleaseReference,
548
+ releaseType: this.parseReleaseType(raw.ReleaseType),
549
+ releaseId: raw.ReleaseId ? this.parseReleaseId(raw.ReleaseId) : void 0,
550
+ displayTitleText: raw.DisplayTitleText ?? void 0,
551
+ displayTitles: this.parseDisplayTitles(raw.DisplayTitle),
552
+ displayArtists: this.parseDisplayArtists(raw.DisplayArtist) ?? [],
553
+ releaseLabelReferences: this.parseReleaseLabelReferences(raw.ReleaseLabelReference),
554
+ resourceGroup: raw.ResourceGroup ? this.parseResourceGroup(Array.isArray(raw.ResourceGroup) ? raw.ResourceGroup[0] : raw.ResourceGroup) : void 0,
555
+ duration: raw.Duration ?? void 0,
556
+ pLine: raw.PLine ? this.parsePLine(Array.isArray(raw.PLine) ? raw.PLine[0] : raw.PLine) : void 0,
557
+ cLine: raw.CLine ? this.parseCLine(Array.isArray(raw.CLine) ? raw.CLine[0] : raw.CLine) : void 0,
558
+ genre: raw.Genre ? this.parseGenre(Array.isArray(raw.Genre) ? raw.Genre[0] : raw.Genre) : void 0,
559
+ parentalWarningType: raw.ParentalWarningType ?? void 0
560
+ };
561
+ }
562
+ parseReleaseType(raw) {
563
+ if (!raw) return void 0;
564
+ const types = ensureArray(raw);
565
+ for (const t of types) {
566
+ const val = typeof t === "string" ? t : t["#text"];
567
+ if (val && val !== "UserDefined") return val;
568
+ }
569
+ return typeof types[0] === "string" ? types[0] : types[0]?.["#text"];
570
+ }
571
+ parseReleaseId(raw) {
572
+ const icpnRaw = raw.ICPN;
573
+ if (icpnRaw) return { icpn: typeof icpnRaw === "string" ? icpnRaw : icpnRaw["#text"] };
574
+ const propId = raw.ProprietaryId;
575
+ let proprietaryId;
576
+ if (propId) proprietaryId = typeof propId === "string" ? propId : propId["#text"];
577
+ return {
578
+ isrc: raw.ISRC ?? void 0,
579
+ gridOrIcpn: raw.GRid ?? void 0,
580
+ catalogNumber: raw.CatalogNumber ?? void 0,
581
+ proprietaryId
582
+ };
583
+ }
584
+ parseReleaseLabelReferences(raw) {
585
+ if (!raw) return void 0;
586
+ return ensureArray(raw).map((r) => typeof r === "string" ? r : r["#text"] ?? "");
587
+ }
588
+ parseTrackReleases(releaseList) {
589
+ if (!releaseList) return void 0;
590
+ const tracks = ensureArray(releaseList.TrackRelease);
591
+ if (tracks.length === 0) return void 0;
592
+ return tracks.map((tr) => this.parseTrackRelease(tr));
593
+ }
594
+ parseTrackRelease(raw) {
595
+ const ref = raw.ReleaseResourceReference;
596
+ const releaseResourceReference = typeof ref === "string" ? ref : Array.isArray(ref) ? ref[0] : ref?.["#text"] ?? "";
597
+ return {
598
+ releaseReference: raw.ReleaseReference,
599
+ releaseId: raw.ReleaseId ? this.parseReleaseId(raw.ReleaseId) : void 0,
600
+ displayTitles: this.parseDisplayTitles(raw.DisplayTitle),
601
+ displayArtists: this.parseDisplayArtists(raw.DisplayArtist) ?? void 0,
602
+ releaseResourceReference,
603
+ releaseLabelReferences: this.parseReleaseLabelReferences(raw.ReleaseLabelReference),
604
+ genre: raw.Genre ? this.parseGenre(Array.isArray(raw.Genre) ? raw.Genre[0] : raw.Genre) : void 0
605
+ };
606
+ }
607
+ parseResourceGroup(raw) {
608
+ const nestedGroups = raw.ResourceGroup ? ensureArray(raw.ResourceGroup).map((g) => this.parseResourceGroup(g)) : void 0;
609
+ const contentItems = raw.ResourceGroupContentItem ? ensureArray(raw.ResourceGroupContentItem).map((item) => this.parseResourceGroupContentItem(item)) : void 0;
610
+ let title;
611
+ if (raw.AdditionalTitle) title = (Array.isArray(raw.AdditionalTitle) ? raw.AdditionalTitle[0] : raw.AdditionalTitle)?.TitleText ?? void 0;
612
+ return {
613
+ sequenceNumber: raw.SequenceNumber ? Number(raw.SequenceNumber) : void 0,
614
+ title,
615
+ resourceGroups: nestedGroups,
616
+ resourceGroupContentItems: contentItems
617
+ };
618
+ }
619
+ parseResourceGroupContentItem(raw) {
620
+ const ref = raw.ReleaseResourceReference;
621
+ let releaseResourceRef;
622
+ if (typeof ref === "string") releaseResourceRef = { value: ref };
623
+ else if (Array.isArray(ref)) {
624
+ const first = ref[0];
625
+ releaseResourceRef = typeof first === "string" ? { value: first } : {
626
+ value: first["#text"],
627
+ releaseResourceType: first["@_ReleaseResourceType"] ?? void 0
628
+ };
629
+ } else releaseResourceRef = {
630
+ value: ref?.["#text"] ?? "",
631
+ releaseResourceType: ref?.["@_ReleaseResourceType"] ?? void 0
632
+ };
633
+ return {
634
+ sequenceNumber: raw.SequenceNumber ? Number(raw.SequenceNumber) : void 0,
635
+ resourceType: raw.ResourceType ?? void 0,
636
+ releaseResourceReference: releaseResourceRef
637
+ };
638
+ }
639
+ parseDealList(dealList) {
640
+ if (!dealList) return [];
641
+ return ensureArray(dealList.ReleaseDeal).map((rd) => this.parseReleaseDeal(rd));
642
+ }
643
+ parseReleaseDeal(raw) {
644
+ return {
645
+ dealReleaseReferences: ensureArray(raw.DealReleaseReference),
646
+ deals: ensureArray(raw.Deal).map((d) => this.parseDeal(d)),
647
+ effectiveDate: raw.EffectiveDate ?? void 0
648
+ };
649
+ }
650
+ parseDeal(raw) {
651
+ return {
652
+ dealReference: raw.DealReference ?? void 0,
653
+ dealTerms: this.parseDealTerms(raw.DealTerms)
654
+ };
655
+ }
656
+ parseDealTerms(raw) {
657
+ const useTypes = raw.UseType ? ensureArray(raw.UseType) : void 0;
658
+ const cmtRaw = raw.CommercialModelType;
659
+ let commercialModelType;
660
+ if (cmtRaw) if (Array.isArray(cmtRaw)) commercialModelType = cmtRaw[0];
661
+ else commercialModelType = cmtRaw;
662
+ return {
663
+ commercialModelType,
664
+ useTypes,
665
+ territoryCode: raw.TerritoryCode ? ensureArray(raw.TerritoryCode) : void 0,
666
+ validityPeriod: raw.ValidityPeriod ? {
667
+ startDate: raw.ValidityPeriod.StartDate ?? void 0,
668
+ endDate: raw.ValidityPeriod.EndDate ?? void 0
669
+ } : void 0
670
+ };
671
+ }
672
+ parseDisplayArtists(raw) {
673
+ if (!raw) return void 0;
674
+ const artists = ensureArray(raw);
675
+ if (artists.length === 0) return void 0;
676
+ return artists.map((a) => {
677
+ const partyRef = a.ArtistPartyReference;
678
+ return {
679
+ artist: {
680
+ name: partyRef ? this.resolveArtistName(partyRef) : a.PartyName?.FullName ?? "",
681
+ partyReference: partyRef ?? void 0,
682
+ roles: a.DisplayArtistRole ? ensureArray(a.DisplayArtistRole) : void 0
683
+ },
684
+ sequenceNumber: a["@_SequenceNumber"] ? Number(a["@_SequenceNumber"]) : void 0
685
+ };
686
+ });
687
+ }
688
+ parseContributors(raw) {
689
+ if (!raw) return void 0;
690
+ const contributors = ensureArray(raw);
691
+ if (contributors.length === 0) return void 0;
692
+ return contributors.map((c) => {
693
+ const partyRef = c.ContributorPartyReference;
694
+ const name = partyRef ? this.resolveArtistName(partyRef) : void 0;
695
+ return {
696
+ contributorPartyReference: partyRef ?? "",
697
+ name,
698
+ role: typeof c.Role === "string" ? c.Role : c.Role?.["#text"] ?? "",
699
+ sequenceNumber: c["@_SequenceNumber"] ? Number(c["@_SequenceNumber"]) : void 0
700
+ };
701
+ });
702
+ }
703
+ parseDisplayTitles(raw) {
704
+ if (!raw) return void 0;
705
+ const titles = ensureArray(raw);
706
+ if (titles.length === 0) return void 0;
707
+ return titles.map((t) => ({
708
+ titleText: t.TitleText ?? "",
709
+ subTitle: t.SubTitle && t.SubTitle !== "" ? t.SubTitle : void 0,
710
+ applicableTerritoryCode: t["@_ApplicableTerritoryCode"] ?? void 0,
711
+ languageAndScriptCode: t["@_LanguageAndScriptCode"] ?? void 0,
712
+ isDefault: t["@_IsDefault"] === "true" ? true : void 0
713
+ }));
714
+ }
715
+ parsePLine(raw) {
716
+ return {
717
+ year: raw.Year ?? void 0,
718
+ pLineText: raw.PLineText ?? ""
719
+ };
720
+ }
721
+ parseCLine(raw) {
722
+ return {
723
+ year: raw.Year ?? void 0,
724
+ cLineText: raw.CLineText ?? ""
725
+ };
726
+ }
727
+ parseGenre(raw) {
728
+ return {
729
+ genreText: raw.GenreText ?? "",
730
+ subGenre: raw.SubGenre ?? void 0
731
+ };
732
+ }
733
+ parseDateValue(raw) {
734
+ if (typeof raw === "string") return raw;
735
+ return raw["#text"] ?? "";
736
+ }
737
+ };
738
+ //#endregion
739
+ //#region src/converter/json-to-xml/ern38-builder.ts
740
+ var Ern38Builder = class {
741
+ build(message, version) {
742
+ const nsUri = VERSION_NAMESPACE_MAP.get(version);
743
+ if (!nsUri) throw new Error(`Unknown version: ${version}`);
744
+ const nsPath = new URL(nsUri).pathname.replace(/^\/xml\//, "");
745
+ const root = { "ern:NewReleaseMessage": {
746
+ "@_xmlns:ern": nsUri,
747
+ "@_xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
748
+ "@_MessageSchemaVersionId": nsPath,
749
+ "@_xsi:schemaLocation": `${nsUri} ${nsUri}/release-notification.xsd`,
750
+ MessageHeader: this.buildMessageHeader(message.messageHeader),
751
+ ...message.updateIndicator ? { UpdateIndicator: message.updateIndicator } : {},
752
+ ResourceList: this.buildResourceList(message.resourceList),
753
+ ReleaseList: this.buildReleaseList(message.releaseList),
754
+ DealList: this.buildDealList(message.dealList)
755
+ } };
756
+ return `<?xml version="1.0" encoding="UTF-8"?>\n${new XMLBuilder(BUILDER_OPTIONS).build(root)}`.trimEnd();
757
+ }
758
+ buildMessageHeader(header) {
759
+ return {
760
+ ...header.messageThreadId ? { MessageThreadId: header.messageThreadId } : {},
761
+ MessageId: header.messageId,
762
+ ...header.messageFileName ? { MessageFileName: header.messageFileName } : {},
763
+ MessageSender: this.buildMessageParty(header.messageSender),
764
+ MessageRecipient: this.buildMessageParty(header.messageRecipient),
765
+ MessageCreatedDateTime: header.messageCreatedDateTime
766
+ };
767
+ }
768
+ buildMessageParty(party) {
769
+ const result = {};
770
+ if (party.partyId !== void 0) result.PartyId = {
771
+ "#text": party.partyId || "",
772
+ ...party.partyIdIsDpid ? { "@_IsDPID": "true" } : {}
773
+ };
774
+ if (party.fullName) result.PartyName = { FullName: party.fullName };
775
+ if (party.tradingName) result.TradingName = party.tradingName;
776
+ return result;
777
+ }
778
+ buildResourceList(soundRecordings) {
779
+ return { SoundRecording: soundRecordings.map((sr) => this.buildSoundRecording(sr)) };
780
+ }
781
+ buildSoundRecording(sr) {
782
+ const result = {};
783
+ if (sr.type) result.SoundRecordingType = sr.type;
784
+ if (sr.soundRecordingId) {
785
+ const id = {};
786
+ if (sr.soundRecordingId.isrc) id.ISRC = sr.soundRecordingId.isrc;
787
+ if (sr.soundRecordingId.catalogNumber) id.CatalogNumber = sr.soundRecordingId.catalogNumber;
788
+ result.SoundRecordingId = id;
789
+ }
790
+ result.ResourceReference = sr.resourceReference;
791
+ if (sr.referenceTitle) result.ReferenceTitle = this.buildReferenceTitle(sr.referenceTitle);
792
+ if (sr.languageOfPerformance) result.LanguageOfPerformance = sr.languageOfPerformance;
793
+ if (sr.duration) result.Duration = sr.duration;
794
+ if (sr.detailsByTerritory) result.SoundRecordingDetailsByTerritory = sr.detailsByTerritory.map((d) => this.buildSoundRecordingDetailsByTerritory(d));
795
+ return result;
796
+ }
797
+ buildReferenceTitle(rt) {
798
+ const result = { TitleText: rt.titleText };
799
+ if (rt.subTitle) result.SubTitle = rt.subTitle;
800
+ return result;
801
+ }
802
+ buildSoundRecordingDetailsByTerritory(d) {
803
+ const result = {};
804
+ result.TerritoryCode = d.territoryCode;
805
+ if (d.titles) result.Title = d.titles.map((t) => this.buildTitle(t));
806
+ if (d.displayArtists) result.DisplayArtist = d.displayArtists.map((a) => this.buildDisplayArtist(a));
807
+ if (d.resourceContributors) result.ResourceContributor = d.resourceContributors.map((c) => this.buildResourceContributor(c));
808
+ if (d.indirectResourceContributors) result.IndirectResourceContributor = d.indirectResourceContributors.map((c) => this.buildIndirectResourceContributor(c));
809
+ if (d.labelName) result.LabelName = d.labelName;
810
+ if (d.pLine) result.PLine = this.buildPLine(d.pLine);
811
+ if (d.sequenceNumber != null) result.SequenceNumber = String(d.sequenceNumber);
812
+ if (d.genre) result.Genre = this.buildGenre(d.genre);
813
+ if (d.parentalWarningType) result.ParentalWarningType = d.parentalWarningType;
814
+ return result;
815
+ }
816
+ buildReleaseList(releases) {
817
+ return { Release: releases.map((r) => this.buildRelease(r)) };
818
+ }
819
+ buildRelease(r) {
820
+ const result = {};
821
+ if (r.releaseId) result.ReleaseId = this.buildReleaseId(r.releaseId);
822
+ result.ReleaseReference = r.releaseReference;
823
+ if (r.referenceTitle) result.ReferenceTitle = this.buildReferenceTitle(r.referenceTitle);
824
+ if (r.releaseResourceReferences) result.ReleaseResourceReferenceList = { ReleaseResourceReference: r.releaseResourceReferences.map((ref) => this.buildReleaseResourceReference(ref)) };
825
+ if (r.releaseType) result.ReleaseType = r.releaseType;
826
+ if (r.detailsByTerritory) result.ReleaseDetailsByTerritory = r.detailsByTerritory.map((d) => this.buildReleaseDetailsByTerritory(d));
827
+ if (r.duration) result.Duration = r.duration;
828
+ if (r.pLine) result.PLine = this.buildPLine(r.pLine);
829
+ if (r.cLine) result.CLine = this.buildCLine(r.cLine);
830
+ return result;
831
+ }
832
+ buildReleaseId(id) {
833
+ if (!id) return {};
834
+ if (id.icpn) return { ICPN: {
835
+ "#text": id.icpn,
836
+ ...id.isEan != null ? { "@_IsEan": String(id.isEan) } : {}
837
+ } };
838
+ const result = {};
839
+ if (id.isrc) result.ISRC = id.isrc;
840
+ if (id.gridOrIcpn) result.GRid = id.gridOrIcpn;
841
+ if (id.catalogNumber) result.CatalogNumber = id.catalogNumber;
842
+ return result;
843
+ }
844
+ buildReleaseResourceReference(ref) {
845
+ return {
846
+ "#text": ref.value,
847
+ ...ref.releaseResourceType ? { "@_ReleaseResourceType": ref.releaseResourceType } : {}
848
+ };
849
+ }
850
+ buildReleaseDetailsByTerritory(d) {
851
+ const result = {};
852
+ result.TerritoryCode = d.territoryCode;
853
+ if (d.displayArtistName) result.DisplayArtistName = d.displayArtistName;
854
+ if (d.labelName) result.LabelName = d.labelName;
855
+ if (d.titles) result.Title = d.titles.map((t) => this.buildTitle(t));
856
+ if (d.displayArtists) result.DisplayArtist = d.displayArtists.map((a) => this.buildDisplayArtist(a));
857
+ if (d.parentalWarningType) result.ParentalWarningType = d.parentalWarningType;
858
+ if (d.resourceGroup) result.ResourceGroup = this.buildResourceGroup(d.resourceGroup);
859
+ if (d.genre) result.Genre = this.buildGenre(d.genre);
860
+ if (d.originalReleaseDate) result.OriginalReleaseDate = d.originalReleaseDate;
861
+ return result;
862
+ }
863
+ buildResourceGroup(rg) {
864
+ const result = {};
865
+ if (rg.title) result.Title = { TitleText: rg.title };
866
+ if (rg.sequenceNumber != null) result.SequenceNumber = String(rg.sequenceNumber);
867
+ if (rg.resourceGroups) result.ResourceGroup = rg.resourceGroups.map((g) => this.buildResourceGroup(g));
868
+ if (rg.resourceGroupContentItems) result.ResourceGroupContentItem = rg.resourceGroupContentItems.map((item) => this.buildResourceGroupContentItem(item));
869
+ return result;
870
+ }
871
+ buildResourceGroupContentItem(item) {
872
+ const result = {};
873
+ if (item.sequenceNumber != null) result.SequenceNumber = String(item.sequenceNumber);
874
+ result.ResourceType = item.resourceType;
875
+ result.ReleaseResourceReference = this.buildReleaseResourceReference(item.releaseResourceReference);
876
+ return result;
877
+ }
878
+ buildDealList(deals) {
879
+ return { ReleaseDeal: deals.map((rd) => this.buildReleaseDeal(rd)) };
880
+ }
881
+ buildReleaseDeal(rd) {
882
+ const result = {};
883
+ result.DealReleaseReference = rd.dealReleaseReferences;
884
+ result.Deal = rd.deals.map((d) => this.buildDeal(d));
885
+ if (rd.effectiveDate) result.EffectiveDate = rd.effectiveDate;
886
+ return result;
887
+ }
888
+ buildDeal(deal) {
889
+ const result = {};
890
+ if (deal.dealReference) result.DealReference = deal.dealReference;
891
+ result.DealTerms = this.buildDealTerms(deal.dealTerms);
892
+ return result;
893
+ }
894
+ buildDealTerms(dt) {
895
+ const result = {};
896
+ if (dt.takeDown) result.TakeDown = "true";
897
+ if (dt.commercialModelType) result.CommercialModelType = dt.commercialModelType;
898
+ if (dt.usage) result.Usage = { UseType: dt.usage.useTypes };
899
+ if (dt.territoryCode) result.TerritoryCode = dt.territoryCode;
900
+ if (dt.validityPeriod) {
901
+ const vp = {};
902
+ if (dt.validityPeriod.startDate) vp.StartDate = dt.validityPeriod.startDate;
903
+ if (dt.validityPeriod.endDate) vp.EndDate = dt.validityPeriod.endDate;
904
+ result.ValidityPeriod = vp;
905
+ }
906
+ return result;
907
+ }
908
+ buildDisplayArtist(da) {
909
+ const result = {};
910
+ if (da.sequenceNumber != null) result["@_SequenceNumber"] = String(da.sequenceNumber);
911
+ result.PartyName = { FullName: da.artist.name };
912
+ if (da.artist.roles?.length) result.ArtistRole = da.artist.roles.length === 1 ? da.artist.roles[0] : da.artist.roles;
913
+ return result;
914
+ }
915
+ buildResourceContributor(c) {
916
+ const result = {};
917
+ if (c.sequenceNumber != null) result["@_SequenceNumber"] = String(c.sequenceNumber);
918
+ result.PartyName = { FullName: c.name };
919
+ if (c.roleUserDefinedValue) result.ResourceContributorRole = {
920
+ "#text": c.role,
921
+ ...c.roleNamespace ? { "@_Namespace": c.roleNamespace } : {},
922
+ "@_UserDefinedValue": c.roleUserDefinedValue
923
+ };
924
+ else result.ResourceContributorRole = c.role;
925
+ return result;
926
+ }
927
+ buildIndirectResourceContributor(c) {
928
+ const result = {};
929
+ if (c.sequenceNumber != null) result["@_SequenceNumber"] = String(c.sequenceNumber);
930
+ result.PartyName = { FullName: c.name };
931
+ result.IndirectResourceContributorRole = c.role;
932
+ return result;
933
+ }
934
+ buildTitle(t) {
935
+ const result = {};
936
+ if (t.titleType) result["@_TitleType"] = t.titleType;
937
+ result.TitleText = t.titleText;
938
+ if (t.subTitle) result.SubTitle = t.subTitle;
939
+ return result;
940
+ }
941
+ buildPLine(p) {
942
+ const result = {};
943
+ if (p.year) result.Year = p.year;
944
+ result.PLineText = p.pLineText;
945
+ return result;
946
+ }
947
+ buildCLine(c) {
948
+ const result = {};
949
+ if (c.year) result.Year = c.year;
950
+ result.CLineText = c.cLineText;
951
+ return result;
952
+ }
953
+ buildGenre(g) {
954
+ const result = {};
955
+ result.GenreText = g.genreText;
956
+ if (g.subGenre) result.SubGenre = g.subGenre;
957
+ return result;
958
+ }
959
+ };
960
+ //#endregion
961
+ //#region src/converter/json-to-xml/ern4-builder.ts
962
+ var Ern4Builder = class {
963
+ build(message, version) {
964
+ const nsUri = VERSION_NAMESPACE_MAP.get(version);
965
+ if (!nsUri) throw new Error(`Unknown version: ${version}`);
966
+ const root = { "ern:NewReleaseMessage": {
967
+ "@_xmlns:ern": nsUri,
968
+ "@_xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
969
+ "@_xsi:schemaLocation": `${nsUri} ${nsUri}/release-notification.xsd`,
970
+ "@_LanguageAndScriptCode": "en",
971
+ MessageHeader: this.buildMessageHeader(message.messageHeader),
972
+ PartyList: this.buildPartyList(message.partyList ?? []),
973
+ ResourceList: this.buildResourceList(message.resourceList, version),
974
+ ReleaseList: this.buildReleaseList(message.releaseList, message.trackReleaseList),
975
+ DealList: this.buildDealList(message.dealList)
976
+ } };
977
+ return `<?xml version="1.0" encoding="UTF-8"?>\n${new XMLBuilder(BUILDER_OPTIONS).build(root)}`.trimEnd();
978
+ }
979
+ buildMessageHeader(header) {
980
+ return {
981
+ ...header.messageThreadId ? { MessageThreadId: header.messageThreadId } : {},
982
+ MessageId: header.messageId,
983
+ ...header.messageFileName ? { MessageFileName: header.messageFileName } : {},
984
+ MessageSender: this.buildMessageParty(header.messageSender),
985
+ MessageRecipient: this.buildMessageParty(header.messageRecipient),
986
+ MessageCreatedDateTime: header.messageCreatedDateTime
987
+ };
988
+ }
989
+ buildMessageParty(party) {
990
+ const result = {};
991
+ if (party.partyId !== void 0) result.PartyId = party.partyId || "";
992
+ if (party.fullName) result.PartyName = { FullName: party.fullName };
993
+ return result;
994
+ }
995
+ buildPartyList(parties) {
996
+ if (parties.length === 0) return {};
997
+ return { Party: parties.map((p) => this.buildParty(p)) };
998
+ }
999
+ buildParty(party) {
1000
+ const result = {};
1001
+ result.PartyReference = party.partyReference;
1002
+ if (party.partyName?.length) result.PartyName = party.partyName.map((pn) => {
1003
+ const r = {};
1004
+ if (pn.languageAndScriptCode) r["@_LanguageAndScriptCode"] = pn.languageAndScriptCode;
1005
+ r.FullName = pn.fullName;
1006
+ if (pn.fullNameIndexed) r.FullNameIndexed = pn.fullNameIndexed;
1007
+ return r;
1008
+ });
1009
+ if (party.partyId?.length) result.PartyId = party.partyId.map((id) => id);
1010
+ return result;
1011
+ }
1012
+ buildResourceList(soundRecordings, _version) {
1013
+ return { SoundRecording: soundRecordings.map((sr) => this.buildSoundRecording(sr)) };
1014
+ }
1015
+ buildSoundRecording(sr) {
1016
+ const result = {};
1017
+ result.ResourceReference = sr.resourceReference;
1018
+ if (sr.type) result.Type = sr.type;
1019
+ if (sr.soundRecordingId) result.ResourceId = this.buildSoundRecordingId(sr.soundRecordingId);
1020
+ if (sr.displayTitleText) result.DisplayTitleText = sr.displayTitleText;
1021
+ if (sr.displayTitles) result.DisplayTitle = sr.displayTitles.map((t) => this.buildDisplayTitle(t));
1022
+ if (sr.displayArtists.length > 0) result.DisplayArtist = sr.displayArtists.map((a) => this.buildDisplayArtist(a));
1023
+ if (sr.contributors) result.Contributor = sr.contributors.map((c) => this.buildContributor(c));
1024
+ if (sr.pLine) result.PLine = this.buildPLine(sr.pLine);
1025
+ if (sr.duration) result.Duration = sr.duration;
1026
+ if (sr.languageOfPerformance) result.LanguageOfPerformance = sr.languageOfPerformance;
1027
+ return result;
1028
+ }
1029
+ buildSoundRecordingId(id) {
1030
+ if (!id) return {};
1031
+ const result = {};
1032
+ if (id.isrc) result.ISRC = id.isrc;
1033
+ if (id.catalogNumber) result.CatalogNumber = id.catalogNumber;
1034
+ return result;
1035
+ }
1036
+ buildReleaseList(releases, trackReleases) {
1037
+ const result = {};
1038
+ result.Release = releases.map((r) => this.buildRelease(r));
1039
+ if (trackReleases?.length) result.TrackRelease = trackReleases.map((tr) => this.buildTrackRelease(tr));
1040
+ return result;
1041
+ }
1042
+ buildRelease(r) {
1043
+ const result = {};
1044
+ result.ReleaseReference = r.releaseReference;
1045
+ if (r.releaseType) result.ReleaseType = r.releaseType;
1046
+ if (r.releaseId) result.ReleaseId = this.buildReleaseId(r.releaseId);
1047
+ if (r.displayTitleText) result.DisplayTitleText = r.displayTitleText;
1048
+ if (r.displayTitles) result.DisplayTitle = r.displayTitles.map((t) => this.buildDisplayTitle(t));
1049
+ if (r.displayArtists.length > 0) result.DisplayArtist = r.displayArtists.map((a) => this.buildDisplayArtist(a));
1050
+ if (r.releaseLabelReferences) result.ReleaseLabelReference = r.releaseLabelReferences;
1051
+ if (r.pLine) result.PLine = this.buildPLine(r.pLine);
1052
+ if (r.cLine) result.CLine = this.buildCLine(r.cLine);
1053
+ if (r.duration) result.Duration = r.duration;
1054
+ if (r.genre) result.Genre = this.buildGenre(r.genre);
1055
+ if (r.parentalWarningType) result.ParentalWarningType = r.parentalWarningType;
1056
+ if (r.resourceGroup) result.ResourceGroup = this.buildResourceGroup(r.resourceGroup);
1057
+ return result;
1058
+ }
1059
+ buildReleaseId(id) {
1060
+ if (!id) return {};
1061
+ const result = {};
1062
+ if (id.icpn) result.ICPN = id.icpn;
1063
+ if (id.isrc) result.ISRC = id.isrc;
1064
+ if (id.gridOrIcpn) result.GRid = id.gridOrIcpn;
1065
+ if (id.proprietaryId) result.ProprietaryId = id.proprietaryId;
1066
+ if (id.catalogNumber) result.CatalogNumber = id.catalogNumber;
1067
+ return result;
1068
+ }
1069
+ buildTrackRelease(tr) {
1070
+ const result = {};
1071
+ result.ReleaseReference = tr.releaseReference;
1072
+ if (tr.releaseId) result.ReleaseId = this.buildReleaseId(tr.releaseId);
1073
+ if (tr.displayTitles) result.DisplayTitle = tr.displayTitles.map((t) => this.buildDisplayTitle(t));
1074
+ result.ReleaseResourceReference = tr.releaseResourceReference;
1075
+ if (tr.releaseLabelReferences) result.ReleaseLabelReference = tr.releaseLabelReferences;
1076
+ if (tr.genre) result.Genre = this.buildGenre(tr.genre);
1077
+ return result;
1078
+ }
1079
+ buildResourceGroup(rg) {
1080
+ const result = {};
1081
+ if (rg.title) result.AdditionalTitle = { TitleText: rg.title };
1082
+ if (rg.sequenceNumber != null) result.SequenceNumber = String(rg.sequenceNumber);
1083
+ if (rg.resourceGroups) result.ResourceGroup = rg.resourceGroups.map((g) => this.buildResourceGroup(g));
1084
+ if (rg.resourceGroupContentItems) result.ResourceGroupContentItem = rg.resourceGroupContentItems.map((item) => this.buildResourceGroupContentItem(item));
1085
+ return result;
1086
+ }
1087
+ buildResourceGroupContentItem(item) {
1088
+ const result = {};
1089
+ if (item.sequenceNumber != null) result.SequenceNumber = String(item.sequenceNumber);
1090
+ if (item.resourceType) result.ResourceType = item.resourceType;
1091
+ result.ReleaseResourceReference = this.buildReleaseResourceReference(item.releaseResourceReference);
1092
+ return result;
1093
+ }
1094
+ buildReleaseResourceReference(ref) {
1095
+ if (ref.releaseResourceType) return {
1096
+ "#text": ref.value,
1097
+ "@_ReleaseResourceType": ref.releaseResourceType
1098
+ };
1099
+ return ref.value;
1100
+ }
1101
+ buildDealList(deals) {
1102
+ return { ReleaseDeal: deals.map((rd) => this.buildReleaseDeal(rd)) };
1103
+ }
1104
+ buildReleaseDeal(rd) {
1105
+ const result = {};
1106
+ result.DealReleaseReference = rd.dealReleaseReferences;
1107
+ result.Deal = rd.deals.map((d) => this.buildDeal(d));
1108
+ if (rd.effectiveDate) result.EffectiveDate = rd.effectiveDate;
1109
+ return result;
1110
+ }
1111
+ buildDeal(deal) {
1112
+ const result = {};
1113
+ if (deal.dealReference) result.DealReference = deal.dealReference;
1114
+ result.DealTerms = this.buildDealTerms(deal.dealTerms);
1115
+ return result;
1116
+ }
1117
+ buildDealTerms(dt) {
1118
+ const result = {};
1119
+ if (dt.territoryCode) result.TerritoryCode = dt.territoryCode;
1120
+ if (dt.validityPeriod) {
1121
+ const vp = {};
1122
+ if (dt.validityPeriod.startDate) vp.StartDate = dt.validityPeriod.startDate;
1123
+ if (dt.validityPeriod.endDate) vp.EndDate = dt.validityPeriod.endDate;
1124
+ result.ValidityPeriod = vp;
1125
+ }
1126
+ if (dt.commercialModelType) result.CommercialModelType = dt.commercialModelType;
1127
+ if (dt.useTypes) result.UseType = dt.useTypes;
1128
+ return result;
1129
+ }
1130
+ buildDisplayArtist(da) {
1131
+ const result = {};
1132
+ if (da.sequenceNumber != null) result["@_SequenceNumber"] = String(da.sequenceNumber);
1133
+ if (da.artist.partyReference) result.ArtistPartyReference = da.artist.partyReference;
1134
+ if (da.artist.roles?.length) result.DisplayArtistRole = da.artist.roles.length === 1 ? da.artist.roles[0] : da.artist.roles;
1135
+ return result;
1136
+ }
1137
+ buildContributor(c) {
1138
+ const result = {};
1139
+ if (c.sequenceNumber != null) result["@_SequenceNumber"] = String(c.sequenceNumber);
1140
+ result.ContributorPartyReference = c.contributorPartyReference;
1141
+ result.Role = c.role;
1142
+ return result;
1143
+ }
1144
+ buildDisplayTitle(t) {
1145
+ const result = {};
1146
+ if (t.applicableTerritoryCode) result["@_ApplicableTerritoryCode"] = t.applicableTerritoryCode;
1147
+ if (t.languageAndScriptCode) result["@_LanguageAndScriptCode"] = t.languageAndScriptCode;
1148
+ if (t.isDefault) result["@_IsDefault"] = "true";
1149
+ result.TitleText = t.titleText;
1150
+ if (t.subTitle) result.SubTitle = t.subTitle;
1151
+ return result;
1152
+ }
1153
+ buildPLine(p) {
1154
+ const result = {};
1155
+ if (p.year) result.Year = p.year;
1156
+ result.PLineText = p.pLineText;
1157
+ return result;
1158
+ }
1159
+ buildCLine(c) {
1160
+ const result = {};
1161
+ if (c.year) result.Year = c.year;
1162
+ result.CLineText = c.cLineText;
1163
+ return result;
1164
+ }
1165
+ buildGenre(g) {
1166
+ const result = {};
1167
+ result.GenreText = g.genreText;
1168
+ if (g.subGenre) result.SubGenre = g.subGenre;
1169
+ return result;
1170
+ }
1171
+ };
1172
+ //#endregion
1173
+ //#region src/converter/converter-factory.ts
1174
+ var ConverterFactory = class {
1175
+ constructor() {}
1176
+ static createXmlToJsonConverter(version) {
1177
+ switch (getMajorVersion(version)) {
1178
+ case "3.8": return new Ern38Converter();
1179
+ case "4": return new Ern4Converter();
1180
+ }
1181
+ }
1182
+ static createJsonToXmlBuilder(version) {
1183
+ switch (getMajorVersion(version)) {
1184
+ case "3.8": return new Ern38Builder();
1185
+ case "4": return new Ern4Builder();
1186
+ }
1187
+ }
1188
+ };
1189
+ //#endregion
1190
+ //#region src/converter/xml-to-json/index.ts
1191
+ /**
1192
+ * XML文字列をDdexMessageに変換する
1193
+ */
1194
+ function xmlToJson(xml) {
1195
+ const version = detectVersion(xml);
1196
+ const parsed = new XMLParser(PARSER_OPTIONS).parse(xml);
1197
+ return ConverterFactory.createXmlToJsonConverter(version).convert(parsed, version);
1198
+ }
1199
+ //#endregion
1200
+ //#region src/converter/json-to-xml/index.ts
1201
+ /**
1202
+ * DdexMessageをXML文字列に変換する
1203
+ */
1204
+ function jsonToXml(message, version) {
1205
+ const targetVersion = version ?? message.ernVersion;
1206
+ return ConverterFactory.createJsonToXmlBuilder(targetVersion).build(message, targetVersion);
1207
+ }
1208
+ //#endregion
1209
+ export { detectVersion, jsonToXml, xmlToJson };