@biblioteksentralen/marc 0.1.1 → 0.2.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/README.md CHANGED
@@ -100,3 +100,7 @@ const ajv = new Ajv();
100
100
  const validate = ajv.compile(schema);
101
101
  const result = validate(record.toJSON());
102
102
  ```
103
+
104
+ ## Changelog
105
+
106
+ - 0.2.0: Removed the logger argument from `MarcRecord.fromJSON()`.
package/dist/index.cjs CHANGED
@@ -59,8 +59,14 @@ var DataField = class {
59
59
  subfields: this.subfields.map((subfield) => subfield.toJSON())
60
60
  };
61
61
  }
62
+ /**
63
+ * Returns a human-readable string representation of this MARC data field.
64
+ *
65
+ * The result is intended for debugging, logging, and test output. The format is not guaranteed to
66
+ * be stable and should not be parsed or relied upon.
67
+ */
62
68
  toString() {
63
- return `${this.tag} ${this.subfields.map((subfield) => subfield.toString()).join(" ")}`;
69
+ return `${this.tag} ${this.ind1 ?? " "}${this.ind2 ?? " "} ${this.subfields.map((subfield) => subfield.toString()).join(" ")}`;
64
70
  }
65
71
  };
66
72
  var isControlField = (field) => field instanceof ControlField;
@@ -180,9 +186,10 @@ function createMarcSchema({
180
186
 
181
187
  // src/marc-record/errors.ts
182
188
  var MarcRecordSchemaValidationError = class extends Error {
183
- constructor(errors) {
189
+ constructor(errors, sourceData) {
184
190
  super("MarcRecord schema validation failed");
185
191
  this.errors = errors;
192
+ this.sourceData = sourceData;
186
193
  }
187
194
  };
188
195
  var MarcParseError = class extends Error {
@@ -191,6 +198,80 @@ var MarcParseError = class extends Error {
191
198
  this.record = record;
192
199
  }
193
200
  };
201
+ function buildRecordXml(input) {
202
+ const fields = [
203
+ xmlUtils.createXmlElement("leader", { text: input.leader }),
204
+ ...input.getControlFields().map(
205
+ (field) => xmlUtils.createXmlElement("controlfield", {
206
+ attributes: { tag: field.tag },
207
+ text: field.value
208
+ })
209
+ ),
210
+ ...input.getDataFields().map(
211
+ (field) => xmlUtils.createXmlElement("datafield", {
212
+ attributes: withoutEmptyValues({
213
+ tag: field.tag,
214
+ ind1: field.ind1,
215
+ ind2: field.ind2
216
+ }),
217
+ children: field.subfields.map(
218
+ (subfield) => xmlUtils.createXmlElement("subfield", {
219
+ attributes: { code: subfield.code },
220
+ text: subfield.value
221
+ })
222
+ )
223
+ })
224
+ )
225
+ ];
226
+ const recordNode = xmlUtils.createXmlElement("record", {
227
+ children: fields
228
+ });
229
+ return recordNode;
230
+ }
231
+ function serializeMarcXml(input, pretty = false) {
232
+ const record = buildRecordXml(input);
233
+ record.setAttribute("xmlns", "http://www.loc.gov/MARC21/slim");
234
+ return xmlUtils.serializeXml(record, pretty);
235
+ }
236
+ var withoutEmptyValues = (obj) => Object.keys(obj).reduce(
237
+ (acc, key) => obj[key] === void 0 ? { ...acc } : { ...acc, [key]: obj[key] },
238
+ {}
239
+ );
240
+ function serializeMarcXmlCollection(input, pretty = false) {
241
+ const records = input.map(buildRecordXml);
242
+ const collectionNode = xmlUtils.createXmlElement("collection", {
243
+ attributes: { xmlns: "http://www.loc.gov/MARC21/slim" },
244
+ children: records
245
+ });
246
+ return xmlUtils.serializeXml(collectionNode, pretty);
247
+ }
248
+
249
+ // src/marc-record/serializeLineMarc.ts
250
+ function serializeLineMarc(input) {
251
+ const leader = serializer.leader(input.leader);
252
+ const control = input.getControlFields().map(serializer.controlfield).join("");
253
+ const data = input.getDataFields().map(serializer.datafield).join("");
254
+ return `${leader}${control}${data}^
255
+ `;
256
+ }
257
+ var serializer = {
258
+ leader: (leader) => `*LDR${leader}
259
+ `,
260
+ controlfield: (field) => `*${field.tag}${field.value}
261
+ `,
262
+ datafield: (field) => {
263
+ const ind1 = field.ind1 ?? " ";
264
+ const ind2 = field.ind2 ?? " ";
265
+ const subfields = field.subfields.map(
266
+ (subfield) => `$${subfield.code}${escapeSubfieldValue(subfield.value)}`
267
+ ).join("");
268
+ return `*${field.tag}${ind1}${ind2}${subfields}
269
+ `;
270
+ }
271
+ };
272
+ var escapeSubfieldValue = (value) => {
273
+ return value.replace(/\n/g, " ").replace(/\$/g, "@{2}");
274
+ };
194
275
 
195
276
  // src/marc-record/MarcRecord.ts
196
277
  var validator = new ajv.Ajv().compile(createMarcSchema());
@@ -207,10 +288,9 @@ var MarcRecord = class _MarcRecord {
207
288
  this.leader = leader;
208
289
  this.fields = fields;
209
290
  }
210
- static fromJSON(data, log) {
291
+ static fromJSON(data) {
211
292
  const { format, leader, fields } = this.validateJSON(
212
- fixInvalidMarcRecordSerialization(data),
213
- log
293
+ fixInvalidMarcRecordSerialization(data)
214
294
  );
215
295
  return new _MarcRecord({
216
296
  leader,
@@ -227,17 +307,23 @@ var MarcRecord = class _MarcRecord {
227
307
  fields: this.fields.map((field) => field.toJSON())
228
308
  };
229
309
  }
230
- static validateJSON(data, log) {
310
+ toXML(pretty = false) {
311
+ return serializeMarcXml(this, pretty);
312
+ }
313
+ toXmlElement() {
314
+ return buildRecordXml(this);
315
+ }
316
+ toLineMarc() {
317
+ return serializeLineMarc(this);
318
+ }
319
+ static validateJSON(data) {
231
320
  if (validator(data)) {
232
321
  return data;
233
322
  }
234
- log.error(
235
- `MarcRecord validation failed:
236
- ${validator.errors ? JSON.stringify(validator.errors) : "Unknown error"}.
237
- Data:
238
- ${JSON.stringify(data)}`
323
+ throw new MarcRecordSchemaValidationError(
324
+ validator.errors ?? [],
325
+ JSON.stringify(data)
239
326
  );
240
- throw new MarcRecordSchemaValidationError(validator.errors ?? []);
241
327
  }
242
328
  getControlFields() {
243
329
  return this.fields.filter(isControlField);
@@ -382,80 +468,6 @@ var marcRecordZodSchema = zod.z.object({
382
468
  fields: zod.z.array(zod.z.union([controlFieldSchema, dataFieldSchema]))
383
469
  });
384
470
 
385
- // src/marc-record/serializeLineMarc.ts
386
- function serializeLineMarc(input) {
387
- const leader = serializer.leader(input.leader);
388
- const control = input.getControlFields().map(serializer.controlfield).join("");
389
- const data = input.getDataFields().map(serializer.datafield).join("");
390
- return `${leader}${control}${data}^
391
- `;
392
- }
393
- var serializer = {
394
- leader: (leader) => `*LDR${leader}
395
- `,
396
- controlfield: (field) => `*${field.tag}${field.value}
397
- `,
398
- datafield: (field) => {
399
- const ind1 = field.ind1 ?? " ";
400
- const ind2 = field.ind2 ?? " ";
401
- const subfields = field.subfields.map(
402
- (subfield) => `$${subfield.code}${escapeSubfieldValue(subfield.value)}`
403
- ).join("");
404
- return `*${field.tag}${ind1}${ind2}${subfields}
405
- `;
406
- }
407
- };
408
- var escapeSubfieldValue = (value) => {
409
- return value.replace(/\n/g, " ").replace(/\$/g, "@{2}");
410
- };
411
- function buildRecordXml(input) {
412
- const fields = [
413
- xmlUtils.createXmlElement("leader", { text: input.leader }),
414
- ...input.getControlFields().map(
415
- (field) => xmlUtils.createXmlElement("controlfield", {
416
- attributes: { tag: field.tag },
417
- text: field.value
418
- })
419
- ),
420
- ...input.getDataFields().map(
421
- (field) => xmlUtils.createXmlElement("datafield", {
422
- attributes: withoutEmptyValues({
423
- tag: field.tag,
424
- ind1: field.ind1,
425
- ind2: field.ind2
426
- }),
427
- children: field.subfields.map(
428
- (subfield) => xmlUtils.createXmlElement("subfield", {
429
- attributes: { code: subfield.code },
430
- text: subfield.value
431
- })
432
- )
433
- })
434
- )
435
- ];
436
- const recordNode = xmlUtils.createXmlElement("record", {
437
- children: fields
438
- });
439
- return recordNode;
440
- }
441
- function serializeMarcXml(input, pretty = false) {
442
- const record = buildRecordXml(input);
443
- record.setAttribute("xmlns", "http://www.loc.gov/MARC21/slim");
444
- return xmlUtils.serializeXml(record, pretty);
445
- }
446
- var withoutEmptyValues = (obj) => Object.keys(obj).reduce(
447
- (acc, key) => obj[key] === void 0 ? { ...acc } : { ...acc, [key]: obj[key] },
448
- {}
449
- );
450
- function serializeMarcXmlCollection(input, pretty = false) {
451
- const records = input.map(buildRecordXml);
452
- const collectionNode = xmlUtils.createXmlElement("collection", {
453
- attributes: { xmlns: "http://www.loc.gov/MARC21/slim" },
454
- children: records
455
- });
456
- return xmlUtils.serializeXml(collectionNode, pretty);
457
- }
458
-
459
471
  exports.ControlField = ControlField;
460
472
  exports.DataField = DataField;
461
473
  exports.MarcParseError = MarcParseError;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { XmlElement } from '@biblioteksentralen/xml-utils';
2
- import { Logger } from 'ts-log';
3
2
  import { z } from 'zod';
4
3
  import { ErrorObject } from 'ajv';
5
4
 
@@ -42,6 +41,12 @@ declare class DataField {
42
41
  getFirstSubfield(code: string | RegExp): Subfield | undefined;
43
42
  getFirstSubfieldValue(code: string | RegExp): string | undefined;
44
43
  toJSON(): SerializedDataField;
44
+ /**
45
+ * Returns a human-readable string representation of this MARC data field.
46
+ *
47
+ * The result is intended for debugging, logging, and test output. The format is not guaranteed to
48
+ * be stable and should not be parsed or relied upon.
49
+ */
45
50
  toString(): string;
46
51
  }
47
52
  type MarcField = ControlField | DataField;
@@ -75,9 +80,12 @@ declare class MarcRecord {
75
80
  fields: MarcField[];
76
81
  format?: string;
77
82
  });
78
- static fromJSON(data: unknown, log: Logger): MarcRecord;
83
+ static fromJSON(data: unknown): MarcRecord;
79
84
  toJSON(): SerializedMarcRecord;
80
- static validateJSON(data: unknown, log: Logger): SerializedMarcRecord;
85
+ toXML(pretty?: boolean): string;
86
+ toXmlElement(): XmlElement;
87
+ toLineMarc(): string;
88
+ static validateJSON(data: unknown): SerializedMarcRecord;
81
89
  getControlFields(): ControlField[];
82
90
  getControlField(tag: string): ControlField | undefined;
83
91
  getDataFields(tag?: string | RegExp, indicators?: Indicators): DataField[];
@@ -210,7 +218,8 @@ declare function serializeMarcXmlCollection(input: MarcRecord[], pretty?: boolea
210
218
 
211
219
  declare class MarcRecordSchemaValidationError extends Error {
212
220
  readonly errors: ErrorObject[];
213
- constructor(errors: ErrorObject[]);
221
+ readonly sourceData?: string | undefined;
222
+ constructor(errors: ErrorObject[], sourceData?: string | undefined);
214
223
  }
215
224
  declare class MarcParseError extends Error {
216
225
  readonly record: string;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { XmlElement } from '@biblioteksentralen/xml-utils';
2
- import { Logger } from 'ts-log';
3
2
  import { z } from 'zod';
4
3
  import { ErrorObject } from 'ajv';
5
4
 
@@ -42,6 +41,12 @@ declare class DataField {
42
41
  getFirstSubfield(code: string | RegExp): Subfield | undefined;
43
42
  getFirstSubfieldValue(code: string | RegExp): string | undefined;
44
43
  toJSON(): SerializedDataField;
44
+ /**
45
+ * Returns a human-readable string representation of this MARC data field.
46
+ *
47
+ * The result is intended for debugging, logging, and test output. The format is not guaranteed to
48
+ * be stable and should not be parsed or relied upon.
49
+ */
45
50
  toString(): string;
46
51
  }
47
52
  type MarcField = ControlField | DataField;
@@ -75,9 +80,12 @@ declare class MarcRecord {
75
80
  fields: MarcField[];
76
81
  format?: string;
77
82
  });
78
- static fromJSON(data: unknown, log: Logger): MarcRecord;
83
+ static fromJSON(data: unknown): MarcRecord;
79
84
  toJSON(): SerializedMarcRecord;
80
- static validateJSON(data: unknown, log: Logger): SerializedMarcRecord;
85
+ toXML(pretty?: boolean): string;
86
+ toXmlElement(): XmlElement;
87
+ toLineMarc(): string;
88
+ static validateJSON(data: unknown): SerializedMarcRecord;
81
89
  getControlFields(): ControlField[];
82
90
  getControlField(tag: string): ControlField | undefined;
83
91
  getDataFields(tag?: string | RegExp, indicators?: Indicators): DataField[];
@@ -210,7 +218,8 @@ declare function serializeMarcXmlCollection(input: MarcRecord[], pretty?: boolea
210
218
 
211
219
  declare class MarcRecordSchemaValidationError extends Error {
212
220
  readonly errors: ErrorObject[];
213
- constructor(errors: ErrorObject[]);
221
+ readonly sourceData?: string | undefined;
222
+ constructor(errors: ErrorObject[], sourceData?: string | undefined);
214
223
  }
215
224
  declare class MarcParseError extends Error {
216
225
  readonly record: string;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { parseXml, serializeXml, createXmlElement } from '@biblioteksentralen/xml-utils';
1
+ import { serializeXml, createXmlElement, parseXml } from '@biblioteksentralen/xml-utils';
2
2
  import { Ajv } from 'ajv';
3
3
  import { z } from 'zod';
4
4
 
@@ -57,8 +57,14 @@ var DataField = class {
57
57
  subfields: this.subfields.map((subfield) => subfield.toJSON())
58
58
  };
59
59
  }
60
+ /**
61
+ * Returns a human-readable string representation of this MARC data field.
62
+ *
63
+ * The result is intended for debugging, logging, and test output. The format is not guaranteed to
64
+ * be stable and should not be parsed or relied upon.
65
+ */
60
66
  toString() {
61
- return `${this.tag} ${this.subfields.map((subfield) => subfield.toString()).join(" ")}`;
67
+ return `${this.tag} ${this.ind1 ?? " "}${this.ind2 ?? " "} ${this.subfields.map((subfield) => subfield.toString()).join(" ")}`;
62
68
  }
63
69
  };
64
70
  var isControlField = (field) => field instanceof ControlField;
@@ -178,9 +184,10 @@ function createMarcSchema({
178
184
 
179
185
  // src/marc-record/errors.ts
180
186
  var MarcRecordSchemaValidationError = class extends Error {
181
- constructor(errors) {
187
+ constructor(errors, sourceData) {
182
188
  super("MarcRecord schema validation failed");
183
189
  this.errors = errors;
190
+ this.sourceData = sourceData;
184
191
  }
185
192
  };
186
193
  var MarcParseError = class extends Error {
@@ -189,6 +196,80 @@ var MarcParseError = class extends Error {
189
196
  this.record = record;
190
197
  }
191
198
  };
199
+ function buildRecordXml(input) {
200
+ const fields = [
201
+ createXmlElement("leader", { text: input.leader }),
202
+ ...input.getControlFields().map(
203
+ (field) => createXmlElement("controlfield", {
204
+ attributes: { tag: field.tag },
205
+ text: field.value
206
+ })
207
+ ),
208
+ ...input.getDataFields().map(
209
+ (field) => createXmlElement("datafield", {
210
+ attributes: withoutEmptyValues({
211
+ tag: field.tag,
212
+ ind1: field.ind1,
213
+ ind2: field.ind2
214
+ }),
215
+ children: field.subfields.map(
216
+ (subfield) => createXmlElement("subfield", {
217
+ attributes: { code: subfield.code },
218
+ text: subfield.value
219
+ })
220
+ )
221
+ })
222
+ )
223
+ ];
224
+ const recordNode = createXmlElement("record", {
225
+ children: fields
226
+ });
227
+ return recordNode;
228
+ }
229
+ function serializeMarcXml(input, pretty = false) {
230
+ const record = buildRecordXml(input);
231
+ record.setAttribute("xmlns", "http://www.loc.gov/MARC21/slim");
232
+ return serializeXml(record, pretty);
233
+ }
234
+ var withoutEmptyValues = (obj) => Object.keys(obj).reduce(
235
+ (acc, key) => obj[key] === void 0 ? { ...acc } : { ...acc, [key]: obj[key] },
236
+ {}
237
+ );
238
+ function serializeMarcXmlCollection(input, pretty = false) {
239
+ const records = input.map(buildRecordXml);
240
+ const collectionNode = createXmlElement("collection", {
241
+ attributes: { xmlns: "http://www.loc.gov/MARC21/slim" },
242
+ children: records
243
+ });
244
+ return serializeXml(collectionNode, pretty);
245
+ }
246
+
247
+ // src/marc-record/serializeLineMarc.ts
248
+ function serializeLineMarc(input) {
249
+ const leader = serializer.leader(input.leader);
250
+ const control = input.getControlFields().map(serializer.controlfield).join("");
251
+ const data = input.getDataFields().map(serializer.datafield).join("");
252
+ return `${leader}${control}${data}^
253
+ `;
254
+ }
255
+ var serializer = {
256
+ leader: (leader) => `*LDR${leader}
257
+ `,
258
+ controlfield: (field) => `*${field.tag}${field.value}
259
+ `,
260
+ datafield: (field) => {
261
+ const ind1 = field.ind1 ?? " ";
262
+ const ind2 = field.ind2 ?? " ";
263
+ const subfields = field.subfields.map(
264
+ (subfield) => `$${subfield.code}${escapeSubfieldValue(subfield.value)}`
265
+ ).join("");
266
+ return `*${field.tag}${ind1}${ind2}${subfields}
267
+ `;
268
+ }
269
+ };
270
+ var escapeSubfieldValue = (value) => {
271
+ return value.replace(/\n/g, " ").replace(/\$/g, "@{2}");
272
+ };
192
273
 
193
274
  // src/marc-record/MarcRecord.ts
194
275
  var validator = new Ajv().compile(createMarcSchema());
@@ -205,10 +286,9 @@ var MarcRecord = class _MarcRecord {
205
286
  this.leader = leader;
206
287
  this.fields = fields;
207
288
  }
208
- static fromJSON(data, log) {
289
+ static fromJSON(data) {
209
290
  const { format, leader, fields } = this.validateJSON(
210
- fixInvalidMarcRecordSerialization(data),
211
- log
291
+ fixInvalidMarcRecordSerialization(data)
212
292
  );
213
293
  return new _MarcRecord({
214
294
  leader,
@@ -225,17 +305,23 @@ var MarcRecord = class _MarcRecord {
225
305
  fields: this.fields.map((field) => field.toJSON())
226
306
  };
227
307
  }
228
- static validateJSON(data, log) {
308
+ toXML(pretty = false) {
309
+ return serializeMarcXml(this, pretty);
310
+ }
311
+ toXmlElement() {
312
+ return buildRecordXml(this);
313
+ }
314
+ toLineMarc() {
315
+ return serializeLineMarc(this);
316
+ }
317
+ static validateJSON(data) {
229
318
  if (validator(data)) {
230
319
  return data;
231
320
  }
232
- log.error(
233
- `MarcRecord validation failed:
234
- ${validator.errors ? JSON.stringify(validator.errors) : "Unknown error"}.
235
- Data:
236
- ${JSON.stringify(data)}`
321
+ throw new MarcRecordSchemaValidationError(
322
+ validator.errors ?? [],
323
+ JSON.stringify(data)
237
324
  );
238
- throw new MarcRecordSchemaValidationError(validator.errors ?? []);
239
325
  }
240
326
  getControlFields() {
241
327
  return this.fields.filter(isControlField);
@@ -380,78 +466,4 @@ var marcRecordZodSchema = z.object({
380
466
  fields: z.array(z.union([controlFieldSchema, dataFieldSchema]))
381
467
  });
382
468
 
383
- // src/marc-record/serializeLineMarc.ts
384
- function serializeLineMarc(input) {
385
- const leader = serializer.leader(input.leader);
386
- const control = input.getControlFields().map(serializer.controlfield).join("");
387
- const data = input.getDataFields().map(serializer.datafield).join("");
388
- return `${leader}${control}${data}^
389
- `;
390
- }
391
- var serializer = {
392
- leader: (leader) => `*LDR${leader}
393
- `,
394
- controlfield: (field) => `*${field.tag}${field.value}
395
- `,
396
- datafield: (field) => {
397
- const ind1 = field.ind1 ?? " ";
398
- const ind2 = field.ind2 ?? " ";
399
- const subfields = field.subfields.map(
400
- (subfield) => `$${subfield.code}${escapeSubfieldValue(subfield.value)}`
401
- ).join("");
402
- return `*${field.tag}${ind1}${ind2}${subfields}
403
- `;
404
- }
405
- };
406
- var escapeSubfieldValue = (value) => {
407
- return value.replace(/\n/g, " ").replace(/\$/g, "@{2}");
408
- };
409
- function buildRecordXml(input) {
410
- const fields = [
411
- createXmlElement("leader", { text: input.leader }),
412
- ...input.getControlFields().map(
413
- (field) => createXmlElement("controlfield", {
414
- attributes: { tag: field.tag },
415
- text: field.value
416
- })
417
- ),
418
- ...input.getDataFields().map(
419
- (field) => createXmlElement("datafield", {
420
- attributes: withoutEmptyValues({
421
- tag: field.tag,
422
- ind1: field.ind1,
423
- ind2: field.ind2
424
- }),
425
- children: field.subfields.map(
426
- (subfield) => createXmlElement("subfield", {
427
- attributes: { code: subfield.code },
428
- text: subfield.value
429
- })
430
- )
431
- })
432
- )
433
- ];
434
- const recordNode = createXmlElement("record", {
435
- children: fields
436
- });
437
- return recordNode;
438
- }
439
- function serializeMarcXml(input, pretty = false) {
440
- const record = buildRecordXml(input);
441
- record.setAttribute("xmlns", "http://www.loc.gov/MARC21/slim");
442
- return serializeXml(record, pretty);
443
- }
444
- var withoutEmptyValues = (obj) => Object.keys(obj).reduce(
445
- (acc, key) => obj[key] === void 0 ? { ...acc } : { ...acc, [key]: obj[key] },
446
- {}
447
- );
448
- function serializeMarcXmlCollection(input, pretty = false) {
449
- const records = input.map(buildRecordXml);
450
- const collectionNode = createXmlElement("collection", {
451
- attributes: { xmlns: "http://www.loc.gov/MARC21/slim" },
452
- children: records
453
- });
454
- return serializeXml(collectionNode, pretty);
455
- }
456
-
457
469
  export { ControlField, DataField, MarcParseError, MarcRecord, MarcRecordSchemaValidationError, Subfield, createControlField, createDataField, marcRecordZodSchema, parseMarcXml, serializeLineMarc, serializeMarcXml, serializeMarcXmlCollection };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@biblioteksentralen/marc",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "MARC record parser and serializer",
@@ -26,7 +26,6 @@
26
26
  ],
27
27
  "dependencies": {
28
28
  "ajv": "^8.17.1",
29
- "ts-log": "^2.2.5",
30
29
  "zod": "^3.23.8",
31
30
  "@biblioteksentralen/xml-utils": "^0.0.3"
32
31
  },