/** * Sutton SignWriting Core Module v1.2.0 (https://github.com/sutton-signwriting/core) * Author: Steve Slevinski (https://SteveSlevinski.me) * swu.cjs is released under the MIT License. */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); /** * Object of regular expressions for SWU strings in UTF-16 * * { symbol, coord, sort, box, prefix, spatial, signbox, sign, sortable } * @alias swu.re * @type {object} */ let re = { 'symbol': '(?:(?:\uD8C0[\uDC01-\uDFFF])|(?:[\uD8C1-\uD8FC][\uDC00-\uDFFF])|(?:\uD8FD[\uDC00-\uDC80]))', 'coord': '(?:\uD836[\uDC0C-\uDDFF]){2}', 'sort': '\uD836\uDC00', 'box': '\uD836[\uDC01-\uDC04]' }; re.prefix = `(?:${re.sort}(?:${re.symbol})+)`; re.spatial = `${re.symbol}${re.coord}`; re.signbox = `${re.box}${re.coord}(?:${re.spatial})*`; re.sign = `${re.prefix}?${re.signbox}`; re.sortable = `${re.prefix}${re.signbox}`; /** * Object of regular expressions for style strings * * { colorize, colorhex, colorname, padding, zoom, zoomsym, classbase, id, colorbase, color, colors, background, detail, detailsym, classes, full } * @alias style.re * @type {object} */ let re$1 = { 'colorize': 'C', 'colorhex': '(?:[0-9a-fA-F]{3}){1,2}', 'colorname': '[a-zA-Z]+', 'padding': 'P[0-9]{2}', 'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)', 'zoomsym': 'Z[0-9]{2},[0-9]+(?:\\.[0-9]+)?(?:,[0-9]{3}x[0-9]{3})?', 'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}', 'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}' }; re$1.colorbase = `(?:${re$1.colorhex}|${re$1.colorname})`; re$1.color = `_${re$1.colorbase}_`; re$1.colors = `_${re$1.colorbase}(?:,${re$1.colorbase})?_`; re$1.background = `G${re$1.color}`; re$1.detail = `D${re$1.colors}`; re$1.detailsym = `D[0-9]{2}${re$1.colors}`; re$1.classes = `${re$1.classbase}(?: ${re$1.classbase})*`; re$1.full = `-(${re$1.colorize})?(${re$1.padding})?(${re$1.background})?(${re$1.detail})?(${re$1.zoom})?(?:-((?:${re$1.detailsym})*)((?:${re$1.zoomsym})*))?(?:-(${re$1.classes})?!(?:(${re$1.id})!)?)?`; /** The convert module contains functions to convert between Formal SignWriitng in ASCII (FSW) and SignWriting in Unicode (SWU) characters, along with other types of data. * [Characters set definitions](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2) * @module convert */ /** * Function to convert an SWU number character to an integer * @function convert.swu2num * @param {string} swuNum - SWU number character * @returns {number} Integer value for number * @example * convert.swu2num('ðĪ†') * * return 500 */ const swu2num = swuNum => parseInt(swuNum.codePointAt(0)) - 0x1D80C + 250; /** * Function to convert a number to an SWU number character * @function convert.num2swu * @param {number} num - Integer value for number * @returns {string} SWU number character * @example * convert.num2swu(500) * * return 'ðĪ†' */ const num2swu = num => String.fromCodePoint(0x1D80C + parseInt(num) - 250); /** * Function to convert two SWU number characters to an array of x,y integers * @function convert.swu2coord * @param {string} swuCoord - Two SWU number character * @returns {number[]} Array of x,y integers * @example * convert.swu2coord('ðĪ†ðĪ†') * * return [500, 500] */ const swu2coord = swuCoord => [swu2num(swuCoord.slice(0, 2)), swu2num(swuCoord.slice(2, 4))]; /** * Function to convert an array of x,y integers to two SWU number characters * @function convert.coord2swu * @param {number[]} coord - Array of x,y integers * @returns {string} Two SWU number character * @example * convert.coord2swu([500, 500]) * * return 'ðĪ†ðĪ†' */ const coord2swu = coord => coord.map(num => num2swu(num)).join(''); /** * Function to convert an SWU symbol character to a code point on plane 4 * @function convert.swu2code * @param {string} swuSym - SWU symbol character * @returns {number} Code point on plane 4 * @example * convert.swu2code('ņ€€') * * return 0x40001 */ const swu2code = swuSym => parseInt(swuSym.codePointAt(0)); const parse = { /** * Function to parse an swu symbol with optional coordinate and style string * @function swu.parse.symbol * @param {string} swuSym - an swu symbol * @returns {object} elements of swu symbol * @example * swu.parse.symbol('ņ€€ðĪ†ðĪ†-C') * * return { * 'symbol': 'ņ€€', * 'coord': [500, 500], * 'style': '-C' * } */ symbol: swuSym => { const regex = `^(${re.symbol})(${re.coord})?(${re$1.full})?`; const symbol = typeof swuSym === 'string' ? swuSym.match(new RegExp(regex)) : undefined; return { 'symbol': symbol ? symbol[1] : undefined, 'coord': symbol && symbol[2] ? swu2coord(symbol[2]) : undefined, 'style': symbol ? symbol[3] : undefined }; }, /** * Function to parse an swu sign with style string * @function swu.parse.sign * @param {string} swuSign - an swu sign * @returns {object} elements of swu sign * @example * swu.parse.sign('𝠀ņ€€’ņ€€šņ‹šĨņ‹›Đ𝠃ðĪŸðĪĐņ‹›ĐðĢĩðĪņ€€’ðĪ‡ðĢĪņ‹šĨðĪðĪ†ņ€€šðĢŪðĢ­-C') * * return { * sequence: ['ņ€€’','ņ€€š','ņ‹šĨ','ņ‹›Đ''], * box: '𝠃', * max: [525, 535], * spatials: [ * { * symbol: 'ņ‹›Đ', * coord: [483, 510] * }, * { * symbol: 'ņ€€’', * coord: [501, 466] * }, * { * symbol: 'ņ‹šĨ', * coord: [510, 500] * }, * { * symbol: 'ņ€€š', * coord: [476, 475] * } * ], * style: '-C' * } */ sign: swuSign => { const regex = `^(${re.prefix})?(${re.signbox})(${re$1.full})?`; const sign = typeof swuSign === 'string' ? swuSign.match(new RegExp(regex)) : undefined; if (sign) { return { 'sequence': sign[1] ? sign[1].slice(2).match(/.{2}/g) : undefined, 'box': sign[2].slice(0, 2), 'max': swu2coord(sign[2].slice(2, 6)), 'spatials': sign[2].length < 7 ? undefined : sign[2].slice(6).match(/(.{6})/g).map(m => { return { symbol: m.slice(0, 2), coord: swu2coord(m.slice(2)) }; }), 'style': sign[3] }; } else { return {}; } } }; /** * Function to encode SWU characters using the UTF-16 escape format. * @function swu.encode * @param {string} swu - SWU characters * @returns {string} UTF-16 escape format * @example * swu.encode('ņ€€ðĪ†ðĪ†') * * return '\\uD8C0\\uDC01\\uD836\\uDD06\\uD836\\uDD06' */ const encode = text => text.replace(/[\u007F-\uFFFF]/g, function (chr) { return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4).toUpperCase(); }); /** * Function to decode UTF-16 escape format to SWU characters. * @function swu.decode * @param {string} encoded - UTF-16 escape format * @returns {string} SWU characters * @example * swu.decode('\\uD8C0\\uDC01\\uD836\\uDD06\\uD836\\uDD06') * * return 'ņ€€ðĪ†ðĪ†' */ const decode = encoded => encoded.replace(/\\u([0-9A-F]{4})/g, function (match, chr) { return String.fromCharCode(parseInt(chr, 16)); }); /** * Function to decompose an SWU character into UTF-16 surrogate pairs. * @function swu.pair * @param {string} swuChar - an SWU character * @returns {string[]} an array of UTF-16 surrogate pairs * @example * swu.pair('ņ€€') * * return ['D8C0', 'DC01'] */ const pair = swuChar => [swuChar.charCodeAt(0).toString(16).toUpperCase(), swuChar.charCodeAt(1).toString(16).toUpperCase()]; const compose = { /** * Function to compose an swu symbol with optional coordinate and style string * @function swu.compose.symbol * @param {object} swuSymObject - an swu symbol object * @param {string} swuSymObject.symbol - an swu symbol key * @param {number[]} swuSymObject.coord - top-left coordinate of symbol with 500,500 center * @param {string} swuSymObject.style - a style string for custom appearance * @returns {string} an swu symbol string * @example * swu.compose.symbol({ * 'symbol': 'ņ€€', * 'coord': [500, 500], * 'style': '-C' * }) * * return 'ņ€€ðĪ†ðĪ†-C' */ symbol: swuSymObject => { if (typeof swuSymObject !== 'object' || swuSymObject === null) return undefined; if (typeof swuSymObject.symbol === 'string') { const symbol = (swuSymObject.symbol.match(re.symbol) || [''])[0]; if (symbol) { const x = swuSymObject.coord && swuSymObject.coord[0] || ''; const y = swuSymObject.coord && swuSymObject.coord[1] || ''; const coord = x && y ? coord2swu([x, y]) : ''; const styleStr = typeof swuSymObject.style === 'string' && (swuSymObject.style.match(re$1.full) || [''])[0] || ''; return symbol + coord + styleStr; } } return undefined; }, /** * Function to compose an swu sign with style string * @function swu.compose.sign * @param {string[]} swuSignObject.sequence - an ordered array of symbols * @param {string} swuSignObject.box - a choice BLMR: horizontal Box, Left, Middle, and Right lane * @param {number[]} swuSymObject.max - max bottom left coordinate of the signbox space * @param {{symbol:string,coord:number[]}[]} swuSymObject.spatials - array of symbols with top-left coordinate placement * @param {string} swuSymObject.style - a style string for custom appearance * @returns {string} an swu sign string * @example * swu.compose.sign({ * sequence: ['ņ€€’','ņ€€š','ņ‹šĨ','ņ‹›Đ''], * box: '𝠃', * max: [525, 535], * spatials: [ * { * symbol: 'ņ‹›Đ', * coord: [483, 510] * }, * { * symbol: 'ņ€€’', * coord: [501, 466] * }, * { * symbol: 'ņ‹šĨ', * coord: [510, 500] * }, * { * symbol: 'ņ€€š', * coord: [476, 475] * } * ], * style: '-C' * }) * * return '𝠀ņ€€’ņ€€šņ‹šĨņ‹›Đ𝠃ðĪŸðĪĐņ‹›ĐðĢĩðĪņ€€’ðĪ‡ðĢĪņ‹šĨðĪðĪ†ņ€€šðĢŪðĢ­-C' */ sign: swuSignObject => { if (typeof swuSignObject !== 'object' || swuSignObject === null) return undefined; let box = typeof swuSignObject.box !== 'string' ? '𝠃' : (swuSignObject.box + '𝠃').match(re.box); const x = swuSignObject.max && swuSignObject.max[0] || ''; const y = swuSignObject.max && swuSignObject.max[1] || ''; const max = x && y ? coord2swu([x, y]) : undefined; if (!max) return undefined; let prefix = ''; if (swuSignObject.sequence && Array.isArray(swuSignObject.sequence)) { prefix = swuSignObject.sequence.map(key => (key.match(re.symbol) || [''])[0]).join(''); prefix = prefix ? '𝠀' + prefix : ''; } let signbox = ''; if (swuSignObject.spatials && Array.isArray(swuSignObject.spatials)) { signbox = swuSignObject.spatials.map(spatial => { if (typeof spatial.symbol === 'string') { const symbol = (spatial.symbol.match(re.symbol) || [''])[0]; if (symbol) { const x = spatial.coord && spatial.coord[0] || ''; const y = spatial.coord && spatial.coord[1] || ''; const coord = x && y ? coord2swu([x, y]) : ''; if (coord) { return symbol + coord; } } } return ''; }).join(''); } const styleStr = typeof swuSignObject.style === 'string' && (swuSignObject.style.match(re$1.full) || [''])[0] || ''; return prefix + box + max + signbox + styleStr; } }; /** * Array of plane 4 code points for kinds of symbols: writing, location, and punctuation. * @alias swu.kind * @type {array} */ const kind = [0x40001, 0x4efa1, 0x4f2a1]; /** * Array of plane 4 code points for categories of symbols: hand, movement, dynamics, head, trunk & limb, location, and punctuation. * @alias swu.category * @type {array} */ const category = [0x40001, 0x461e1, 0x4bca1, 0x4bfa1, 0x4e8e1, 0x4efa1, 0x4f2a1]; /** * Array of plane 4 code points for the 30 symbol groups. * @alias swu.group * @type {array} */ const group = [0x40001, 0x40541, 0x40b41, 0x41981, 0x41c81, 0x43241, 0x43d81, 0x445c1, 0x44ce1, 0x45be1, 0x461e1, 0x46841, 0x46fc1, 0x47fe1, 0x485e1, 0x49301, 0x49e41, 0x4a4a1, 0x4afe1, 0x4b521, 0x4bca1, 0x4bfa1, 0x4c3c1, 0x4cfc1, 0x4d621, 0x4e161, 0x4e8e1, 0x4ec41, 0x4efa1, 0x4f2a1]; /** * Object of symbol ranges with starting and ending code points on plane 4. * * { all, writing, hand, movement, dynamic, head, hcenter, vcenter, trunk, limb, location, punctuation } * @alias swu.ranges * @type {object} */ const ranges = { 'all': [0x40001, 0x4f480], 'writing': [0x40001, 0x4efa0], 'hand': [0x40001, 0x461e0], 'movement': [0x461e1, 0x4bca0], 'dynamic': [0x4bca1, 0x4bfa0], 'head': [0x4bfa1, 0x4e8e0], 'hcenter': [0x4bfa1, 0x4e8e0], 'vcenter': [0x4bfa1, 0x4ec40], 'trunk': [0x4e8e1, 0x4ec40], 'limb': [0x4ec41, 0x4efa0], 'location': [0x4efa1, 0x4f2a0], 'punctuation': [0x4f2a1, 0x4f480] }; /** * Function to test if symbol is of a certain type. * @function swu.isType * @param {string} swuSym - an SWU symbol character * @param {string} type - the name of a symbol range * @returns {boolean} is symbol of specified type * @example * swu.isType('ņ€€', 'hand') * * return true */ const isType = (swuSym, type) => { const parsed = parse.symbol(swuSym); if (parsed.symbol) { const code = swu2code(parsed.symbol); const range = ranges[type]; if (range) { return range[0] <= code && range[1] >= code; } } return false; }; /** * Array of colors associated with the seven symbol categories. * @alias swu.colors * @type {array} */ const colors = ['#0000CC', '#CC0000', '#FF0099', '#006600', '#000000', '#884411', '#FF9900']; /** * Function that returns the standardized color for a symbol. * @function swu.colorize * @param {string} swuSym - an SWU symbol character * @returns {string} name of standardized color for symbol * @example * swu.colorize('ņ€€') * * return '#0000CC' */ const colorize = swuSym => { const parsed = parse.symbol(swuSym); let color = '#000000'; if (parsed.symbol) { const code = swu2code(parsed.symbol); const index = category.findIndex(val => val > code); color = colors[index < 0 ? 6 : index - 1]; } return color; }; exports.category = category; exports.colorize = colorize; exports.colors = colors; exports.compose = compose; exports.decode = decode; exports.encode = encode; exports.group = group; exports.isType = isType; exports.kind = kind; exports.pair = pair; exports.parse = parse; exports.ranges = ranges; exports.re = re; /* support ongoing development on https://patreon.com/signwriting */