isahaq-barcode 1.9.0 → 2.0.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/CHANGELOG.md +107 -0
- package/LICENSE +21 -0
- package/README.md +317 -553
- package/bin/generate.js +171 -134
- package/browser.js +163 -170
- package/index.d.ts +497 -0
- package/index.js +119 -51
- package/package.json +69 -41
- package/src/builders/QrCodeBuilder.js +328 -165
- package/src/encoders/BarcodeEncoder.js +260 -0
- package/src/renderers/HTMLRenderer.js +36 -169
- package/src/renderers/PDFRenderer.js +108 -130
- package/src/renderers/PNGRenderer.js +7 -83
- package/src/renderers/RenderFormats.js +89 -38
- package/src/renderers/SVGRenderer.js +8 -182
- package/src/services/BarcodeService.js +96 -36
- package/src/types/BarcodeTypes.js +535 -144
- package/src/validators/Validator.js +140 -122
- package/.eslintrc.js +0 -29
- package/.prettierignore +0 -11
- package/.prettierrc +0 -11
- package/eslint.config.js +0 -67
- package/examples/basic-usage.js +0 -58
- package/examples/batch-example.json +0 -56
- package/examples/express-server.js +0 -163
- package/jest.config.js +0 -13
- package/tests/BarcodeGenerator.test.js +0 -187
- package/tests/BarcodeService.test.js +0 -76
- package/tests/QrCodeBuilder.test.js +0 -130
- package/tests/setup.js +0 -59
- package/webpack.config.js +0 -26
|
@@ -1,28 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* PDF Renderer - Renders barcodes as PDF
|
|
2
|
+
* PDF Renderer - Renders barcodes as PDF documents
|
|
3
|
+
*
|
|
4
|
+
* The barcode itself is encoded as a real symbology (see BarcodeEncoder) and
|
|
5
|
+
* embedded as a lossless PNG image, so the PDF is scannable.
|
|
3
6
|
*/
|
|
4
7
|
|
|
5
8
|
const PDFDocument = require('pdfkit');
|
|
9
|
+
const { BarcodeEncoder } = require('../encoders/BarcodeEncoder');
|
|
6
10
|
|
|
7
11
|
class PDFRenderer {
|
|
8
12
|
constructor() {
|
|
9
13
|
this.defaultOptions = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
displayValue: true,
|
|
13
|
-
fontSize: 20,
|
|
14
|
-
textAlign: 'center',
|
|
15
|
-
textPosition: 'bottom',
|
|
16
|
-
textMargin: 2,
|
|
17
|
-
background: '#ffffff',
|
|
18
|
-
lineColor: '#000000',
|
|
19
|
-
margin: 10,
|
|
20
|
-
marginTop: 10,
|
|
21
|
-
marginBottom: 10,
|
|
22
|
-
marginLeft: 10,
|
|
23
|
-
marginRight: 10,
|
|
24
|
-
pageWidth: 612,
|
|
14
|
+
...BarcodeEncoder.getDefaultOptions(),
|
|
15
|
+
pageWidth: 612, // US Letter at 72dpi
|
|
25
16
|
pageHeight: 792,
|
|
17
|
+
pageSize: null, // e.g. 'A4' - takes precedence over pageWidth/pageHeight
|
|
18
|
+
fitToBarcode: false, // size the page to the barcode plus margins
|
|
19
|
+
title: null,
|
|
26
20
|
};
|
|
27
21
|
}
|
|
28
22
|
|
|
@@ -31,137 +25,93 @@ class PDFRenderer {
|
|
|
31
25
|
* @param {string} data - The data to encode
|
|
32
26
|
* @param {string} type - The barcode type
|
|
33
27
|
* @param {Object} options - Render options
|
|
34
|
-
* @returns {Buffer} PDF buffer
|
|
28
|
+
* @returns {Promise<Buffer>} PDF buffer
|
|
35
29
|
*/
|
|
36
|
-
render(data, type, options = {}) {
|
|
37
|
-
|
|
38
|
-
// Merge options with defaults
|
|
39
|
-
const renderOptions = { ...this.defaultOptions, ...options };
|
|
40
|
-
|
|
41
|
-
// Create PDF document
|
|
42
|
-
const doc = new PDFDocument({
|
|
43
|
-
size: [renderOptions.pageWidth, renderOptions.pageHeight],
|
|
44
|
-
margins: {
|
|
45
|
-
top: renderOptions.marginTop,
|
|
46
|
-
bottom: renderOptions.marginBottom,
|
|
47
|
-
left: renderOptions.marginLeft,
|
|
48
|
-
right: renderOptions.marginRight,
|
|
49
|
-
},
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// Collect PDF data
|
|
53
|
-
const chunks = [];
|
|
54
|
-
doc.on('data', chunk => chunks.push(chunk));
|
|
55
|
-
|
|
56
|
-
return new Promise((resolve, reject) => {
|
|
57
|
-
doc.on('end', () => {
|
|
58
|
-
const pdfBuffer = Buffer.concat(chunks);
|
|
59
|
-
resolve(pdfBuffer);
|
|
60
|
-
});
|
|
30
|
+
async render(data, type, options = {}) {
|
|
31
|
+
const renderOptions = { ...this.defaultOptions, ...options };
|
|
61
32
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
33
|
+
let png;
|
|
34
|
+
let dimensions;
|
|
35
|
+
try {
|
|
36
|
+
png = await BarcodeEncoder.toPng(data, type, renderOptions);
|
|
37
|
+
dimensions = readPngSize(png);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
throw new Error(`PDF rendering failed: ${error.message}`);
|
|
40
|
+
}
|
|
66
41
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
});
|
|
42
|
+
try {
|
|
43
|
+
return await this.buildDocument(png, dimensions, renderOptions);
|
|
70
44
|
} catch (error) {
|
|
71
45
|
throw new Error(`PDF rendering failed: ${error.message}`);
|
|
72
46
|
}
|
|
73
47
|
}
|
|
74
48
|
|
|
75
49
|
/**
|
|
76
|
-
*
|
|
77
|
-
* @param {
|
|
78
|
-
* @param {
|
|
79
|
-
* @param {string} type - The barcode type
|
|
50
|
+
* Build the PDF document around an encoded barcode image
|
|
51
|
+
* @param {Buffer} png - Encoded barcode as PNG
|
|
52
|
+
* @param {{width: number, height: number}} dimensions - Image size in pixels
|
|
80
53
|
* @param {Object} options - Render options
|
|
54
|
+
* @returns {Promise<Buffer>} PDF buffer
|
|
81
55
|
*/
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const x = options.marginLeft;
|
|
90
|
-
const y = options.marginTop;
|
|
91
|
-
|
|
92
|
-
if (type === 'qrcode') {
|
|
93
|
-
this.addQRCodeToPDF(doc, data, x, y, options);
|
|
94
|
-
} else {
|
|
95
|
-
this.addLinearBarcodeToPDF(doc, data, type, x, y, options);
|
|
96
|
-
}
|
|
56
|
+
buildDocument(png, dimensions, options) {
|
|
57
|
+
const margins = {
|
|
58
|
+
top: fallbackNumber(options.marginTop, options.margin, 10),
|
|
59
|
+
bottom: fallbackNumber(options.marginBottom, options.margin, 10),
|
|
60
|
+
left: fallbackNumber(options.marginLeft, options.margin, 10),
|
|
61
|
+
right: fallbackNumber(options.marginRight, options.margin, 10),
|
|
62
|
+
};
|
|
97
63
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
64
|
+
const pageSetup = options.fitToBarcode
|
|
65
|
+
? {
|
|
66
|
+
size: [
|
|
67
|
+
dimensions.width + margins.left + margins.right,
|
|
68
|
+
dimensions.height + margins.top + margins.bottom,
|
|
69
|
+
],
|
|
70
|
+
}
|
|
71
|
+
: {
|
|
72
|
+
size: options.pageSize || [options.pageWidth, options.pageHeight],
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const doc = new PDFDocument({ ...pageSetup, margins, autoFirstPage: true });
|
|
76
|
+
|
|
77
|
+
if (options.title) {
|
|
78
|
+
doc.info.Title = options.title;
|
|
105
79
|
}
|
|
106
|
-
}
|
|
107
80
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
// Draw QR code pattern
|
|
124
|
-
for (let row = 0; row < cells; row++) {
|
|
125
|
-
for (let col = 0; col < cells; col++) {
|
|
126
|
-
const shouldFill =
|
|
127
|
-
(data.charCodeAt((row * cells + col) % data.length) + row + col) %
|
|
128
|
-
2 ===
|
|
129
|
-
0;
|
|
130
|
-
|
|
131
|
-
if (shouldFill) {
|
|
132
|
-
doc.rect(x + col * cellSize, y + row * cellSize, cellSize, cellSize);
|
|
133
|
-
doc.fillColor(options.lineColor);
|
|
134
|
-
doc.fill();
|
|
81
|
+
const chunks = [];
|
|
82
|
+
doc.on('data', chunk => chunks.push(chunk));
|
|
83
|
+
|
|
84
|
+
return new Promise((resolve, reject) => {
|
|
85
|
+
doc.on('end', () => resolve(Buffer.concat(chunks)));
|
|
86
|
+
doc.on('error', reject);
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const pageWidth = doc.page.width;
|
|
90
|
+
const pageHeight = doc.page.height;
|
|
91
|
+
const availableWidth = pageWidth - margins.left - margins.right;
|
|
92
|
+
const availableHeight = pageHeight - margins.top - margins.bottom;
|
|
93
|
+
|
|
94
|
+
if (options.background) {
|
|
95
|
+
doc.rect(0, 0, pageWidth, pageHeight).fill(options.background);
|
|
135
96
|
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
97
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
const char = data.charCodeAt(i);
|
|
156
|
-
const barCount = (char % 5) + 1;
|
|
157
|
-
|
|
158
|
-
for (let j = 0; j < barCount; j++) {
|
|
159
|
-
doc.rect(currentX, y, barWidth, options.height);
|
|
160
|
-
doc.fillColor(options.lineColor);
|
|
161
|
-
doc.fill();
|
|
162
|
-
currentX += barWidth * 2;
|
|
98
|
+
// Never upscale - a barcode drawn larger than encoded loses crispness
|
|
99
|
+
const scale = Math.min(
|
|
100
|
+
1,
|
|
101
|
+
availableWidth / dimensions.width,
|
|
102
|
+
availableHeight / dimensions.height
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
doc.image(png, margins.left, margins.top, {
|
|
106
|
+
width: dimensions.width * scale,
|
|
107
|
+
height: dimensions.height * scale,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
doc.end();
|
|
111
|
+
} catch (error) {
|
|
112
|
+
reject(error);
|
|
163
113
|
}
|
|
164
|
-
}
|
|
114
|
+
});
|
|
165
115
|
}
|
|
166
116
|
|
|
167
117
|
/**
|
|
@@ -181,4 +131,32 @@ class PDFRenderer {
|
|
|
181
131
|
}
|
|
182
132
|
}
|
|
183
133
|
|
|
134
|
+
/**
|
|
135
|
+
* Read the pixel dimensions out of a PNG buffer's IHDR chunk
|
|
136
|
+
* @param {Buffer} png - PNG buffer
|
|
137
|
+
* @returns {{width: number, height: number}} Dimensions
|
|
138
|
+
*/
|
|
139
|
+
function readPngSize(png) {
|
|
140
|
+
if (!Buffer.isBuffer(png) || png.length < 24) {
|
|
141
|
+
throw new Error('Encoded barcode is not a valid PNG buffer');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return { width: png.readUInt32BE(16), height: png.readUInt32BE(20) };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* First finite number out of the candidates
|
|
149
|
+
* @param {...*} values - Candidate values
|
|
150
|
+
* @returns {number} The first usable number, or 0
|
|
151
|
+
*/
|
|
152
|
+
function fallbackNumber(...values) {
|
|
153
|
+
for (const value of values) {
|
|
154
|
+
const num = Number(value);
|
|
155
|
+
if (Number.isFinite(num)) {
|
|
156
|
+
return num;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
184
162
|
module.exports = PDFRenderer;
|
|
@@ -2,27 +2,11 @@
|
|
|
2
2
|
* PNG Renderer - Renders barcodes as PNG images
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
const {
|
|
6
|
-
const JsBarcode = require('jsbarcode');
|
|
5
|
+
const { BarcodeEncoder } = require('../encoders/BarcodeEncoder');
|
|
7
6
|
|
|
8
7
|
class PNGRenderer {
|
|
9
8
|
constructor() {
|
|
10
|
-
this.defaultOptions =
|
|
11
|
-
width: 2,
|
|
12
|
-
height: 100,
|
|
13
|
-
displayValue: true,
|
|
14
|
-
fontSize: 20,
|
|
15
|
-
textAlign: 'center',
|
|
16
|
-
textPosition: 'bottom',
|
|
17
|
-
textMargin: 2,
|
|
18
|
-
background: '#ffffff',
|
|
19
|
-
lineColor: '#000000',
|
|
20
|
-
margin: 10,
|
|
21
|
-
marginTop: 10,
|
|
22
|
-
marginBottom: 10,
|
|
23
|
-
marginLeft: 10,
|
|
24
|
-
marginRight: 10,
|
|
25
|
-
};
|
|
9
|
+
this.defaultOptions = BarcodeEncoder.getDefaultOptions();
|
|
26
10
|
}
|
|
27
11
|
|
|
28
12
|
/**
|
|
@@ -30,79 +14,19 @@ class PNGRenderer {
|
|
|
30
14
|
* @param {string} data - The data to encode
|
|
31
15
|
* @param {string} type - The barcode type
|
|
32
16
|
* @param {Object} options - Render options
|
|
33
|
-
* @returns {Buffer} PNG buffer
|
|
17
|
+
* @returns {Promise<Buffer>} PNG buffer
|
|
34
18
|
*/
|
|
35
|
-
render(data, type, options = {}) {
|
|
19
|
+
async render(data, type, options = {}) {
|
|
36
20
|
try {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// Create canvas
|
|
41
|
-
const canvas = createCanvas(400, 200);
|
|
42
|
-
const ctx = canvas.getContext('2d');
|
|
43
|
-
|
|
44
|
-
// Set background
|
|
45
|
-
ctx.fillStyle = renderOptions.background;
|
|
46
|
-
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
47
|
-
|
|
48
|
-
// Generate barcode using JsBarcode
|
|
49
|
-
JsBarcode(canvas, data, {
|
|
50
|
-
format: this.mapBarcodeType(type),
|
|
51
|
-
width: renderOptions.width,
|
|
52
|
-
height: renderOptions.height,
|
|
53
|
-
displayValue: renderOptions.displayValue,
|
|
54
|
-
fontSize: renderOptions.fontSize,
|
|
55
|
-
textAlign: renderOptions.textAlign,
|
|
56
|
-
textPosition: renderOptions.textPosition,
|
|
57
|
-
textMargin: renderOptions.textMargin,
|
|
58
|
-
background: renderOptions.background,
|
|
59
|
-
lineColor: renderOptions.lineColor,
|
|
60
|
-
margin: renderOptions.margin,
|
|
61
|
-
marginTop: renderOptions.marginTop,
|
|
62
|
-
marginBottom: renderOptions.marginBottom,
|
|
63
|
-
marginLeft: renderOptions.marginLeft,
|
|
64
|
-
marginRight: renderOptions.marginRight,
|
|
21
|
+
return await BarcodeEncoder.toPng(data, type, {
|
|
22
|
+
...this.defaultOptions,
|
|
23
|
+
...options,
|
|
65
24
|
});
|
|
66
|
-
|
|
67
|
-
// Convert to PNG buffer
|
|
68
|
-
return canvas.toBuffer('image/png');
|
|
69
25
|
} catch (error) {
|
|
70
26
|
throw new Error(`PNG rendering failed: ${error.message}`);
|
|
71
27
|
}
|
|
72
28
|
}
|
|
73
29
|
|
|
74
|
-
/**
|
|
75
|
-
* Map barcode type to JsBarcode format
|
|
76
|
-
* @param {string} type - The barcode type
|
|
77
|
-
* @returns {string} JsBarcode format
|
|
78
|
-
*/
|
|
79
|
-
mapBarcodeType(type) {
|
|
80
|
-
const typeMap = {
|
|
81
|
-
code128: 'CODE128',
|
|
82
|
-
code128a: 'CODE128A',
|
|
83
|
-
code128b: 'CODE128B',
|
|
84
|
-
code128c: 'CODE128C',
|
|
85
|
-
code128auto: 'CODE128',
|
|
86
|
-
code39: 'CODE39',
|
|
87
|
-
code39extended: 'CODE39',
|
|
88
|
-
code39checksum: 'CODE39',
|
|
89
|
-
code39auto: 'CODE39',
|
|
90
|
-
code93: 'CODE93',
|
|
91
|
-
ean13: 'EAN13',
|
|
92
|
-
ean8: 'EAN8',
|
|
93
|
-
upca: 'UPC',
|
|
94
|
-
upce: 'UPC',
|
|
95
|
-
codabar: 'codabar',
|
|
96
|
-
code11: 'CODE11',
|
|
97
|
-
msi: 'MSI',
|
|
98
|
-
pharmazentral: 'pharmazentral',
|
|
99
|
-
interleaved25: 'ITF',
|
|
100
|
-
standard25: 'STD25',
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
return typeMap[type] || 'CODE128';
|
|
104
|
-
}
|
|
105
|
-
|
|
106
30
|
/**
|
|
107
31
|
* Get default options
|
|
108
32
|
* @returns {Object} Default options
|
|
@@ -2,40 +2,75 @@
|
|
|
2
2
|
* Render Formats - Supported output formats
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
const FORMAT_REGISTRY = {
|
|
6
|
+
png: {
|
|
7
|
+
name: 'PNG',
|
|
8
|
+
mimeType: 'image/png',
|
|
9
|
+
extension: '.png',
|
|
10
|
+
returns: 'Buffer',
|
|
11
|
+
description: 'Portable Network Graphics - Raster image format',
|
|
12
|
+
},
|
|
13
|
+
svg: {
|
|
14
|
+
name: 'SVG',
|
|
15
|
+
mimeType: 'image/svg+xml',
|
|
16
|
+
extension: '.svg',
|
|
17
|
+
returns: 'string',
|
|
18
|
+
description: 'Scalable Vector Graphics - Vector image format',
|
|
19
|
+
},
|
|
20
|
+
html: {
|
|
21
|
+
name: 'HTML',
|
|
22
|
+
mimeType: 'text/html',
|
|
23
|
+
extension: '.html',
|
|
24
|
+
returns: 'string',
|
|
25
|
+
description: 'HTML fragment wrapping an inline SVG barcode',
|
|
26
|
+
},
|
|
27
|
+
pdf: {
|
|
28
|
+
name: 'PDF',
|
|
29
|
+
mimeType: 'application/pdf',
|
|
30
|
+
extension: '.pdf',
|
|
31
|
+
returns: 'Buffer',
|
|
32
|
+
description: 'Portable Document Format - Document format',
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const FORMATS = Object.keys(FORMAT_REGISTRY).reduce((acc, format) => {
|
|
37
|
+
acc[format.toUpperCase()] = format;
|
|
38
|
+
return acc;
|
|
39
|
+
}, {});
|
|
40
|
+
|
|
5
41
|
class RenderFormats {
|
|
6
|
-
static FORMATS =
|
|
7
|
-
PNG: 'png',
|
|
8
|
-
SVG: 'svg',
|
|
9
|
-
HTML: 'html',
|
|
10
|
-
PDF: 'pdf',
|
|
11
|
-
JPG: 'jpg',
|
|
12
|
-
JPEG: 'jpeg',
|
|
13
|
-
};
|
|
42
|
+
static FORMATS = FORMATS;
|
|
14
43
|
|
|
15
|
-
static MIME_TYPES =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
44
|
+
static MIME_TYPES = Object.entries(FORMAT_REGISTRY).reduce(
|
|
45
|
+
(acc, [format, info]) => {
|
|
46
|
+
acc[format] = info.mimeType;
|
|
47
|
+
return acc;
|
|
48
|
+
},
|
|
49
|
+
{}
|
|
50
|
+
);
|
|
23
51
|
|
|
24
|
-
static EXTENSIONS =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
};
|
|
52
|
+
static EXTENSIONS = Object.entries(FORMAT_REGISTRY).reduce(
|
|
53
|
+
(acc, [format, info]) => {
|
|
54
|
+
acc[format] = info.extension;
|
|
55
|
+
return acc;
|
|
56
|
+
},
|
|
57
|
+
{}
|
|
58
|
+
);
|
|
32
59
|
|
|
33
60
|
/**
|
|
34
61
|
* Get all supported formats
|
|
35
|
-
* @returns {
|
|
62
|
+
* @returns {string[]} Array of all formats
|
|
36
63
|
*/
|
|
37
64
|
static getAll() {
|
|
38
|
-
return Object.
|
|
65
|
+
return Object.keys(FORMAT_REGISTRY);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get all supported formats (alias of getAll)
|
|
70
|
+
* @returns {string[]} Array of all formats
|
|
71
|
+
*/
|
|
72
|
+
static getFormats() {
|
|
73
|
+
return this.getAll();
|
|
39
74
|
}
|
|
40
75
|
|
|
41
76
|
/**
|
|
@@ -44,7 +79,7 @@ class RenderFormats {
|
|
|
44
79
|
* @returns {boolean} True if valid
|
|
45
80
|
*/
|
|
46
81
|
static isValid(format) {
|
|
47
|
-
return Object.
|
|
82
|
+
return typeof format === 'string' && Object.hasOwn(FORMAT_REGISTRY, format);
|
|
48
83
|
}
|
|
49
84
|
|
|
50
85
|
/**
|
|
@@ -53,7 +88,9 @@ class RenderFormats {
|
|
|
53
88
|
* @returns {string} MIME type
|
|
54
89
|
*/
|
|
55
90
|
static getMimeType(format) {
|
|
56
|
-
return
|
|
91
|
+
return FORMAT_REGISTRY[format]
|
|
92
|
+
? FORMAT_REGISTRY[format].mimeType
|
|
93
|
+
: 'application/octet-stream';
|
|
57
94
|
}
|
|
58
95
|
|
|
59
96
|
/**
|
|
@@ -62,7 +99,7 @@ class RenderFormats {
|
|
|
62
99
|
* @returns {string} File extension
|
|
63
100
|
*/
|
|
64
101
|
static getExtension(format) {
|
|
65
|
-
return
|
|
102
|
+
return FORMAT_REGISTRY[format] ? FORMAT_REGISTRY[format].extension : '';
|
|
66
103
|
}
|
|
67
104
|
|
|
68
105
|
/**
|
|
@@ -71,16 +108,30 @@ class RenderFormats {
|
|
|
71
108
|
* @returns {string} Description
|
|
72
109
|
*/
|
|
73
110
|
static getDescription(format) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
111
|
+
return FORMAT_REGISTRY[format]
|
|
112
|
+
? FORMAT_REGISTRY[format].description
|
|
113
|
+
: 'Unknown format';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Get full information about a format
|
|
118
|
+
* @param {string} format - The format
|
|
119
|
+
* @returns {Object|null} Format information, or null when unknown
|
|
120
|
+
*/
|
|
121
|
+
static getFormatInfo(format) {
|
|
122
|
+
const info = FORMAT_REGISTRY[format];
|
|
123
|
+
if (!info) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
82
126
|
|
|
83
|
-
return
|
|
127
|
+
return {
|
|
128
|
+
format,
|
|
129
|
+
name: info.name,
|
|
130
|
+
mimeType: info.mimeType,
|
|
131
|
+
extension: info.extension,
|
|
132
|
+
returns: info.returns,
|
|
133
|
+
description: info.description,
|
|
134
|
+
};
|
|
84
135
|
}
|
|
85
136
|
}
|
|
86
137
|
|