@biblioteksentralen/marc 0.0.1 → 0.0.2
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 → index.cjs} +30 -103
- package/dist/index.d.cts +180 -0
- package/dist/index.d.ts +85 -48
- package/dist/index.js +21 -118
- package/package.json +19 -13
|
@@ -1,103 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
import xpath from 'xpath';
|
|
3
|
-
import Ajv from 'ajv';
|
|
1
|
+
'use strict';
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
var xmlUtils = require('@biblioteksentralen/xml-utils');
|
|
4
|
+
var ajv = require('ajv');
|
|
5
|
+
var zod = require('zod');
|
|
6
6
|
|
|
7
|
-
// src/
|
|
8
|
-
var NodeType = {
|
|
9
|
-
ELEMENT_NODE: 1,
|
|
10
|
-
ATTRIBUTE_NODE: 2,
|
|
11
|
-
TEXT_NODE: 3,
|
|
12
|
-
CDATA_SECTION_NODE: 4,
|
|
13
|
-
ENTITY_REFERENCE_NODE: 5,
|
|
14
|
-
ENTITY_NODE: 6,
|
|
15
|
-
PROCESSING_INSTRUCTION_NODE: 7,
|
|
16
|
-
COMMENT_NODE: 8,
|
|
17
|
-
DOCUMENT_NODE: 9,
|
|
18
|
-
DOCUMENT_TYPE_NODE: 1,
|
|
19
|
-
DOCUMENT_FRAGMENT_NODE: 1,
|
|
20
|
-
NOTATION_NODE: 1
|
|
21
|
-
};
|
|
22
|
-
var isNode = (value) => typeof value === "object" && value !== null && "nodeType" in value;
|
|
23
|
-
var isElementNode = (node) => isNode(node) && node.nodeType === NodeType.ELEMENT_NODE;
|
|
24
|
-
|
|
25
|
-
// src/xml-element/XmlElement.ts
|
|
26
|
-
var InvalidXml = class extends Error {
|
|
27
|
-
};
|
|
28
|
-
function parseXml(xmlText, { log = console, namespaces = {} } = {}) {
|
|
29
|
-
const errorHandler = (error) => {
|
|
30
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
31
|
-
throw new InvalidXml(
|
|
32
|
-
`Failed to parse XML response: "${xmlText}". Error: "${errorMsg}"`
|
|
33
|
-
);
|
|
34
|
-
};
|
|
35
|
-
const doc = new DOMParser({
|
|
36
|
-
errorHandler: {
|
|
37
|
-
warning: (msg) => log.warn(msg),
|
|
38
|
-
error: errorHandler,
|
|
39
|
-
fatalError: errorHandler
|
|
40
|
-
}
|
|
41
|
-
}).parseFromString(xmlText, "text/xml");
|
|
42
|
-
return new XmlElement(doc, namespaces);
|
|
43
|
-
}
|
|
44
|
-
var XmlElement = class _XmlElement {
|
|
45
|
-
node;
|
|
46
|
-
namespaces;
|
|
47
|
-
select;
|
|
48
|
-
constructor(node, namespaces = {}) {
|
|
49
|
-
this.node = node;
|
|
50
|
-
this.namespaces = namespaces;
|
|
51
|
-
this.select = xpath.useNamespaces(namespaces);
|
|
52
|
-
}
|
|
53
|
-
toString() {
|
|
54
|
-
return new XMLSerializer().serializeToString(this.node);
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Get the underlying Element node. Returns undefined if the underlying
|
|
58
|
-
* node is the root Document node.
|
|
59
|
-
*/
|
|
60
|
-
get element() {
|
|
61
|
-
return isElementNode(this.node) ? this.node : void 0;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Get namespaces used in XPath queries.
|
|
65
|
-
*/
|
|
66
|
-
getNamespaces() {
|
|
67
|
-
return this.namespaces;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Find anything (nodes, text, etc.) by xpath.
|
|
71
|
-
* @param {string} query - XPath query.
|
|
72
|
-
*/
|
|
73
|
-
query(query) {
|
|
74
|
-
return this.select(query, this.node);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Find element nodes by XPath query.
|
|
78
|
-
* @param {string} query - XPath query.
|
|
79
|
-
*/
|
|
80
|
-
elements(query) {
|
|
81
|
-
return this.query(query).filter(isElementNode).map((elementNode) => new _XmlElement(elementNode, this.namespaces));
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Get text content of the current node or the *first* result matched by an XPath query.
|
|
85
|
-
* @param {string} query - XPath query.
|
|
86
|
-
*/
|
|
87
|
-
text(query) {
|
|
88
|
-
if (!query) {
|
|
89
|
-
return this.node.textContent ? this.node.textContent : void 0;
|
|
90
|
-
}
|
|
91
|
-
return this.elements(query)[0]?.text();
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Get atribute value of the current node.
|
|
95
|
-
* @param {string} name - Attribute name
|
|
96
|
-
*/
|
|
97
|
-
attr(name) {
|
|
98
|
-
return isElementNode(this.node) ? this.node.getAttribute(name) : void 0;
|
|
99
|
-
}
|
|
100
|
-
};
|
|
7
|
+
// src/marc-record/parseMarcXml.ts
|
|
101
8
|
|
|
102
9
|
// src/marc-record/MarcField.ts
|
|
103
10
|
var Subfield = class {
|
|
@@ -272,6 +179,7 @@ function createMarcSchema({
|
|
|
272
179
|
}
|
|
273
180
|
|
|
274
181
|
// src/marc-record/MarcRecord.ts
|
|
182
|
+
var validator = new ajv.Ajv().compile(createMarcSchema());
|
|
275
183
|
var ValidationFailed = class extends Error {
|
|
276
184
|
constructor(errors) {
|
|
277
185
|
super("MarcRecord validation failed");
|
|
@@ -304,9 +212,6 @@ var MarcRecord = class _MarcRecord {
|
|
|
304
212
|
});
|
|
305
213
|
}
|
|
306
214
|
static validateJSON(data) {
|
|
307
|
-
const schema = createMarcSchema();
|
|
308
|
-
const ajv = new Ajv();
|
|
309
|
-
const validator = ajv.compile(schema);
|
|
310
215
|
if (validator(data)) {
|
|
311
216
|
return data;
|
|
312
217
|
}
|
|
@@ -373,7 +278,7 @@ function detectNamespace(input) {
|
|
|
373
278
|
// src/marc-record/parseMarcXml.ts
|
|
374
279
|
function parseMarcXml(input, options = {}) {
|
|
375
280
|
const namespace = options.namespace ?? detectNamespace(input);
|
|
376
|
-
const xmlRecord = parseXml(input, {
|
|
281
|
+
const xmlRecord = xmlUtils.parseXml(input, {
|
|
377
282
|
namespaces: {
|
|
378
283
|
marc: namespace
|
|
379
284
|
}
|
|
@@ -410,5 +315,27 @@ function parseMarcXml(input, options = {}) {
|
|
|
410
315
|
return new MarcRecord({ leader, fields, format: options.format });
|
|
411
316
|
});
|
|
412
317
|
}
|
|
318
|
+
var controlFieldSchema = zod.z.object({
|
|
319
|
+
tag: zod.z.string().length(3, "MARC tag must be three characters long"),
|
|
320
|
+
value: zod.z.string()
|
|
321
|
+
});
|
|
322
|
+
var dataFieldSchema = zod.z.object({
|
|
323
|
+
tag: zod.z.string().length(3, "MARC tag must be three characters long"),
|
|
324
|
+
ind1: zod.z.string().length(1, "indicator 1 must be one character long").optional(),
|
|
325
|
+
ind2: zod.z.string().length(1, "indicator 2 must be one character long").optional(),
|
|
326
|
+
subfields: zod.z.array(zod.z.object({ code: zod.z.string(), value: zod.z.string() }))
|
|
327
|
+
});
|
|
328
|
+
var marcRecordZodSchema = zod.z.object({
|
|
329
|
+
format: zod.z.string().optional(),
|
|
330
|
+
leader: zod.z.string(),
|
|
331
|
+
fields: zod.z.array(zod.z.union([controlFieldSchema, dataFieldSchema]))
|
|
332
|
+
});
|
|
413
333
|
|
|
414
|
-
|
|
334
|
+
exports.ControlField = ControlField;
|
|
335
|
+
exports.DataField = DataField;
|
|
336
|
+
exports.MarcRecord = MarcRecord;
|
|
337
|
+
exports.Subfield = Subfield;
|
|
338
|
+
exports.createControlField = createControlField;
|
|
339
|
+
exports.createDataField = createDataField;
|
|
340
|
+
exports.marcRecordZodSchema = marcRecordZodSchema;
|
|
341
|
+
exports.parseMarcXml = parseMarcXml;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
type SerializedMarcField = SerializedDataField | SerializedControlField;
|
|
4
|
+
interface SerializedControlField {
|
|
5
|
+
tag: string;
|
|
6
|
+
value: string;
|
|
7
|
+
}
|
|
8
|
+
interface SerializedDataField {
|
|
9
|
+
tag: string;
|
|
10
|
+
ind1?: string;
|
|
11
|
+
ind2?: string;
|
|
12
|
+
subfields: SerializedMarcSubfield[];
|
|
13
|
+
}
|
|
14
|
+
interface SerializedMarcSubfield {
|
|
15
|
+
code: string;
|
|
16
|
+
value: string;
|
|
17
|
+
}
|
|
18
|
+
declare class Subfield {
|
|
19
|
+
readonly code: string;
|
|
20
|
+
readonly value: string;
|
|
21
|
+
constructor(code: string, value: string);
|
|
22
|
+
toJSON(): SerializedMarcSubfield;
|
|
23
|
+
toString(): string;
|
|
24
|
+
}
|
|
25
|
+
declare class ControlField {
|
|
26
|
+
readonly tag: string;
|
|
27
|
+
readonly value: string;
|
|
28
|
+
constructor(tag: string, value: string);
|
|
29
|
+
toJSON(): SerializedControlField;
|
|
30
|
+
toString(): string;
|
|
31
|
+
}
|
|
32
|
+
declare class DataField {
|
|
33
|
+
readonly tag: string;
|
|
34
|
+
readonly ind1: string | undefined;
|
|
35
|
+
readonly ind2: string | undefined;
|
|
36
|
+
readonly subfields: Subfield[];
|
|
37
|
+
constructor(tag: string, ind1: string | undefined, ind2: string | undefined, subfields: Subfield[]);
|
|
38
|
+
getSubfields(code?: string | RegExp): Subfield[];
|
|
39
|
+
getFirstSubfield(code: string | RegExp): Subfield | undefined;
|
|
40
|
+
getFirstSubfieldValue(code: string | RegExp): string | undefined;
|
|
41
|
+
toJSON(): SerializedDataField;
|
|
42
|
+
toString(): string;
|
|
43
|
+
}
|
|
44
|
+
type MarcField = ControlField | DataField;
|
|
45
|
+
declare const createDataField: (field: SerializedDataField) => DataField;
|
|
46
|
+
declare const createControlField: (field: SerializedControlField) => ControlField;
|
|
47
|
+
|
|
48
|
+
type Indicators = {
|
|
49
|
+
ind1?: string;
|
|
50
|
+
ind2?: string;
|
|
51
|
+
};
|
|
52
|
+
interface SerializedMarcRecord {
|
|
53
|
+
/**
|
|
54
|
+
* Identifies the MARC format (examples: "MARC 21", "UNIMARC", "danMARC2", ...).
|
|
55
|
+
*/
|
|
56
|
+
format?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Corresponds to ISO 2709 record label, 24 bytes
|
|
59
|
+
*/
|
|
60
|
+
leader: string;
|
|
61
|
+
/**
|
|
62
|
+
* List of control fields and data fields.
|
|
63
|
+
*/
|
|
64
|
+
fields: SerializedMarcField[];
|
|
65
|
+
}
|
|
66
|
+
declare class MarcRecord {
|
|
67
|
+
readonly format: string | undefined;
|
|
68
|
+
readonly leader: string;
|
|
69
|
+
readonly fields: MarcField[];
|
|
70
|
+
constructor({ leader, fields, format, }: {
|
|
71
|
+
leader: string;
|
|
72
|
+
fields: MarcField[];
|
|
73
|
+
format?: string;
|
|
74
|
+
});
|
|
75
|
+
static fromJSON(data: unknown): MarcRecord;
|
|
76
|
+
static validateJSON(data: unknown): SerializedMarcRecord;
|
|
77
|
+
getControlFields(): ControlField[];
|
|
78
|
+
getControlField(tag: string): ControlField | undefined;
|
|
79
|
+
getDataFields(tag?: string | RegExp, indicators?: Indicators): DataField[];
|
|
80
|
+
getFirstDataField(tag: string | RegExp, indicators?: Indicators): DataField | undefined;
|
|
81
|
+
getSubfields(tag: string | RegExp, code: string | RegExp, indicators?: Indicators): Subfield[];
|
|
82
|
+
getSubfieldValues(tag: string | RegExp, code: string | RegExp, indicators?: Indicators): string[];
|
|
83
|
+
getFirstSubfieldValue(tag: string | RegExp, code: string | RegExp, indicators?: Indicators): string | undefined;
|
|
84
|
+
toJSON(): SerializedMarcRecord;
|
|
85
|
+
toString(): string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface MarcXmlOptions {
|
|
89
|
+
namespace?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Callback function to transform or filter control fields.
|
|
92
|
+
*/
|
|
93
|
+
processControlField?: (field: ControlField) => ControlField | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* Callback function to transform or filter data fields.
|
|
96
|
+
*/
|
|
97
|
+
processDataField?: (field: DataField) => DataField | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* Free-form string that specifies the MARC record flavour.
|
|
100
|
+
*/
|
|
101
|
+
format?: string;
|
|
102
|
+
}
|
|
103
|
+
declare function parseMarcXml(input: string, options?: MarcXmlOptions): MarcRecord[];
|
|
104
|
+
|
|
105
|
+
declare const marcRecordZodSchema: z.ZodObject<{
|
|
106
|
+
format: z.ZodOptional<z.ZodString>;
|
|
107
|
+
leader: z.ZodString;
|
|
108
|
+
fields: z.ZodArray<z.ZodUnion<[z.ZodObject<{
|
|
109
|
+
tag: z.ZodString;
|
|
110
|
+
value: z.ZodString;
|
|
111
|
+
}, "strip", z.ZodTypeAny, {
|
|
112
|
+
tag: string;
|
|
113
|
+
value: string;
|
|
114
|
+
}, {
|
|
115
|
+
tag: string;
|
|
116
|
+
value: string;
|
|
117
|
+
}>, z.ZodObject<{
|
|
118
|
+
tag: z.ZodString;
|
|
119
|
+
ind1: z.ZodOptional<z.ZodString>;
|
|
120
|
+
ind2: z.ZodOptional<z.ZodString>;
|
|
121
|
+
subfields: z.ZodArray<z.ZodObject<{
|
|
122
|
+
code: z.ZodString;
|
|
123
|
+
value: z.ZodString;
|
|
124
|
+
}, "strip", z.ZodTypeAny, {
|
|
125
|
+
value: string;
|
|
126
|
+
code: string;
|
|
127
|
+
}, {
|
|
128
|
+
value: string;
|
|
129
|
+
code: string;
|
|
130
|
+
}>, "many">;
|
|
131
|
+
}, "strip", z.ZodTypeAny, {
|
|
132
|
+
tag: string;
|
|
133
|
+
subfields: {
|
|
134
|
+
value: string;
|
|
135
|
+
code: string;
|
|
136
|
+
}[];
|
|
137
|
+
ind1?: string | undefined;
|
|
138
|
+
ind2?: string | undefined;
|
|
139
|
+
}, {
|
|
140
|
+
tag: string;
|
|
141
|
+
subfields: {
|
|
142
|
+
value: string;
|
|
143
|
+
code: string;
|
|
144
|
+
}[];
|
|
145
|
+
ind1?: string | undefined;
|
|
146
|
+
ind2?: string | undefined;
|
|
147
|
+
}>]>, "many">;
|
|
148
|
+
}, "strip", z.ZodTypeAny, {
|
|
149
|
+
fields: ({
|
|
150
|
+
tag: string;
|
|
151
|
+
value: string;
|
|
152
|
+
} | {
|
|
153
|
+
tag: string;
|
|
154
|
+
subfields: {
|
|
155
|
+
value: string;
|
|
156
|
+
code: string;
|
|
157
|
+
}[];
|
|
158
|
+
ind1?: string | undefined;
|
|
159
|
+
ind2?: string | undefined;
|
|
160
|
+
})[];
|
|
161
|
+
leader: string;
|
|
162
|
+
format?: string | undefined;
|
|
163
|
+
}, {
|
|
164
|
+
fields: ({
|
|
165
|
+
tag: string;
|
|
166
|
+
value: string;
|
|
167
|
+
} | {
|
|
168
|
+
tag: string;
|
|
169
|
+
subfields: {
|
|
170
|
+
value: string;
|
|
171
|
+
code: string;
|
|
172
|
+
}[];
|
|
173
|
+
ind1?: string | undefined;
|
|
174
|
+
ind2?: string | undefined;
|
|
175
|
+
})[];
|
|
176
|
+
leader: string;
|
|
177
|
+
format?: string | undefined;
|
|
178
|
+
}>;
|
|
179
|
+
|
|
180
|
+
export { ControlField, DataField, type MarcField, MarcRecord, type SerializedControlField, type SerializedDataField, type SerializedMarcRecord, Subfield, createControlField, createDataField, marcRecordZodSchema, parseMarcXml };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Logger } from 'ts-log';
|
|
1
|
+
import { z } from 'zod';
|
|
3
2
|
|
|
4
3
|
type SerializedMarcField = SerializedDataField | SerializedControlField;
|
|
5
4
|
interface SerializedControlField {
|
|
@@ -51,8 +50,17 @@ type Indicators = {
|
|
|
51
50
|
ind2?: string;
|
|
52
51
|
};
|
|
53
52
|
interface SerializedMarcRecord {
|
|
53
|
+
/**
|
|
54
|
+
* Identifies the MARC format (examples: "MARC 21", "UNIMARC", "danMARC2", ...).
|
|
55
|
+
*/
|
|
54
56
|
format?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Corresponds to ISO 2709 record label, 24 bytes
|
|
59
|
+
*/
|
|
55
60
|
leader: string;
|
|
61
|
+
/**
|
|
62
|
+
* List of control fields and data fields.
|
|
63
|
+
*/
|
|
56
64
|
fields: SerializedMarcField[];
|
|
57
65
|
}
|
|
58
66
|
declare class MarcRecord {
|
|
@@ -94,50 +102,79 @@ interface MarcXmlOptions {
|
|
|
94
102
|
}
|
|
95
103
|
declare function parseMarcXml(input: string, options?: MarcXmlOptions): MarcRecord[];
|
|
96
104
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
105
|
+
declare const marcRecordZodSchema: z.ZodObject<{
|
|
106
|
+
format: z.ZodOptional<z.ZodString>;
|
|
107
|
+
leader: z.ZodString;
|
|
108
|
+
fields: z.ZodArray<z.ZodUnion<[z.ZodObject<{
|
|
109
|
+
tag: z.ZodString;
|
|
110
|
+
value: z.ZodString;
|
|
111
|
+
}, "strip", z.ZodTypeAny, {
|
|
112
|
+
tag: string;
|
|
113
|
+
value: string;
|
|
114
|
+
}, {
|
|
115
|
+
tag: string;
|
|
116
|
+
value: string;
|
|
117
|
+
}>, z.ZodObject<{
|
|
118
|
+
tag: z.ZodString;
|
|
119
|
+
ind1: z.ZodOptional<z.ZodString>;
|
|
120
|
+
ind2: z.ZodOptional<z.ZodString>;
|
|
121
|
+
subfields: z.ZodArray<z.ZodObject<{
|
|
122
|
+
code: z.ZodString;
|
|
123
|
+
value: z.ZodString;
|
|
124
|
+
}, "strip", z.ZodTypeAny, {
|
|
125
|
+
value: string;
|
|
126
|
+
code: string;
|
|
127
|
+
}, {
|
|
128
|
+
value: string;
|
|
129
|
+
code: string;
|
|
130
|
+
}>, "many">;
|
|
131
|
+
}, "strip", z.ZodTypeAny, {
|
|
132
|
+
tag: string;
|
|
133
|
+
subfields: {
|
|
134
|
+
value: string;
|
|
135
|
+
code: string;
|
|
136
|
+
}[];
|
|
137
|
+
ind1?: string | undefined;
|
|
138
|
+
ind2?: string | undefined;
|
|
139
|
+
}, {
|
|
140
|
+
tag: string;
|
|
141
|
+
subfields: {
|
|
142
|
+
value: string;
|
|
143
|
+
code: string;
|
|
144
|
+
}[];
|
|
145
|
+
ind1?: string | undefined;
|
|
146
|
+
ind2?: string | undefined;
|
|
147
|
+
}>]>, "many">;
|
|
148
|
+
}, "strip", z.ZodTypeAny, {
|
|
149
|
+
fields: ({
|
|
150
|
+
tag: string;
|
|
151
|
+
value: string;
|
|
152
|
+
} | {
|
|
153
|
+
tag: string;
|
|
154
|
+
subfields: {
|
|
155
|
+
value: string;
|
|
156
|
+
code: string;
|
|
157
|
+
}[];
|
|
158
|
+
ind1?: string | undefined;
|
|
159
|
+
ind2?: string | undefined;
|
|
160
|
+
})[];
|
|
161
|
+
leader: string;
|
|
162
|
+
format?: string | undefined;
|
|
163
|
+
}, {
|
|
164
|
+
fields: ({
|
|
165
|
+
tag: string;
|
|
166
|
+
value: string;
|
|
167
|
+
} | {
|
|
168
|
+
tag: string;
|
|
169
|
+
subfields: {
|
|
170
|
+
value: string;
|
|
171
|
+
code: string;
|
|
172
|
+
}[];
|
|
173
|
+
ind1?: string | undefined;
|
|
174
|
+
ind2?: string | undefined;
|
|
175
|
+
})[];
|
|
176
|
+
leader: string;
|
|
177
|
+
format?: string | undefined;
|
|
178
|
+
}>;
|
|
142
179
|
|
|
143
|
-
export { ControlField, DataField, type MarcField, MarcRecord, type SerializedControlField, type SerializedDataField, type SerializedMarcRecord, Subfield,
|
|
180
|
+
export { ControlField, DataField, type MarcField, MarcRecord, type SerializedControlField, type SerializedDataField, type SerializedMarcRecord, Subfield, createControlField, createDataField, marcRecordZodSchema, parseMarcXml };
|
package/dist/index.js
CHANGED
|
@@ -1,110 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
import { parseXml } from '@biblioteksentralen/xml-utils';
|
|
2
|
+
import { Ajv } from 'ajv';
|
|
3
|
+
import { z } from 'zod';
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
var xpath = require('xpath');
|
|
5
|
-
var Ajv = require('ajv');
|
|
6
|
-
|
|
7
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
|
-
|
|
9
|
-
var xpath__default = /*#__PURE__*/_interopDefault(xpath);
|
|
10
|
-
var Ajv__default = /*#__PURE__*/_interopDefault(Ajv);
|
|
11
|
-
|
|
12
|
-
// src/xml-element/XmlElement.ts
|
|
13
|
-
|
|
14
|
-
// src/xml-element/NodeType.ts
|
|
15
|
-
var NodeType = {
|
|
16
|
-
ELEMENT_NODE: 1,
|
|
17
|
-
ATTRIBUTE_NODE: 2,
|
|
18
|
-
TEXT_NODE: 3,
|
|
19
|
-
CDATA_SECTION_NODE: 4,
|
|
20
|
-
ENTITY_REFERENCE_NODE: 5,
|
|
21
|
-
ENTITY_NODE: 6,
|
|
22
|
-
PROCESSING_INSTRUCTION_NODE: 7,
|
|
23
|
-
COMMENT_NODE: 8,
|
|
24
|
-
DOCUMENT_NODE: 9,
|
|
25
|
-
DOCUMENT_TYPE_NODE: 1,
|
|
26
|
-
DOCUMENT_FRAGMENT_NODE: 1,
|
|
27
|
-
NOTATION_NODE: 1
|
|
28
|
-
};
|
|
29
|
-
var isNode = (value) => typeof value === "object" && value !== null && "nodeType" in value;
|
|
30
|
-
var isElementNode = (node) => isNode(node) && node.nodeType === NodeType.ELEMENT_NODE;
|
|
31
|
-
|
|
32
|
-
// src/xml-element/XmlElement.ts
|
|
33
|
-
var InvalidXml = class extends Error {
|
|
34
|
-
};
|
|
35
|
-
function parseXml(xmlText, { log = console, namespaces = {} } = {}) {
|
|
36
|
-
const errorHandler = (error) => {
|
|
37
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
38
|
-
throw new InvalidXml(
|
|
39
|
-
`Failed to parse XML response: "${xmlText}". Error: "${errorMsg}"`
|
|
40
|
-
);
|
|
41
|
-
};
|
|
42
|
-
const doc = new xmldom.DOMParser({
|
|
43
|
-
errorHandler: {
|
|
44
|
-
warning: (msg) => log.warn(msg),
|
|
45
|
-
error: errorHandler,
|
|
46
|
-
fatalError: errorHandler
|
|
47
|
-
}
|
|
48
|
-
}).parseFromString(xmlText, "text/xml");
|
|
49
|
-
return new XmlElement(doc, namespaces);
|
|
50
|
-
}
|
|
51
|
-
var XmlElement = class _XmlElement {
|
|
52
|
-
node;
|
|
53
|
-
namespaces;
|
|
54
|
-
select;
|
|
55
|
-
constructor(node, namespaces = {}) {
|
|
56
|
-
this.node = node;
|
|
57
|
-
this.namespaces = namespaces;
|
|
58
|
-
this.select = xpath__default.default.useNamespaces(namespaces);
|
|
59
|
-
}
|
|
60
|
-
toString() {
|
|
61
|
-
return new xmldom.XMLSerializer().serializeToString(this.node);
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Get the underlying Element node. Returns undefined if the underlying
|
|
65
|
-
* node is the root Document node.
|
|
66
|
-
*/
|
|
67
|
-
get element() {
|
|
68
|
-
return isElementNode(this.node) ? this.node : void 0;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Get namespaces used in XPath queries.
|
|
72
|
-
*/
|
|
73
|
-
getNamespaces() {
|
|
74
|
-
return this.namespaces;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Find anything (nodes, text, etc.) by xpath.
|
|
78
|
-
* @param {string} query - XPath query.
|
|
79
|
-
*/
|
|
80
|
-
query(query) {
|
|
81
|
-
return this.select(query, this.node);
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Find element nodes by XPath query.
|
|
85
|
-
* @param {string} query - XPath query.
|
|
86
|
-
*/
|
|
87
|
-
elements(query) {
|
|
88
|
-
return this.query(query).filter(isElementNode).map((elementNode) => new _XmlElement(elementNode, this.namespaces));
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Get text content of the current node or the *first* result matched by an XPath query.
|
|
92
|
-
* @param {string} query - XPath query.
|
|
93
|
-
*/
|
|
94
|
-
text(query) {
|
|
95
|
-
if (!query) {
|
|
96
|
-
return this.node.textContent ? this.node.textContent : void 0;
|
|
97
|
-
}
|
|
98
|
-
return this.elements(query)[0]?.text();
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Get atribute value of the current node.
|
|
102
|
-
* @param {string} name - Attribute name
|
|
103
|
-
*/
|
|
104
|
-
attr(name) {
|
|
105
|
-
return isElementNode(this.node) ? this.node.getAttribute(name) : void 0;
|
|
106
|
-
}
|
|
107
|
-
};
|
|
5
|
+
// src/marc-record/parseMarcXml.ts
|
|
108
6
|
|
|
109
7
|
// src/marc-record/MarcField.ts
|
|
110
8
|
var Subfield = class {
|
|
@@ -279,6 +177,7 @@ function createMarcSchema({
|
|
|
279
177
|
}
|
|
280
178
|
|
|
281
179
|
// src/marc-record/MarcRecord.ts
|
|
180
|
+
var validator = new Ajv().compile(createMarcSchema());
|
|
282
181
|
var ValidationFailed = class extends Error {
|
|
283
182
|
constructor(errors) {
|
|
284
183
|
super("MarcRecord validation failed");
|
|
@@ -311,9 +210,6 @@ var MarcRecord = class _MarcRecord {
|
|
|
311
210
|
});
|
|
312
211
|
}
|
|
313
212
|
static validateJSON(data) {
|
|
314
|
-
const schema = createMarcSchema();
|
|
315
|
-
const ajv = new Ajv__default.default();
|
|
316
|
-
const validator = ajv.compile(schema);
|
|
317
213
|
if (validator(data)) {
|
|
318
214
|
return data;
|
|
319
215
|
}
|
|
@@ -417,13 +313,20 @@ function parseMarcXml(input, options = {}) {
|
|
|
417
313
|
return new MarcRecord({ leader, fields, format: options.format });
|
|
418
314
|
});
|
|
419
315
|
}
|
|
316
|
+
var controlFieldSchema = z.object({
|
|
317
|
+
tag: z.string().length(3, "MARC tag must be three characters long"),
|
|
318
|
+
value: z.string()
|
|
319
|
+
});
|
|
320
|
+
var dataFieldSchema = z.object({
|
|
321
|
+
tag: z.string().length(3, "MARC tag must be three characters long"),
|
|
322
|
+
ind1: z.string().length(1, "indicator 1 must be one character long").optional(),
|
|
323
|
+
ind2: z.string().length(1, "indicator 2 must be one character long").optional(),
|
|
324
|
+
subfields: z.array(z.object({ code: z.string(), value: z.string() }))
|
|
325
|
+
});
|
|
326
|
+
var marcRecordZodSchema = z.object({
|
|
327
|
+
format: z.string().optional(),
|
|
328
|
+
leader: z.string(),
|
|
329
|
+
fields: z.array(z.union([controlFieldSchema, dataFieldSchema]))
|
|
330
|
+
});
|
|
420
331
|
|
|
421
|
-
|
|
422
|
-
exports.DataField = DataField;
|
|
423
|
-
exports.MarcRecord = MarcRecord;
|
|
424
|
-
exports.Subfield = Subfield;
|
|
425
|
-
exports.XmlElement = XmlElement;
|
|
426
|
-
exports.createControlField = createControlField;
|
|
427
|
-
exports.createDataField = createDataField;
|
|
428
|
-
exports.parseMarcXml = parseMarcXml;
|
|
429
|
-
exports.parseXml = parseXml;
|
|
332
|
+
export { ControlField, DataField, MarcRecord, Subfield, createControlField, createDataField, marcRecordZodSchema, parseMarcXml };
|
package/package.json
CHANGED
|
@@ -1,34 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@biblioteksentralen/marc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"private": false,
|
|
5
|
+
"type": "module",
|
|
5
6
|
"description": "MARC record parser and serializer",
|
|
6
7
|
"author": "Biblioteksentralen",
|
|
7
8
|
"license": "MIT",
|
|
8
|
-
"main": "dist/index.
|
|
9
|
+
"main": "./dist/index.cjs",
|
|
10
|
+
"module": "./dist/index.js",
|
|
9
11
|
"types": "./dist/index.d.ts",
|
|
10
12
|
"exports": {
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
|
|
13
|
+
"import": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"require": {
|
|
18
|
+
"types": "./dist/index.d.cts",
|
|
19
|
+
"require": "./dist/index.cjs"
|
|
15
20
|
}
|
|
16
21
|
},
|
|
17
22
|
"files": [
|
|
18
23
|
"README.md",
|
|
19
24
|
"LICENSE",
|
|
20
|
-
"dist/**/*.{js,mjs,d.ts}"
|
|
25
|
+
"dist/**/*.{js,cjs,mjs,ts,d.ts,d.cts}"
|
|
21
26
|
],
|
|
22
27
|
"dependencies": {
|
|
23
|
-
"
|
|
24
|
-
"ajv": "^8.12.0",
|
|
28
|
+
"ajv": "^8.17.1",
|
|
25
29
|
"ts-log": "^2.2.5",
|
|
26
|
-
"
|
|
27
|
-
"
|
|
30
|
+
"zod": "^3.23.8",
|
|
31
|
+
"@biblioteksentralen/xml-utils": "^0.0.1"
|
|
28
32
|
},
|
|
29
33
|
"devDependencies": {
|
|
34
|
+
"@arethetypeswrong/cli": "^0.15.4",
|
|
30
35
|
"@types/json-schema": "^7.0.15",
|
|
31
|
-
"@types/node": "^
|
|
36
|
+
"@types/node": "^20.14.14",
|
|
32
37
|
"@vitest/coverage-v8": "^1.5.0",
|
|
33
38
|
"rimraf": "^5.0.5",
|
|
34
39
|
"tsup": "^8.0.2",
|
|
@@ -42,6 +47,7 @@
|
|
|
42
47
|
"test": "vitest run --poolOptions.threads.singleThread --reporter=verbose --coverage",
|
|
43
48
|
"test:watch": "vitest",
|
|
44
49
|
"clean": "rimraf dist",
|
|
45
|
-
"lint": "eslint ."
|
|
50
|
+
"lint": "eslint .",
|
|
51
|
+
"lint:package": "attw --pack"
|
|
46
52
|
}
|
|
47
53
|
}
|