const Allignments = { LEFT: '[L]', CENTER: '[C]', RIGHT: '[R]', } as const; const AllignmentArray = [...Object.values(Allignments)] as const; export type Allignment = (typeof AllignmentArray)[number]; const Commands = { RESET: '[X]', } as const; const CommandArray = [...Object.values(Commands)] as const; export type Command = (typeof CommandArray)[number]; const FontSizes = { NORMAL: 'normal', WIDE: 'wide', TALL: 'tall', BIG: 'big', BIG2: 'big-2', BIG3: 'big-3', BIG4: 'big-4', BIG5: 'big-5', BIG6: 'big-6', } as const; const FontSizeArray = [...Object.values(FontSizes)] as const; export type FontSize = (typeof FontSizeArray)[number]; const FontColors = { BLACK: 'black', BLACKBG: 'bg-black', RED: 'red', REDBG: 'bg-red', } as const; const FontColorArray = [...Object.values(FontColors)] as const; export type FontColor = (typeof FontColorArray)[number]; const BarCodeTypes = { EAN13: 'ean13', // 12 Numeric char EAN8: 'ean8', // 7 Numeric char UPCA: 'upca', // 11 Numeric char UPCE: 'upce', // 6 Numeric char B128: '128', // strings } as const; const BarCodeTypeArray = [...Object.values(BarCodeTypes)] as const; export type BarCodeType = (typeof BarCodeTypeArray)[number]; const BarCodeTextPositions = { NONE: 'none', ABOVE: 'above', BELOW: 'below', } as const; const BarCodeTextPositionArray = [ ...Object.values(BarCodeTextPositions), ] as const; export type BarCodeTextPosition = (typeof BarCodeTextPositionArray)[number]; const Tags = { ALLIGNMENT: Allignments, FONT: { TAG: 'font', ATTRIBUTES: { SIZE: 'size', COLOR: 'color', UNDERLINE: 'underline', }, SIZE: FontSizes, COLOR: FontColors, }, BOLD: 'b', UNDERLINE: 'u', IMAGE: 'img', BARCODE: { TAG: 'barcode', ATTRIBUTES: { TYPE: 'type', HEIGHT: 'height', WIDTH: 'width', TEXTPOSITION: 'text', }, TYPE: BarCodeTypes, TEXT_POSITION: BarCodeTextPositions, }, QRCODE: { TAG: 'qrcode', ATTRIBUTES: { SIZE: 'size', }, }, RAW: 'raw', BREAKLINE: '\n', }; const prepend = (text: string, extra: string) => { return extra + text; }; const append = (text: string, extra: string) => { return text + extra; }; const align = (text: string, direction: Allignment) => { return prepend(text, direction); }; const wrap = (text: string, extra1: string, extra2: string) => { return extra1 + text + extra2; }; const attr = (attribute: string, value: string | number) => { return `${attribute}='${value}'`; }; const wraptag = ( text: string, tag: string, attributes: Array<[string, string | number | undefined | null]> ) => { const modifiers = attributes .filter( ([key, value]) => key !== null && value !== null && key !== undefined && value !== undefined ) .map(([key, value]) => { return attr(key, value as string | number); }) .join(' '); const modifier = modifiers.length > 0 ? ` ${modifiers}` : ''; return wrap(text, `<${tag}${modifier}>`, ``); }; const toHexString = (input: string | number) => { if (typeof input === 'string') { const hexAsciiString = input .split('') .map((char) => char.charCodeAt(0).toString(16)) .join(''); return hexAsciiString; } else if (typeof input === 'number') { const hexString = input.toString(16); if (hexString.length % 2 === 1) { return '0' + hexString; } else { return hexString; } } else { throw new Error('Invalid input type. 1'); } }; export default { ...{ ALLIGNMENT: Allignments, FONT_SIZE: FontSizes, FONT_COLOR: FontSizes, BARCODE_TYPE: BarCodeTypes, BARCODE_TEXT_POSITION: BarCodeTextPositions, }, /** * Create left aligned text * * @param {string} text text to be formated * @return formated text */ left: (text: string) => { return align(text, Tags.ALLIGNMENT.LEFT); }, /** * Create left aligned text * * @param {string} text text to be formated * @return formated text */ center: (text: string) => { return align(text, Tags.ALLIGNMENT.CENTER); }, /** * Create right aligned text * * @param {string} text text to be formated * @return formated text */ right: (text: string) => { return align(text, Tags.ALLIGNMENT.RIGHT); }, /** * Create aligned text * * @param {string} text text to be formated * @param {string} direction Select direction size from **.ALLIGNMENT.???** * @return formated text */ align: align, /** * Create text with custom font * * @param {string} text text to be formated * @param {FontSize} [size=Tags.FONT.SIZE.NORMAL] Select text size from **.FONT.SIZE.???** default is **.FONT.SIZE.NORMAL** * @param {FontColor} [color=Tags.FONT.COLOR.BLACK] Select text color from **.FONT.COLOR.???** default is **.FONT.SIZE.BLACK** * @return formated text */ font: ( text: string, size: FontSize | null | undefined = Tags.FONT.SIZE.NORMAL, color: FontColor | null | undefined = Tags.FONT.COLOR.BLACK, underline: boolean | null | undefined = false ) => { return wraptag(text, Tags.FONT.TAG, [ [Tags.FONT.ATTRIBUTES.SIZE, size], [Tags.FONT.ATTRIBUTES.COLOR, color], [Tags.FONT.ATTRIBUTES.UNDERLINE, underline ? '1' : null], ]); }, /** * Create bold text * * @param {string} text text to be formated * @return formated text */ bold: (text: string) => { return wraptag(text, Tags.BOLD, []); }, /** * Create underlined text * * @param {string} text text to be formated * @return formated text */ underline: (text: string) => { return wraptag(text, Tags.UNDERLINE, []); }, /** * Add image * * @param {string} source image source, protocol must be **file://** or **http[s]://**, remote file willbe downloaded * @return image tag text */ image: (source: string) => { return wraptag(source, Tags.IMAGE, []); }, /** * Create barcode tag * * @param {string} text barcode payload data * @param {(BarCodeType | null | undefined)} [type] Select barcode type from **.BARCODE.TYPE.???** default is **.BARCODE.TYPE.EAN13** * @param {(number | null | undefined)} [height] Set barcode height * @param {(number | null | undefined)} [width] Set barcode width * @param {(BarCodeTextPosition | null | undefined)} [text_position] Select text position from **.BARCODE.TEXTPOSITION.???** default is **.BARCODE.TEXTPOSITION.NONE** * @return barcode tag text */ barcode: ( text: string, type?: BarCodeType | null | undefined, height?: number | null | undefined, width?: number | null | undefined, text_position?: BarCodeTextPosition | null | undefined ) => { if (!type) { type = Tags.BARCODE.TYPE.EAN13; } if (!text_position) { text_position = Tags.BARCODE.TEXT_POSITION.NONE; } return wraptag(text, Tags.BARCODE.TAG, [ [Tags.BARCODE.ATTRIBUTES.TYPE, type], [Tags.BARCODE.ATTRIBUTES.HEIGHT, height], [Tags.BARCODE.ATTRIBUTES.WIDTH, width], [Tags.BARCODE.ATTRIBUTES.TEXTPOSITION, text_position], ]); }, /** * Create QRCode tag * * @param {string} text qrcode payload data * @param {number} [size=25] Set qrcode size, default is 25 * @return barcode tag text */ qrcode: (text: string, size: number = 25) => { return wraptag(text, Tags.QRCODE.TAG, [ [Tags.QRCODE.ATTRIBUTES.SIZE, size], ]); }, /** * Add raw command * * @param {string} command hex string * @return image tag text */ raw: (command: string) => { return wraptag(command, Tags.RAW, []); }, hexString(...data: (string | number | (string | number)[])[]): string { return data.reduce((all: string, current) => { if (typeof current === 'string' || typeof current === 'number') { return all + toHexString(current); } else if (Array.isArray(current)) { return ( all + current.reduce((_all: string, _current) => { return _all + toHexString(_current); }, '') ); } else { throw new Error('Invalid input type. 2'); } }, ''); }, /** * Create a line * * @param {string} text input * @return formated text */ line: (text: string) => { return append(text, Tags.BREAKLINE); }, /** * Reset printer before write the line, must be at first * * @param {string} text input * @return formated text */ reset: (text: string) => { return prepend(text, Commands.RESET); }, };