UNPKG

16.1 kBJavaScriptView Raw
1/**
2* Sutton SignWriting Core Module v1.2.0 (https://github.com/sutton-signwriting/core)
3* Author: Steve Slevinski (https://SteveSlevinski.me)
4* swu.js is released under the MIT License.
5*/
6
7(function (global, factory) {
8 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
9 typeof define === 'function' && define.amd ? define(['exports'], factory) :
10 (global = global || self, factory((global.ssw = global.ssw || {}, global.ssw.swu = {})));
11}(this, function (exports) { 'use strict';
12
13 /**
14 * Object of regular expressions for SWU strings in UTF-16
15 *
16 * { symbol, coord, sort, box, prefix, spatial, signbox, sign, sortable }
17 * @alias swu.re
18 * @type {object}
19 */
20 let re = {
21 'symbol': '(?:(?:\uD8C0[\uDC01-\uDFFF])|(?:[\uD8C1-\uD8FC][\uDC00-\uDFFF])|(?:\uD8FD[\uDC00-\uDC80]))',
22 'coord': '(?:\uD836[\uDC0C-\uDDFF]){2}',
23 'sort': '\uD836\uDC00',
24 'box': '\uD836[\uDC01-\uDC04]'
25 };
26 re.prefix = `(?:${re.sort}(?:${re.symbol})+)`;
27 re.spatial = `${re.symbol}${re.coord}`;
28 re.signbox = `${re.box}${re.coord}(?:${re.spatial})*`;
29 re.sign = `${re.prefix}?${re.signbox}`;
30 re.sortable = `${re.prefix}${re.signbox}`;
31
32 /**
33 * Object of regular expressions for style strings
34 *
35 * { colorize, colorhex, colorname, padding, zoom, zoomsym, classbase, id, colorbase, color, colors, background, detail, detailsym, classes, full }
36 * @alias style.re
37 * @type {object}
38 */
39 let re$1 = {
40 'colorize': 'C',
41 'colorhex': '(?:[0-9a-fA-F]{3}){1,2}',
42 'colorname': '[a-zA-Z]+',
43 'padding': 'P[0-9]{2}',
44 'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)',
45 'zoomsym': 'Z[0-9]{2},[0-9]+(?:\\.[0-9]+)?(?:,[0-9]{3}x[0-9]{3})?',
46 'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}',
47 'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}'
48 };
49 re$1.colorbase = `(?:${re$1.colorhex}|${re$1.colorname})`;
50 re$1.color = `_${re$1.colorbase}_`;
51 re$1.colors = `_${re$1.colorbase}(?:,${re$1.colorbase})?_`;
52 re$1.background = `G${re$1.color}`;
53 re$1.detail = `D${re$1.colors}`;
54 re$1.detailsym = `D[0-9]{2}${re$1.colors}`;
55 re$1.classes = `${re$1.classbase}(?: ${re$1.classbase})*`;
56 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})!)?)?`;
57
58 /** 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.
59 * [Characters set definitions](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2)
60 * @module convert
61 */
62 /**
63 * Function to convert an SWU number character to an integer
64 * @function convert.swu2num
65 * @param {string} swuNum - SWU number character
66 * @returns {number} Integer value for number
67 * @example
68 * convert.swu2num('𝤆')
69 *
70 * return 500
71 */
72
73
74 const swu2num = swuNum => parseInt(swuNum.codePointAt(0)) - 0x1D80C + 250;
75 /**
76 * Function to convert a number to an SWU number character
77 * @function convert.num2swu
78 * @param {number} num - Integer value for number
79 * @returns {string} SWU number character
80 * @example
81 * convert.num2swu(500)
82 *
83 * return '𝤆'
84 */
85
86
87 const num2swu = num => String.fromCodePoint(0x1D80C + parseInt(num) - 250);
88 /**
89 * Function to convert two SWU number characters to an array of x,y integers
90 * @function convert.swu2coord
91 * @param {string} swuCoord - Two SWU number character
92 * @returns {number[]} Array of x,y integers
93 * @example
94 * convert.swu2coord('𝤆𝤆')
95 *
96 * return [500, 500]
97 */
98
99
100 const swu2coord = swuCoord => [swu2num(swuCoord.slice(0, 2)), swu2num(swuCoord.slice(2, 4))];
101 /**
102 * Function to convert an array of x,y integers to two SWU number characters
103 * @function convert.coord2swu
104 * @param {number[]} coord - Array of x,y integers
105 * @returns {string} Two SWU number character
106 * @example
107 * convert.coord2swu([500, 500])
108 *
109 * return '𝤆𝤆'
110 */
111
112
113 const coord2swu = coord => coord.map(num => num2swu(num)).join('');
114 /**
115 * Function to convert an SWU symbol character to a code point on plane 4
116 * @function convert.swu2code
117 * @param {string} swuSym - SWU symbol character
118 * @returns {number} Code point on plane 4
119 * @example
120 * convert.swu2code('񀀁')
121 *
122 * return 0x40001
123 */
124
125
126 const swu2code = swuSym => parseInt(swuSym.codePointAt(0));
127
128 const parse = {
129 /**
130 * Function to parse an swu symbol with optional coordinate and style string
131 * @function swu.parse.symbol
132 * @param {string} swuSym - an swu symbol
133 * @returns {object} elements of swu symbol
134 * @example
135 * swu.parse.symbol('񀀁𝤆𝤆-C')
136 *
137 * return {
138 * 'symbol': '񀀁',
139 * 'coord': [500, 500],
140 * 'style': '-C'
141 * }
142 */
143 symbol: swuSym => {
144 const regex = `^(${re.symbol})(${re.coord})?(${re$1.full})?`;
145 const symbol = typeof swuSym === 'string' ? swuSym.match(new RegExp(regex)) : undefined;
146 return {
147 'symbol': symbol ? symbol[1] : undefined,
148 'coord': symbol && symbol[2] ? swu2coord(symbol[2]) : undefined,
149 'style': symbol ? symbol[3] : undefined
150 };
151 },
152
153 /**
154 * Function to parse an swu sign with style string
155 * @function swu.parse.sign
156 * @param {string} swuSign - an swu sign
157 * @returns {object} elements of swu sign
158 * @example
159 * swu.parse.sign('𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭-C')
160 *
161 * return {
162 * sequence: ['񀀒','񀀚','񋚥','񋛩''],
163 * box: '𝠃',
164 * max: [525, 535],
165 * spatials: [
166 * {
167 * symbol: '񋛩',
168 * coord: [483, 510]
169 * },
170 * {
171 * symbol: '񀀒',
172 * coord: [501, 466]
173 * },
174 * {
175 * symbol: '񋚥',
176 * coord: [510, 500]
177 * },
178 * {
179 * symbol: '񀀚',
180 * coord: [476, 475]
181 * }
182 * ],
183 * style: '-C'
184 * }
185 */
186 sign: swuSign => {
187 const regex = `^(${re.prefix})?(${re.signbox})(${re$1.full})?`;
188 const sign = typeof swuSign === 'string' ? swuSign.match(new RegExp(regex)) : undefined;
189
190 if (sign) {
191 return {
192 'sequence': sign[1] ? sign[1].slice(2).match(/.{2}/g) : undefined,
193 'box': sign[2].slice(0, 2),
194 'max': swu2coord(sign[2].slice(2, 6)),
195 'spatials': sign[2].length < 7 ? undefined : sign[2].slice(6).match(/(.{6})/g).map(m => {
196 return {
197 symbol: m.slice(0, 2),
198 coord: swu2coord(m.slice(2))
199 };
200 }),
201 'style': sign[3]
202 };
203 } else {
204 return {};
205 }
206 }
207 };
208 /**
209 * Function to encode SWU characters using the UTF-16 escape format.
210 * @function swu.encode
211 * @param {string} swu - SWU characters
212 * @returns {string} UTF-16 escape format
213 * @example
214 * swu.encode('񀀁𝤆𝤆')
215 *
216 * return '\\uD8C0\\uDC01\\uD836\\uDD06\\uD836\\uDD06'
217 */
218
219 const encode = text => text.replace(/[\u007F-\uFFFF]/g, function (chr) {
220 return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4).toUpperCase();
221 });
222 /**
223 * Function to decode UTF-16 escape format to SWU characters.
224 * @function swu.decode
225 * @param {string} encoded - UTF-16 escape format
226 * @returns {string} SWU characters
227 * @example
228 * swu.decode('\\uD8C0\\uDC01\\uD836\\uDD06\\uD836\\uDD06')
229 *
230 * return '񀀁𝤆𝤆'
231 */
232
233
234 const decode = encoded => encoded.replace(/\\u([0-9A-F]{4})/g, function (match, chr) {
235 return String.fromCharCode(parseInt(chr, 16));
236 });
237 /**
238 * Function to decompose an SWU character into UTF-16 surrogate pairs.
239 * @function swu.pair
240 * @param {string} swuChar - an SWU character
241 * @returns {string[]} an array of UTF-16 surrogate pairs
242 * @example
243 * swu.pair('񀀁')
244 *
245 * return ['D8C0', 'DC01']
246 */
247
248
249 const pair = swuChar => [swuChar.charCodeAt(0).toString(16).toUpperCase(), swuChar.charCodeAt(1).toString(16).toUpperCase()];
250
251 const compose = {
252 /**
253 * Function to compose an swu symbol with optional coordinate and style string
254 * @function swu.compose.symbol
255 * @param {object} swuSymObject - an swu symbol object
256 * @param {string} swuSymObject.symbol - an swu symbol key
257 * @param {number[]} swuSymObject.coord - top-left coordinate of symbol with 500,500 center
258 * @param {string} swuSymObject.style - a style string for custom appearance
259 * @returns {string} an swu symbol string
260 * @example
261 * swu.compose.symbol({
262 * 'symbol': '񀀁',
263 * 'coord': [500, 500],
264 * 'style': '-C'
265 * })
266 *
267 * return '񀀁𝤆𝤆-C'
268 */
269 symbol: swuSymObject => {
270 if (typeof swuSymObject !== 'object' || swuSymObject === null) return undefined;
271
272 if (typeof swuSymObject.symbol === 'string') {
273 const symbol = (swuSymObject.symbol.match(re.symbol) || [''])[0];
274
275 if (symbol) {
276 const x = swuSymObject.coord && swuSymObject.coord[0] || '';
277 const y = swuSymObject.coord && swuSymObject.coord[1] || '';
278 const coord = x && y ? coord2swu([x, y]) : '';
279 const styleStr = typeof swuSymObject.style === 'string' && (swuSymObject.style.match(re$1.full) || [''])[0] || '';
280 return symbol + coord + styleStr;
281 }
282 }
283
284 return undefined;
285 },
286
287 /**
288 * Function to compose an swu sign with style string
289 * @function swu.compose.sign
290 * @param {string[]} swuSignObject.sequence - an ordered array of symbols
291 * @param {string} swuSignObject.box - a choice BLMR: horizontal Box, Left, Middle, and Right lane
292 * @param {number[]} swuSymObject.max - max bottom left coordinate of the signbox space
293 * @param {{symbol:string,coord:number[]}[]} swuSymObject.spatials - array of symbols with top-left coordinate placement
294 * @param {string} swuSymObject.style - a style string for custom appearance
295 * @returns {string} an swu sign string
296 * @example
297 * swu.compose.sign({
298 * sequence: ['񀀒','񀀚','񋚥','񋛩''],
299 * box: '𝠃',
300 * max: [525, 535],
301 * spatials: [
302 * {
303 * symbol: '񋛩',
304 * coord: [483, 510]
305 * },
306 * {
307 * symbol: '񀀒',
308 * coord: [501, 466]
309 * },
310 * {
311 * symbol: '񋚥',
312 * coord: [510, 500]
313 * },
314 * {
315 * symbol: '񀀚',
316 * coord: [476, 475]
317 * }
318 * ],
319 * style: '-C'
320 * })
321 *
322 * return '𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭-C'
323 */
324 sign: swuSignObject => {
325 if (typeof swuSignObject !== 'object' || swuSignObject === null) return undefined;
326 let box = typeof swuSignObject.box !== 'string' ? '𝠃' : (swuSignObject.box + '𝠃').match(re.box);
327 const x = swuSignObject.max && swuSignObject.max[0] || '';
328 const y = swuSignObject.max && swuSignObject.max[1] || '';
329 const max = x && y ? coord2swu([x, y]) : undefined;
330 if (!max) return undefined;
331 let prefix = '';
332
333 if (swuSignObject.sequence && Array.isArray(swuSignObject.sequence)) {
334 prefix = swuSignObject.sequence.map(key => (key.match(re.symbol) || [''])[0]).join('');
335 prefix = prefix ? '𝠀' + prefix : '';
336 }
337
338 let signbox = '';
339
340 if (swuSignObject.spatials && Array.isArray(swuSignObject.spatials)) {
341 signbox = swuSignObject.spatials.map(spatial => {
342 if (typeof spatial.symbol === 'string') {
343 const symbol = (spatial.symbol.match(re.symbol) || [''])[0];
344
345 if (symbol) {
346 const x = spatial.coord && spatial.coord[0] || '';
347 const y = spatial.coord && spatial.coord[1] || '';
348 const coord = x && y ? coord2swu([x, y]) : '';
349
350 if (coord) {
351 return symbol + coord;
352 }
353 }
354 }
355
356 return '';
357 }).join('');
358 }
359
360 const styleStr = typeof swuSignObject.style === 'string' && (swuSignObject.style.match(re$1.full) || [''])[0] || '';
361 return prefix + box + max + signbox + styleStr;
362 }
363 };
364
365 /**
366 * Array of plane 4 code points for kinds of symbols: writing, location, and punctuation.
367 * @alias swu.kind
368 * @type {array}
369 */
370
371 const kind = [0x40001, 0x4efa1, 0x4f2a1];
372 /**
373 * Array of plane 4 code points for categories of symbols: hand, movement, dynamics, head, trunk & limb, location, and punctuation.
374 * @alias swu.category
375 * @type {array}
376 */
377
378 const category = [0x40001, 0x461e1, 0x4bca1, 0x4bfa1, 0x4e8e1, 0x4efa1, 0x4f2a1];
379 /**
380 * Array of plane 4 code points for the 30 symbol groups.
381 * @alias swu.group
382 * @type {array}
383 */
384
385 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];
386 /**
387 * Object of symbol ranges with starting and ending code points on plane 4.
388 *
389 * { all, writing, hand, movement, dynamic, head, hcenter, vcenter, trunk, limb, location, punctuation }
390 * @alias swu.ranges
391 * @type {object}
392 */
393
394 const ranges = {
395 'all': [0x40001, 0x4f480],
396 'writing': [0x40001, 0x4efa0],
397 'hand': [0x40001, 0x461e0],
398 'movement': [0x461e1, 0x4bca0],
399 'dynamic': [0x4bca1, 0x4bfa0],
400 'head': [0x4bfa1, 0x4e8e0],
401 'hcenter': [0x4bfa1, 0x4e8e0],
402 'vcenter': [0x4bfa1, 0x4ec40],
403 'trunk': [0x4e8e1, 0x4ec40],
404 'limb': [0x4ec41, 0x4efa0],
405 'location': [0x4efa1, 0x4f2a0],
406 'punctuation': [0x4f2a1, 0x4f480]
407 };
408 /**
409 * Function to test if symbol is of a certain type.
410 * @function swu.isType
411 * @param {string} swuSym - an SWU symbol character
412 * @param {string} type - the name of a symbol range
413 * @returns {boolean} is symbol of specified type
414 * @example
415 * swu.isType('񀀁', 'hand')
416 *
417 * return true
418 */
419
420 const isType = (swuSym, type) => {
421 const parsed = parse.symbol(swuSym);
422
423 if (parsed.symbol) {
424 const code = swu2code(parsed.symbol);
425 const range = ranges[type];
426
427 if (range) {
428 return range[0] <= code && range[1] >= code;
429 }
430 }
431
432 return false;
433 };
434
435 /**
436 * Array of colors associated with the seven symbol categories.
437 * @alias swu.colors
438 * @type {array}
439 */
440
441 const colors = ['#0000CC', '#CC0000', '#FF0099', '#006600', '#000000', '#884411', '#FF9900'];
442 /**
443 * Function that returns the standardized color for a symbol.
444 * @function swu.colorize
445 * @param {string} swuSym - an SWU symbol character
446 * @returns {string} name of standardized color for symbol
447 * @example
448 * swu.colorize('񀀁')
449 *
450 * return '#0000CC'
451 */
452
453 const colorize = swuSym => {
454 const parsed = parse.symbol(swuSym);
455 let color = '#000000';
456
457 if (parsed.symbol) {
458 const code = swu2code(parsed.symbol);
459 const index = category.findIndex(val => val > code);
460 color = colors[index < 0 ? 6 : index - 1];
461 }
462
463 return color;
464 };
465
466 exports.category = category;
467 exports.colorize = colorize;
468 exports.colors = colors;
469 exports.compose = compose;
470 exports.decode = decode;
471 exports.encode = encode;
472 exports.group = group;
473 exports.isType = isType;
474 exports.kind = kind;
475 exports.pair = pair;
476 exports.parse = parse;
477 exports.ranges = ranges;
478 exports.re = re;
479
480 Object.defineProperty(exports, '__esModule', { value: true });
481
482}));
483
484/* support ongoing development on https://patreon.com/signwriting */