UNPKG

84.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* core.mjs is released under the MIT License.
5*/
6
7/**
8 * Object of regular expressions for FSW strings
9 *
10 * { symbol, coord, sort, box, prefix, spatial, signbox, sign, sortable }
11 * @alias fsw.re
12 * @type {object}
13 */
14let re = {
15 'symbol': 'S[123][0-9a-f]{2}[0-5][0-9a-f]',
16 'coord': '[0-9]{3}x[0-9]{3}',
17 'sort': 'A',
18 'box': '[BLMR]'
19};
20re.prefix = `(?:${re.sort}(?:${re.symbol})+)`;
21re.spatial = `${re.symbol}${re.coord}`;
22re.signbox = `${re.box}${re.coord}(?:${re.spatial})*`;
23re.sign = `${re.prefix}?${re.signbox}`;
24re.sortable = `${re.prefix}${re.signbox}`;
25
26/**
27 * Object of regular expressions for style strings
28 *
29 * { colorize, colorhex, colorname, padding, zoom, zoomsym, classbase, id, colorbase, color, colors, background, detail, detailsym, classes, full }
30 * @alias style.re
31 * @type {object}
32 */
33let re$1 = {
34 'colorize': 'C',
35 'colorhex': '(?:[0-9a-fA-F]{3}){1,2}',
36 'colorname': '[a-zA-Z]+',
37 'padding': 'P[0-9]{2}',
38 'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)',
39 'zoomsym': 'Z[0-9]{2},[0-9]+(?:\\.[0-9]+)?(?:,[0-9]{3}x[0-9]{3})?',
40 'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}',
41 'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}'
42};
43re$1.colorbase = `(?:${re$1.colorhex}|${re$1.colorname})`;
44re$1.color = `_${re$1.colorbase}_`;
45re$1.colors = `_${re$1.colorbase}(?:,${re$1.colorbase})?_`;
46re$1.background = `G${re$1.color}`;
47re$1.detail = `D${re$1.colors}`;
48re$1.detailsym = `D[0-9]{2}${re$1.colors}`;
49re$1.classes = `${re$1.classbase}(?: ${re$1.classbase})*`;
50re$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})!)?)?`;
51
52const prefixColor = color => {
53 const regex = new RegExp(`^${re$1.colorhex}$`);
54 return (regex.test(color) ? '#' : '') + color;
55};
56/**
57 * Function to parse style string to object
58 * @function style.parse
59 * @param {string} styleString - a style string
60 * @returns {object} elements of style string
61 * @example
62 * style.parse('-CP10G_blue_D_red,Cyan_')
63 *
64 * return {
65 * 'colorize': true,
66 * 'padding': 10,
67 * 'background': 'blue',
68 * 'detail': ['red', 'Cyan']
69 * }
70 */
71
72
73const parse = styleString => {
74 const regex = `^${re$1.full}`;
75 const m = (typeof styleString === 'string' ? styleString.match(new RegExp(regex)) : []) || [];
76 return {
77 'colorize': !m[1] ? undefined : !!m[1],
78 'padding': !m[2] ? undefined : parseInt(m[2].slice(1)),
79 'background': !m[3] ? undefined : prefixColor(m[3].slice(2, -1)),
80 'detail': !m[4] ? undefined : m[4].slice(2, -1).split(',').map(prefixColor),
81 'zoom': !m[5] ? undefined : m[5] === 'Zx' ? 'x' : parseFloat(m[5].slice(1)),
82 'detailsym': !m[6] ? undefined : m[6].match(new RegExp(re$1.detailsym, 'g')).map(val => {
83 const parts = val.split('_');
84 const detail = parts[1].split(',').map(prefixColor);
85 return {
86 'index': parseInt(parts[0].slice(1)),
87 'detail': detail
88 };
89 }),
90 'zoomsym': !m[7] ? undefined : m[7].match(new RegExp(re$1.zoomsym, 'g')).map(val => {
91 const parts = val.split(',');
92 return {
93 'index': parseInt(parts[0].slice(1)),
94 'zoom': parseFloat(parts[1]),
95 'offset': !parts[2] ? undefined : parts[2].split('x').map(val => parseInt(val) - 500)
96 };
97 }),
98 'classes': !m[8] ? undefined : m[8],
99 'id': !m[9] ? undefined : m[9]
100 };
101};
102
103/**
104 * Function to compose style string from object
105 * @function style.compose
106 * @param {object} styleObject - an object of style options
107 * @param {boolean} styleObject.colorize - boolean to use standardized colors for symbol groups
108 * @param {number} styleObject.padding - integer value for padding around symbol or sign
109 * @param {string} styleObject.background - css name or hex color for background
110 * @param {string[]} styleObject.detail - css name or hex color for line and optional fill
111 * @param {number} styleObject.zoom - decimal value for zoom level
112 * @param {{index:number,detail:string[]}[]} styleObject.detailsym - array of symbol indexes and detail color array
113 * @param {{index:number,zoom:number,offset:number[]}[]} styleObject.zoomsym - array of symbol indexes and zoom levels with optional x,y offset
114 * @param {string} styleObject.classes - list of class names separated with spaces used for SVG
115 * @param {string} styleObject.id - id name used for SVG
116 * @returns {string} style string
117 * @example
118 * style.compose({
119 * 'colorize': true,
120 * 'padding': 10,
121 * 'background': 'blue',
122 * 'detail': ['red', 'Cyan'],
123 * 'zoom': 1.1,
124 * 'detailsym': [
125 * {
126 * 'index': 1,
127 * 'detail': ['#ff00ff']
128 * },
129 * {
130 * 'index': 2,
131 * 'detail': ['yellow', 'green']
132 * }
133 * ],
134 * 'zoomsym': [
135 * {
136 * 'index': 1,
137 * 'zoom': 10,
138 * 'offset': [0, 0]
139 * },
140 * {
141 * 'index': 2,
142 * 'zoom': 5.5
143 * }
144 * ],
145 * 'classes': 'primary blinking',
146 * 'id': 'cursor'
147 * })
148 *
149 * return '-CP10G_blue_D_red,Cyan_Z1.1-D01_ff00ff_D02_yellow,green_Z01,10,500x500Z02,5.5-primary blinking!cursor!'
150 */
151
152const compose = styleObject => {
153 if (typeof styleObject !== 'object' || styleObject === null) return undefined; // three sections
154
155 let style1 = '-';
156 style1 += !styleObject.colorize ? '' : 'C';
157 const padding = parseInt(styleObject.padding);
158 style1 += !padding || padding <= 0 || padding > 99 ? '' : 'P' + (padding > 9 ? padding : '0' + padding);
159 const background = !styleObject.background || !(typeof styleObject.background === 'string') ? undefined : styleObject.background.match(re$1.colorbase)[0];
160 style1 += !background ? '' : 'G_' + background + '_';
161 const detail1 = !styleObject.detail || !styleObject.detail[0] || !(typeof styleObject.detail[0] === 'string') ? undefined : styleObject.detail[0].match(re$1.colorbase)[0];
162 const detail2 = !styleObject.detail || !styleObject.detail[1] || !(typeof styleObject.detail[1] === 'string') ? undefined : styleObject.detail[1].match(re$1.colorbase)[0];
163
164 if (detail1) {
165 style1 += 'D_' + detail1;
166
167 if (detail2) {
168 style1 += ',' + detail2;
169 }
170
171 style1 += '_';
172 }
173
174 const zoom = styleObject.zoom === 'x' ? 'x' : parseFloat(styleObject.zoom);
175 style1 += !zoom || zoom <= 0 ? '' : 'Z' + zoom;
176 let style2 = '';
177 const detailsym = !styleObject.detailsym || !Array.isArray(styleObject.detailsym) ? [] : styleObject.detailsym.map(styleObject => {
178 const index = parseInt(styleObject.index);
179 if (!index || index <= 0 || index > 99) return '';
180 let style = 'D' + (index > 9 ? index : '0' + index);
181 const detail1 = !styleObject.detail || !styleObject.detail[0] ? undefined : styleObject.detail[0].match(re$1.colorbase)[0];
182 const detail2 = !styleObject.detail || !styleObject.detail[1] ? undefined : styleObject.detail[1].match(re$1.colorbase)[0];
183
184 if (detail1) {
185 style += '_' + detail1;
186
187 if (detail2) {
188 style += ',' + detail2;
189 }
190
191 style += '_';
192 }
193
194 return style;
195 });
196 style2 += detailsym.join('');
197 const zoomsym = !styleObject.zoomsym || !Array.isArray(styleObject.zoomsym) ? [] : styleObject.zoomsym.map(styleObject => {
198 const index = parseInt(styleObject.index);
199 if (!index || index <= 0 || index > 99) return '';
200 let style = 'Z' + (index > 9 ? index : '0' + index);
201 const zoom = parseFloat(styleObject.zoom);
202 style += !zoom || zoom <= 0 ? '' : ',' + zoom;
203
204 if (styleObject.offset && 0 in styleObject.offset && 1 in styleObject.offset) {
205 const x = parseInt(styleObject.offset[0]) + 500;
206 const y = parseInt(styleObject.offset[1]) + 500;
207
208 if (x >= 250 && x < 750 && y >= 250 && y < 750) {
209 style += ',' + x + 'x' + y;
210 }
211 }
212
213 return style;
214 });
215 style2 += zoomsym.join('');
216 let style3 = '';
217 const classes = !styleObject.classes || !(typeof styleObject.classes === 'string') ? undefined : styleObject.classes.match(re$1.classes)[0];
218 style3 += !classes ? '' : classes;
219 const id = !styleObject.id || !(typeof styleObject.id === 'string') ? undefined : styleObject.id.match(re$1.id)[0];
220 style3 += classes || id ? '!' : '';
221 style3 += !id ? '' : id + '!';
222 return style1 + (style2 || style3 ? '-' + style2 : '') + (style3 ? '-' + style3 : '');
223};
224
225/** The style module contains regular expressions and functions for parsing and composing style strings.
226 * [Style string definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.5)
227 * @module style
228 */
229
230var index = /*#__PURE__*/Object.freeze({
231 __proto__: null,
232 re: re$1,
233 parse: parse,
234 compose: compose
235});
236
237/**
238 * Object of regular expressions for SWU strings in UTF-16
239 *
240 * { symbol, coord, sort, box, prefix, spatial, signbox, sign, sortable }
241 * @alias swu.re
242 * @type {object}
243 */
244let re$2 = {
245 'symbol': '(?:(?:\uD8C0[\uDC01-\uDFFF])|(?:[\uD8C1-\uD8FC][\uDC00-\uDFFF])|(?:\uD8FD[\uDC00-\uDC80]))',
246 'coord': '(?:\uD836[\uDC0C-\uDDFF]){2}',
247 'sort': '\uD836\uDC00',
248 'box': '\uD836[\uDC01-\uDC04]'
249};
250re$2.prefix = `(?:${re$2.sort}(?:${re$2.symbol})+)`;
251re$2.spatial = `${re$2.symbol}${re$2.coord}`;
252re$2.signbox = `${re$2.box}${re$2.coord}(?:${re$2.spatial})*`;
253re$2.sign = `${re$2.prefix}?${re$2.signbox}`;
254re$2.sortable = `${re$2.prefix}${re$2.signbox}`;
255
256/** 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.
257 * [Characters set definitions](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2)
258 * @module convert
259 */
260/**
261 * Function to convert an SWU structural marker to FSW equivalent
262 * @function convert.swu2mark
263 * @param {string} swuMark - character for SWU structural marker
264 * @returns {string} FSW structural marker
265 * @example
266 * convert.swu2mark('𝠀')
267 *
268 * return 'A'
269 */
270
271const swu2mark = swuMark => {
272 return {
273 '𝠀': 'A',
274 '𝠁': 'B',
275 '𝠂': 'L',
276 '𝠃': 'M',
277 '𝠄': 'R'
278 }[swuMark];
279};
280/**
281 * Function to convert an FSW structural marker to SWU equivalent
282 * @function convert.mark2swu
283 * @param {string} fswMark - character for FSW structural marker
284 * @returns {string} SWU structural marker
285 * @example
286 * convert.mark2swu('A')
287 *
288 * return '𝠀'
289 */
290
291
292const mark2swu = fswMark => {
293 return {
294 'A': '𝠀',
295 'B': '𝠁',
296 'L': '𝠂',
297 'M': '𝠃',
298 'R': '𝠄'
299 }[fswMark];
300};
301/**
302 * Function to convert an SWU number character to an integer
303 * @function convert.swu2num
304 * @param {string} swuNum - SWU number character
305 * @returns {number} Integer value for number
306 * @example
307 * convert.swu2num('𝤆')
308 *
309 * return 500
310 */
311
312
313const swu2num = swuNum => parseInt(swuNum.codePointAt(0)) - 0x1D80C + 250;
314/**
315 * Function to convert a number to an SWU number character
316 * @function convert.num2swu
317 * @param {number} num - Integer value for number
318 * @returns {string} SWU number character
319 * @example
320 * convert.num2swu(500)
321 *
322 * return '𝤆'
323 */
324
325
326const num2swu = num => String.fromCodePoint(0x1D80C + parseInt(num) - 250);
327/**
328 * Function to convert two SWU number characters to an array of x,y integers
329 * @function convert.swu2coord
330 * @param {string} swuCoord - Two SWU number character
331 * @returns {number[]} Array of x,y integers
332 * @example
333 * convert.swu2coord('𝤆𝤆')
334 *
335 * return [500, 500]
336 */
337
338
339const swu2coord = swuCoord => [swu2num(swuCoord.slice(0, 2)), swu2num(swuCoord.slice(2, 4))];
340/**
341 * Function to convert an array of x,y integers to two SWU number characters
342 * @function convert.coord2swu
343 * @param {number[]} coord - Array of x,y integers
344 * @returns {string} Two SWU number character
345 * @example
346 * convert.coord2swu([500, 500])
347 *
348 * return '𝤆𝤆'
349 */
350
351
352const coord2swu = coord => coord.map(num => num2swu(num)).join('');
353/**
354 * Function to convert an FSW coordinate string to an array of x,y integers
355 * @function convert.fsw2coord
356 * @param {string} fswCoord - An FSW coordinate string
357 * @returns {number[]} Array of x,y integers
358 * @example
359 * convert.fsw2coord('500x500')
360 *
361 * return [500, 500]
362 */
363
364
365const fsw2coord = fswCoord => fswCoord.split('x').map(num => parseInt(num));
366/**
367 * Function to convert an array of x,y integers to an FSW coordinate string
368 * @function convert.coord2fsw
369 * @param {number[]} coord - Array of x,y integers
370 * @returns {string} An FSW coordinate string
371 * @example
372 * convert.coord2fsw([500, 500])
373 *
374 * return '500x500'
375 */
376
377
378const coord2fsw = coord => coord.join('x');
379/**
380 * Function to convert an SWU symbol character to a code point on plane 4
381 * @function convert.swu2code
382 * @param {string} swuSym - SWU symbol character
383 * @returns {number} Code point on plane 4
384 * @example
385 * convert.swu2code('񀀁')
386 *
387 * return 0x40001
388 */
389
390
391const swu2code = swuSym => parseInt(swuSym.codePointAt(0));
392/**
393 * Function to convert a code point on plane 4 to an SWU symbol character
394 * @function convert.code2swu
395 * @param {number} code - Code point on plane 4
396 * @returns {string} SWU symbol character
397 * @example
398 * convert.code2swu(0x40001)
399 *
400 * return '񀀁'
401 */
402
403
404const code2swu = code => String.fromCodePoint(code);
405/**
406 * Function to convert an SWU symbol character to a 16-bit ID
407 * @function convert.swu2id
408 * @param {string} swuSym - SWU symbol character
409 * @returns {number} 16-bit ID
410 * @example
411 * convert.swu2id('񀀁')
412 *
413 * return 1
414 */
415
416
417const swu2id = swuSym => swu2code(swuSym) - 0x40000;
418/**
419 * Function to convert a 16-bit ID to an SWU symbol character
420 * @function convert.id2swu
421 * @param {number} id - 16-bit ID
422 * @returns {string} SWU symbol character
423 * @example
424 * convert.id2swu(1)
425 *
426 * return '񀀁'
427 */
428
429
430const id2swu = id => code2swu(id + 0x40000);
431/**
432 * Function to convert an FSW symbol key to a 16-bit ID
433 * @function convert.key2id
434 * @param {string} key - FSW symbol key
435 * @returns {number} 16-bit ID
436 * @example
437 * convert.key2id('S10000')
438 *
439 * return 1
440 */
441
442
443const key2id = key => 1 + (parseInt(key.slice(1, 4), 16) - 256) * 96 + parseInt(key.slice(4, 5), 16) * 16 + parseInt(key.slice(5, 6), 16);
444/**
445 * Function to convert a 16-bit ID to an FSW symbol key
446 * @function convert.id2key
447 * @param {number} id - 16-bit ID
448 * @returns {string} FSW symbol key
449 * @example
450 * convert.id2key(1)
451 *
452 * return 'S10000'
453 */
454
455
456const id2key = id => {
457 const symcode = id - 1;
458 const base = parseInt(symcode / 96);
459 const fill = parseInt((symcode - base * 96) / 16);
460 const rotation = parseInt(symcode - base * 96 - fill * 16);
461 return 'S' + (base + 0x100).toString(16) + fill.toString(16) + rotation.toString(16);
462};
463/**
464 * Function to convert an SWU symbol character to an FSW symbol key
465 * @function convert.swu2key
466 * @param {string} swuSym - SWU symbol character
467 * @returns {string} FSW symbol key
468 * @example
469 * convert.swu2key('񀀁')
470 *
471 * return 'S10000'
472 */
473
474
475const swu2key = swuSym => {
476 const symcode = swu2code(swuSym) - 0x40001;
477 const base = parseInt(symcode / 96);
478 const fill = parseInt((symcode - base * 96) / 16);
479 const rotation = parseInt(symcode - base * 96 - fill * 16);
480 return 'S' + (base + 0x100).toString(16) + fill.toString(16) + rotation.toString(16);
481};
482/**
483 * Function to convert an FSW symbol key to an SWU symbol character
484 * @function convert.key2swu
485 * @param {string} key - FSW symbol key
486 * @returns {string} SWU symbol character
487 * @example
488 * convert.key2swu('S10000')
489 *
490 * return '񀀁'
491 */
492
493
494const key2swu = key => code2swu(0x40001 + (parseInt(key.slice(1, 4), 16) - 256) * 96 + parseInt(key.slice(4, 5), 16) * 16 + parseInt(key.slice(5, 6), 16));
495/**
496 * Function to convert SWU text to FSW text
497 * @function convert.swu2fsw
498 * @param {string} swuText - SWU text
499 * @returns {string} FSW text
500 * @example
501 * convert.swu2fsw('𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭')
502 *
503 * return 'AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475'
504 */
505
506
507const swu2fsw = swuText => {
508 if (!swuText) return '';
509 let fsw = swuText.replace(/𝠀/g, "A").replace(/𝠁/g, "B").replace(/𝠂/g, "L").replace(/𝠃/g, "M").replace(/𝠄/g, "R");
510 const syms = fsw.match(new RegExp(re$2.symbol, 'g'));
511
512 if (syms) {
513 syms.forEach(function (sym) {
514 fsw = fsw.replace(sym, swu2key(sym));
515 });
516 }
517
518 const coords = fsw.match(new RegExp(re$2.coord, 'g'));
519
520 if (coords) {
521 coords.forEach(function (coord) {
522 fsw = fsw.replace(coord, swu2coord(coord).join('x'));
523 });
524 }
525
526 return fsw;
527};
528/**
529 * Function to convert FSW text to SWU text
530 * @function convert.fsw2swu
531 * @param {string} fswText - FSW text
532 * @returns {string} SWU text
533 * @example
534 * convert.fsw2swu('AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475')
535 *
536 * return '𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭'
537 */
538
539
540const fsw2swu = fswText => {
541 if (!fswText) return '';
542 const prefixes = fswText.match(new RegExp(re.prefix, 'g'));
543
544 if (prefixes) {
545 prefixes.forEach(function (prefix) {
546 fswText = fswText.replace(prefix, '𝠀' + prefix.slice(1).match(/.{6}/g).map(key => key2swu(key)).join(''));
547 });
548 }
549
550 const boxes = fswText.match(new RegExp(re.box + re.coord, 'g'));
551
552 if (boxes) {
553 boxes.forEach(function (boxes) {
554 fswText = fswText.replace(boxes, mark2swu(boxes.slice(0, 1)) + coord2swu(fsw2coord(boxes.slice(1, 8))));
555 });
556 }
557
558 const spatials = fswText.match(new RegExp(re.spatial, 'g'));
559
560 if (spatials) {
561 spatials.forEach(function (spatial) {
562 fswText = fswText.replace(spatial, key2swu(spatial.slice(0, 6)) + coord2swu(fsw2coord(spatial.slice(6, 13))));
563 });
564 }
565
566 return fswText;
567};
568
569var index$1 = /*#__PURE__*/Object.freeze({
570 __proto__: null,
571 swu2mark: swu2mark,
572 mark2swu: mark2swu,
573 swu2num: swu2num,
574 num2swu: num2swu,
575 swu2coord: swu2coord,
576 coord2swu: coord2swu,
577 fsw2coord: fsw2coord,
578 coord2fsw: coord2fsw,
579 swu2code: swu2code,
580 code2swu: code2swu,
581 swu2id: swu2id,
582 id2swu: id2swu,
583 key2id: key2id,
584 id2key: id2key,
585 swu2key: swu2key,
586 key2swu: key2swu,
587 swu2fsw: swu2fsw,
588 fsw2swu: fsw2swu
589});
590
591const parse$1 = {
592 /**
593 * Function to parse an fsw symbol with optional coordinate and style string
594 * @function fsw.parse.symbol
595 * @param {string} fswSym - an fsw symbol
596 * @returns {object} elements of fsw symbol
597 * @example
598 * fsw.parse.symbol('S10000500x500-C')
599 *
600 * return {
601 * 'symbol': 'S10000',
602 * 'coord': [500, 500],
603 * 'style': '-C'
604 * }
605 */
606 symbol: fswSym => {
607 const regex = `^(${re.symbol})(${re.coord})?(${re$1.full})?`;
608 const symbol = typeof fswSym === 'string' ? fswSym.match(new RegExp(regex)) : undefined;
609 return {
610 'symbol': symbol ? symbol[1] : undefined,
611 'coord': symbol && symbol[2] ? fsw2coord(symbol[2]) : undefined,
612 'style': symbol ? symbol[3] : undefined
613 };
614 },
615
616 /**
617 * Function to parse an fsw sign with style string
618 * @function fsw.parse.sign
619 * @param {string} fswSign - an fsw sign
620 * @returns {object} elements of fsw sign
621 * @example
622 * fsw.parse.sign('AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475-C')
623 *
624 * return {
625 * sequence: ['S10011', 'S10019', 'S2e704', 'S2e748'],
626 * box: 'M',
627 * max: [525, 535],
628 * spatials: [
629 * {
630 * symbol: 'S2e748',
631 * coord: [483, 510]
632 * },
633 * {
634 * symbol: 'S10011',
635 * coord: [501, 466]
636 * },
637 * {
638 * symbol: 'S2e704',
639 * coord: [510, 500]
640 * },
641 * {
642 * symbol: 'S10019',
643 * coord: [476, 475]
644 * }
645 * ],
646 * style: '-C'
647 * }
648 */
649 sign: fswSign => {
650 const regex = `^(${re.prefix})?(${re.signbox})(${re$1.full})?`;
651 const sign = typeof fswSign === 'string' ? fswSign.match(new RegExp(regex)) : undefined;
652
653 if (sign) {
654 return {
655 'sequence': sign[1] ? sign[1].slice(1).match(/.{6}/g) : undefined,
656 'box': sign[2][0],
657 'max': fsw2coord(sign[2].slice(1, 8)),
658 'spatials': sign[2].length < 9 ? undefined : sign[2].slice(8).match(/(.{13})/g).map(m => {
659 return {
660 symbol: m.slice(0, 6),
661 coord: [parseInt(m.slice(6, 9)), parseInt(m.slice(10, 13))]
662 };
663 }),
664 'style': sign[3]
665 };
666 } else {
667 return {};
668 }
669 }
670};
671
672const compose$1 = {
673 /**
674 * Function to compose an fsw symbol with optional coordinate and style string
675 * @function fsw.compose.symbol
676 * @param {object} fswSymObject - an fsw symbol object
677 * @param {string} fswSymObject.symbol - an fsw symbol key
678 * @param {number[]} fswSymObject.coord - top-left coordinate of symbol with 500,500 center
679 * @param {string} fswSymObject.style - a style string for custom appearance
680 * @returns {string} an fsw symbol string
681 * @example
682 * fsw.compose.symbol({
683 * 'symbol': 'S10000',
684 * 'coord': [480, 480],
685 * 'style': '-C'
686 * })
687 *
688 * return 'S10000480x480-C'
689 */
690 symbol: fswSymObject => {
691 if (typeof fswSymObject.symbol === 'string') {
692 const symbol = (fswSymObject.symbol.match(re.symbol) || [''])[0];
693
694 if (symbol) {
695 const x = (fswSymObject.coord && fswSymObject.coord[0] || '').toString();
696 const y = (fswSymObject.coord && fswSymObject.coord[1] || '').toString();
697 const coord = ((x + 'x' + y).match(re.coord) || [''])[0] || '';
698 const styleStr = typeof fswSymObject.style === 'string' && (fswSymObject.style.match(re$1.full) || [''])[0] || '';
699 return symbol + coord + styleStr;
700 }
701 }
702
703 return undefined;
704 },
705
706 /**
707 * Function to compose an fsw sign with style string
708 * @function fsw.compose.sign
709 * @param {string[]} fswSignObject.sequence - an ordered array of symbols
710 * @param {string} fswSignObject.box - a choice BLMR: horizontal Box, Left, Middle, and Right lane
711 * @param {number[]} fswSymObject.max - max bottom left coordinate of the signbox space
712 * @param {{symbol:string,coord:number[]}[]} fswSymObject.spatials - array of symbols with top-left coordinate placement
713 * @param {string} fswSymObject.style - a style string for custom appearance
714 * @returns {string} an fsw sign string
715 * @example
716 * fsw.compose.sign({
717 * sequence: ['S10011', 'S10019', 'S2e704', 'S2e748'],
718 * box: 'M',
719 * max: [525, 535],
720 * spatials: [
721 * {
722 * symbol: 'S2e748',
723 * coord: [483, 510]
724 * },
725 * {
726 * symbol: 'S10011',
727 * coord: [501, 466]
728 * },
729 * {
730 * symbol: 'S2e704',
731 * coord: [510, 500]
732 * },
733 * {
734 * symbol: 'S10019',
735 * coord: [476, 475]
736 * }
737 * ],
738 * style: '-C'
739 * })
740 *
741 * return 'AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475-C'
742 */
743 sign: fswSignObject => {
744 let box = typeof fswSignObject.box !== 'string' ? 'M' : (fswSignObject.box + 'M').match(re.box);
745 const x = (fswSignObject.max && fswSignObject.max[0] || '').toString();
746 const y = (fswSignObject.max && fswSignObject.max[1] || '').toString();
747 const max = ((x + 'x' + y).match(re.coord) || [''])[0] || '';
748 if (!max) return undefined;
749 let prefix = '';
750
751 if (fswSignObject.sequence && Array.isArray(fswSignObject.sequence)) {
752 prefix = fswSignObject.sequence.map(key => (key.match(re.symbol) || [''])[0]).join('');
753 prefix = prefix ? 'A' + prefix : '';
754 }
755
756 let signbox = '';
757
758 if (fswSignObject.spatials && Array.isArray(fswSignObject.spatials)) {
759 signbox = fswSignObject.spatials.map(spatial => {
760 if (typeof spatial.symbol === 'string') {
761 const symbol = (spatial.symbol.match(re.symbol) || [''])[0];
762
763 if (symbol) {
764 const x = (spatial.coord && spatial.coord[0] || '').toString();
765 const y = (spatial.coord && spatial.coord[1] || '').toString();
766 const coord = ((x + 'x' + y).match(re.coord) || [''])[0] || '';
767
768 if (coord) {
769 return symbol + coord;
770 }
771 }
772 }
773
774 return '';
775 }).join('');
776 }
777
778 const styleStr = typeof fswSignObject.style === 'string' && (fswSignObject.style.match(re$1.full) || [''])[0] || '';
779 return prefix + box + max + signbox + styleStr;
780 }
781};
782
783/**
784 * Array of numbers for kinds of symbols: writing, location, and punctuation.
785 * @alias fsw.kind
786 * @type {array}
787 */
788
789const kind = [0x100, 0x37f, 0x387];
790/**
791 * Array of numbers for categories of symbols: hand, movement, dynamics, head, trunk & limb, location, and punctuation.
792 * @alias fsw.category
793 * @type {array}
794 */
795
796const category = [0x100, 0x205, 0x2f7, 0x2ff, 0x36d, 0x37f, 0x387];
797/**
798 * Array of numbers for the 30 symbol groups.
799 * @alias fsw.group
800 * @type {array}
801 */
802
803const group = [0x100, 0x10e, 0x11e, 0x144, 0x14c, 0x186, 0x1a4, 0x1ba, 0x1cd, 0x1f5, 0x205, 0x216, 0x22a, 0x255, 0x265, 0x288, 0x2a6, 0x2b7, 0x2d5, 0x2e3, 0x2f7, 0x2ff, 0x30a, 0x32a, 0x33b, 0x359, 0x36d, 0x376, 0x37f, 0x387];
804/**
805 * Object of symbol ranges with starting and ending numbers.
806 *
807 * { all, writing, hand, movement, dynamic, head, hcenter, vcenter, trunk, limb, location, punctuation }
808 * @alias fsw.ranges
809 * @type {object}
810 */
811
812const ranges = {
813 'all': [0x100, 0x38b],
814 'writing': [0x100, 0x37e],
815 'hand': [0x100, 0x204],
816 'movement': [0x205, 0x2f6],
817 'dynamic': [0x2f7, 0x2fe],
818 'head': [0x2ff, 0x36c],
819 'hcenter': [0x2ff, 0x36c],
820 'vcenter': [0x2ff, 0x375],
821 'trunk': [0x36d, 0x375],
822 'limb': [0x376, 0x37e],
823 'location': [0x37f, 0x386],
824 'punctuation': [0x387, 0x38b]
825};
826/**
827 * Function to test if symbol is of a certain type.
828 * @function fsw.isType
829 * @param {string} key - an FSW symbol key
830 * @param {string} type - the name of a symbol range
831 * @returns {boolean} is symbol of specified type
832 * @example
833 * fsw.isType('S10000', 'hand')
834 *
835 * return true
836 */
837
838const isType = (key, type) => {
839 const parsed = parse$1.symbol(key);
840
841 if (parsed.symbol) {
842 const dec = parseInt(parsed.symbol.slice(1, 4), 16);
843 const range = ranges[type];
844
845 if (range) {
846 return range[0] <= dec && range[1] >= dec;
847 }
848 }
849
850 return false;
851};
852
853/**
854 * Array of colors associated with the seven symbol categories.
855 * @alias fsw.colors
856 * @type {array}
857 */
858
859const colors = ['#0000CC', '#CC0000', '#FF0099', '#006600', '#000000', '#884411', '#FF9900'];
860/**
861 * Function that returns the standardized color for a symbol.
862 * @function fsw.colorize
863 * @param {string} key - an FSW symbol key
864 * @returns {string} name of standardized color for symbol
865 * @example
866 * fsw.colorize('S10000')
867 *
868 * return '#0000CC'
869 */
870
871const colorize = key => {
872 const parsed = parse$1.symbol(key);
873 let color = '#000000';
874
875 if (parsed.symbol) {
876 const dec = parseInt(parsed.symbol.slice(1, 4), 16);
877 const index = category.findIndex(val => val > dec);
878 color = colors[index < 0 ? 6 : index - 1];
879 }
880
881 return color;
882};
883
884/** The fsw module contains functions for handling Formal SignWriitng in ASCII (FSW) characters.
885 * [FSW characters definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2.1)
886 * @module fsw
887 */
888
889var index$2 = /*#__PURE__*/Object.freeze({
890 __proto__: null,
891 re: re,
892 parse: parse$1,
893 compose: compose$1,
894 kind: kind,
895 category: category,
896 group: group,
897 ranges: ranges,
898 isType: isType,
899 colors: colors,
900 colorize: colorize
901});
902
903/**
904 * Object of regular expressions for FSW query strings
905 *
906 * { base, coord, var, symbol, range, prefix, signbox, full }
907 * @alias fswquery.re
908 * @type {object}
909 */
910let re$3 = {
911 'base': '[123][0-9a-f]{2}',
912 'coord': '(?:[0-9]{3}x[0-9]{3})?',
913 'var': 'V[0-9]+'
914};
915re$3.symbol = `S${re$3.base}[0-5u][0-9a-fu]`;
916re$3.range = `R${re$3.base}t${re$3.base}`;
917re$3.prefix = `(?:A(?:${re$3.symbol}|${re$3.range})+)?T`;
918re$3.signbox = `(?:${re$3.symbol}${re$3.coord}|${re$3.range}${re$3.coord})*`;
919re$3.full = `Q(${re$3.prefix})?(${re$3.signbox})?(${re$3.var})?(-?)`;
920
921const parsePrefix = text => {
922 return {
923 required: true,
924 parts: text == 'T' ? undefined : text.match(new RegExp(`(${re$3.symbol}|${re$3.range})`, 'g')).map(part => part[0] == 'S' ? part : part.slice(1).split('t'))
925 };
926};
927
928const parseSignbox = text => {
929 return text.match(new RegExp(`(${re$3.symbol}${re$3.coord}|${re$3.range}${re$3.coord})`, 'g')).map(part => {
930 let coord, front;
931
932 if (part.includes('x')) {
933 coord = fsw2coord(part.slice(-7));
934 front = part.slice(0, -7);
935 } else {
936 front = part;
937 }
938
939 if (front.includes('S')) {
940 return {
941 symbol: front,
942 coord: coord
943 };
944 } else {
945 return {
946 range: front.slice(1).split('t'),
947 coord: coord
948 };
949 }
950 });
951};
952/**
953 * Function to parse FSW query string to object
954 * @function fswquery.parse
955 * @param {string} fswQueryString - an FSW query string
956 * @returns {object} elements of an FSW query string
957 * @example
958 * fswquery.parse('QAS10000R100t204S20500TS20000R100t105500x500V5-')
959 *
960 * return {
961 * query: true,
962 * prefix: {
963 * required: true,
964 * parts: [
965 * 'S10000',
966 * ['100', '204'],
967 * 'S20500'
968 * ]
969 * },
970 * signbox: [
971 * { symbol: 'S20000' },
972 * {
973 * range: ['100', '105'],
974 * coord: [500, 500]
975 * }
976 * ],
977 * variance: 5,
978 * style: true
979 * }
980 */
981
982
983const parse$2 = fswQueryString => {
984 const query = typeof fswQueryString === 'string' ? fswQueryString.match(new RegExp(`^${re$3.full}`)) : undefined;
985 return {
986 'query': query ? true : undefined,
987 'prefix': query && query[1] ? parsePrefix(query[1]) : undefined,
988 'signbox': query && query[2] ? parseSignbox(query[2]) : undefined,
989 'variance': query && query[3] ? parseInt(query[3].slice(1)) : undefined,
990 'style': query && query[4] ? true : undefined
991 };
992};
993
994/**
995 * Function to compose FSW query string from object
996 * @function fswquery.compose
997 * @param {object} fswQueryObject - an object of style options
998 * @param {boolean} fswQueryObject.query - required true for FSW query object
999 * @param {object} fswQueryObject.prefix - an object for prefix elements
1000 * @param {boolean} fswQueryObject.prefix.required - true if sorting prefix is required
1001 * @param {(string|string[])[]} fswQueryObject.prefix.parts - array of symbol strings and range arrays
1002 * @param {({symbol:string,coord:number[]}|{range:string[],coord:number[]})[]} fswQueryObject.signbox - array of objects for symbols and ranges with optional coordinates
1003 * @param {number} fswQueryObject.variance - amount that x or y coordinates can vary and find a match, defaults to 20
1004 * @param {boolean} fswQueryObject.style - boolean value for including style string in matches
1005 * @returns {string} FSW query string
1006 * @example
1007 * fswquery.compose({
1008 * query: true,
1009 * prefix: {
1010 * required: true,
1011 * parts: [
1012 * 'S10000',
1013 * ['100', '204'],
1014 * 'S20500'
1015 * ]
1016 * },
1017 * signbox: [
1018 * { symbol: 'S20000' },
1019 * {
1020 * range: ['100', '105'],
1021 * coord: [500, 500]
1022 * }
1023 * ],
1024 * variance: 5,
1025 * style: true
1026 * })
1027 *
1028 * return 'QAS10000R100t204S20500TS20000R100t105500x500V5-'
1029 */
1030
1031const compose$2 = fswQueryObject => {
1032 if (!fswQueryObject || !fswQueryObject.query) {
1033 return undefined;
1034 }
1035
1036 let query = 'Q';
1037
1038 if (fswQueryObject.prefix && fswQueryObject.prefix.required) {
1039 if (Array.isArray(fswQueryObject.prefix.parts)) {
1040 query += 'A';
1041 query += fswQueryObject.prefix.parts.map(part => {
1042 if (typeof part === 'string') {
1043 return part;
1044 } else {
1045 if (Array.isArray(part) && part.length == 2) {
1046 return `R${part[0]}t${part[1]}`;
1047 }
1048 }
1049 }).join('');
1050 }
1051
1052 query += 'T';
1053 }
1054
1055 if (Array.isArray(fswQueryObject.signbox)) {
1056 query += fswQueryObject.signbox.map(part => {
1057 let out;
1058
1059 if (part.symbol) {
1060 out = part.symbol;
1061 } else {
1062 if (part.range && Array.isArray(part.range) && part.range.length == 2) {
1063 out = `R${part.range[0]}t${part.range[1]}`;
1064 }
1065 }
1066
1067 return out + (Array.isArray(part.coord) && part.coord.length == 2 ? part.coord.join('x') : '');
1068 }).join('');
1069 }
1070
1071 query += fswQueryObject.style ? '-' : '';
1072 query = query.match(new RegExp(`^${re$3.full}`))[0];
1073 return query;
1074};
1075
1076/**
1077 * Function to convert an FSW sign to a query string
1078 *
1079 * For the flags parameter, use one or more of the following.
1080 * - A: exact symbol in temporal prefix
1081 * - a: general symbol in temporal prefix
1082 * - S: exact symbol in spatial signbox
1083 * - s: general symbol in spatial signbox
1084 * - L: spatial signbox symbol at location
1085 * @function fswquery.fsw2query
1086 * @param {string} fswSign - FSW sign
1087 * @param {string} flags - flags for query string creation
1088 * @returns {string} FSW query string
1089 * @example
1090 * fswquery.fsw2query('AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475', 'ASL')
1091 *
1092 * return 'QAS10011S10019S2e704S2e748TS2e748483x510S10011501x466S2e704510x500S10019476x475'
1093 */
1094
1095const fsw2query = (fswSign, flags) => {
1096 let query = '';
1097 const parsed = parse$1.sign(fswSign);
1098
1099 if (parsed.box) {
1100 const A_flag = flags.indexOf('A') > -1;
1101 const a_flag = flags.indexOf('a') > -1;
1102 const S_flag = flags.indexOf('S') > -1;
1103 const s_flag = flags.indexOf('s') > -1;
1104 const L_flag = flags.indexOf('L') > -1;
1105
1106 if (A_flag || a_flag || S_flag || s_flag) {
1107 if ((A_flag || a_flag) && parsed.sequence) {
1108 query += 'A';
1109 query += parsed.sequence.map(sym => sym.slice(0, 4) + (a_flag ? 'uu' : sym.slice(4, 6))).join('');
1110 query += 'T';
1111 }
1112
1113 if ((S_flag || s_flag) && parsed.spatials) {
1114 query += parsed.spatials.map(spatial => spatial.symbol.slice(0, 4) + (s_flag ? 'uu' : spatial.symbol.slice(4, 6)) + (L_flag ? spatial.coord.join('x') : '')).join('');
1115 }
1116 }
1117
1118 return query ? "Q" + query : undefined;
1119 } else {
1120 return undefined;
1121 }
1122};
1123
1124//needs rewritten, but it works
1125
1126/**
1127 * Function to transform a range to a regular expression
1128 * @function fswquery.range
1129 * @param {(number|string)} min - either a decimal number or hexidecimal string
1130 * @param {(number|string)} max - either a decimal number or hexidecimal string
1131 * @param {boolean?} hex - if true, the regular expression will match a hexidecimal range
1132 * @returns {string} a regular expression that matches a range
1133 * @example
1134 * fswquery.range(500,749)
1135 *
1136 * return '(([56][0-9][0-9])|(7[0-4][0-9])|(750))'
1137 * @example
1138 * fswquery.range('100','10e',true)
1139 *
1140 * return '10[0-9a-e]'
1141 */
1142const range = (min, max, hex) => {
1143 let pattern;
1144 let re;
1145 let diff;
1146 let tmax;
1147 let cnt;
1148 let minV;
1149 let maxV;
1150
1151 if (!hex) {
1152 hex = '';
1153 }
1154
1155 min = ("000" + min).slice(-3);
1156 max = '' + max;
1157 pattern = '';
1158
1159 if (min === max) {
1160 return min;
1161 } //ending pattern will be series of connected OR ranges
1162
1163
1164 re = []; //first pattern+ 10's don't match and the min 1's are not zero
1165 //odd number to 9
1166
1167 if (!(min[0] == max[0] && min[1] == max[1])) {
1168 if (min[2] != '0') {
1169 pattern = min[0] + min[1];
1170
1171 if (hex) {
1172 //switch for dex
1173 switch (min[2]) {
1174 case "f":
1175 pattern += 'f';
1176 break;
1177
1178 case "e":
1179 pattern += '[ef]';
1180 break;
1181
1182 case "d":
1183 case "c":
1184 case "b":
1185 case "a":
1186 pattern += '[' + min[2] + '-f]';
1187 break;
1188
1189 default:
1190 switch (min[2]) {
1191 case "9":
1192 pattern += '[9a-f]';
1193 break;
1194
1195 case "8":
1196 pattern += '[89a-f]';
1197 break;
1198
1199 default:
1200 pattern += '[' + min[2] + '-9a-f]';
1201 break;
1202 }
1203
1204 break;
1205 }
1206
1207 diff = 15 - parseInt(min[2], 16) + 1;
1208 min = '' + (parseInt(min, 16) + diff).toString(16);
1209 re.push(pattern);
1210 } else {
1211 //switch for dex
1212 switch (min[2]) {
1213 case "9":
1214 pattern += '9';
1215 break;
1216
1217 case "8":
1218 pattern += '[89]';
1219 break;
1220
1221 default:
1222 pattern += '[' + min[2] + '-9]';
1223 break;
1224 }
1225
1226 diff = 9 - min[2] + 1;
1227 min = '' + (min * 1 + diff);
1228 re.push(pattern);
1229 }
1230 }
1231 }
1232
1233 pattern = ''; //if hundreds are different, get odd to 99 or ff
1234
1235 if (min[0] != max[0]) {
1236 if (min[1] != '0') {
1237 if (hex) {
1238 //scrape to ff
1239 pattern = min[0];
1240
1241 switch (min[1]) {
1242 case "f":
1243 pattern += 'f';
1244 break;
1245
1246 case "e":
1247 pattern += '[ef]';
1248 break;
1249
1250 case "d":
1251 case "c":
1252 case "b":
1253 case "a":
1254 pattern += '[' + min[1] + '-f]';
1255 break;
1256
1257 case "9":
1258 pattern += '[9a-f]';
1259 break;
1260
1261 case "8":
1262 pattern += '[89a-f]';
1263 break;
1264
1265 default:
1266 pattern += '[' + min[1] + '-9a-f]';
1267 break;
1268 }
1269
1270 pattern += '[0-9a-f]';
1271 diff = 15 - parseInt(min[1], 16) + 1;
1272 min = '' + (parseInt(min, 16) + diff * 16).toString(16);
1273 re.push(pattern);
1274 } else {
1275 //scrape to 99
1276 pattern = min[0];
1277 diff = 9 - min[1] + 1;
1278
1279 switch (min[1]) {
1280 case "9":
1281 pattern += '9';
1282 break;
1283
1284 case "8":
1285 pattern += '[89]';
1286 break;
1287
1288 default:
1289 pattern += '[' + min[1] + '-9]';
1290 break;
1291 }
1292
1293 pattern += '[0-9]';
1294 diff = 9 - min[1] + 1;
1295 min = '' + (min * 1 + diff * 10);
1296 re.push(pattern);
1297 }
1298 }
1299 }
1300
1301 pattern = ''; //if hundreds are different, get to same
1302
1303 if (min[0] != max[0]) {
1304 if (hex) {
1305 diff = parseInt(max[0], 16) - parseInt(min[0], 16);
1306 tmax = (parseInt(min[0], 16) + diff - 1).toString(16);
1307
1308 switch (diff) {
1309 case 1:
1310 pattern = min[0];
1311 break;
1312
1313 case 2:
1314 pattern = '[' + min[0] + tmax + ']';
1315 break;
1316
1317 default:
1318 if (parseInt(min[0], 16) > 9) {
1319 minV = 'h';
1320 } else {
1321 minV = 'd';
1322 }
1323
1324 if (parseInt(tmax, 16) > 9) {
1325 maxV = 'h';
1326 } else {
1327 maxV = 'd';
1328 }
1329
1330 switch (minV + maxV) {
1331 case "dd":
1332 pattern += '[' + min[0] + '-' + tmax + ']';
1333 break;
1334
1335 case "dh":
1336 diff = 9 - min[0]; //firs get up to 9
1337
1338 switch (diff) {
1339 case 0:
1340 pattern += '[9';
1341 break;
1342
1343 case 1:
1344 pattern += '[89';
1345 break;
1346
1347 default:
1348 pattern += '[' + min[0] + '-9';
1349 break;
1350 }
1351
1352 switch (tmax[0]) {
1353 case 'a':
1354 pattern += 'a]';
1355 break;
1356
1357 case 'b':
1358 pattern += 'ab]';
1359 break;
1360
1361 default:
1362 pattern += 'a-' + tmax + ']';
1363 break;
1364 }
1365
1366 break;
1367
1368 case "hh":
1369 pattern += '[' + min[0] + '-' + tmax + ']';
1370 break;
1371 }
1372
1373 }
1374
1375 pattern += '[0-9a-f][0-9a-f]';
1376 diff = parseInt(max[0], 16) - parseInt(min[0], 16);
1377 min = '' + (parseInt(min, 16) + diff * 256).toString(16);
1378 re.push(pattern);
1379 } else {
1380 diff = max[0] - min[0];
1381 tmax = min[0] * 1 + diff - 1;
1382
1383 switch (diff) {
1384 case 1:
1385 pattern = min[0];
1386 break;
1387
1388 case 2:
1389 pattern = '[' + min[0] + tmax + ']';
1390 break;
1391
1392 default:
1393 pattern = '[' + min[0] + '-' + tmax + ']';
1394 break;
1395 }
1396
1397 pattern += '[0-9][0-9]';
1398 min = '' + (min * 1 + diff * 100);
1399 re.push(pattern);
1400 }
1401 }
1402
1403 pattern = ''; //if tens are different, get to same
1404
1405 if (min[1] != max[1]) {
1406 if (hex) {
1407 diff = parseInt(max[1], 16) - parseInt(min[1], 16);
1408 tmax = (parseInt(min[1], 16) + diff - 1).toString(16);
1409 pattern = min[0];
1410
1411 switch (diff) {
1412 case 1:
1413 pattern += min[1];
1414 break;
1415
1416 case 2:
1417 pattern += '[' + min[1] + tmax + ']';
1418 break;
1419
1420 default:
1421 if (parseInt(min[1], 16) > 9) {
1422 minV = 'h';
1423 } else {
1424 minV = 'd';
1425 }
1426
1427 if (parseInt(tmax, 16) > 9) {
1428 maxV = 'h';
1429 } else {
1430 maxV = 'd';
1431 }
1432
1433 switch (minV + maxV) {
1434 case "dd":
1435 pattern += '[' + min[1];
1436
1437 if (diff > 1) {
1438 pattern += '-';
1439 }
1440
1441 pattern += tmax + ']';
1442 break;
1443
1444 case "dh":
1445 diff = 9 - min[1]; //firs get up to 9
1446
1447 switch (diff) {
1448 case 0:
1449 pattern += '[9';
1450 break;
1451
1452 case 1:
1453 pattern += '[89';
1454 break;
1455
1456 default:
1457 pattern += '[' + min[1] + '-9';
1458 break;
1459 }
1460
1461 switch (max[1]) {
1462 case 'a':
1463 pattern += ']';
1464 break;
1465
1466 case 'b':
1467 pattern += 'a]';
1468 break;
1469
1470 default:
1471 pattern += 'a-' + (parseInt(max[1], 16) - 1).toString(16) + ']';
1472 break;
1473 }
1474
1475 break;
1476
1477 case "hh":
1478 pattern += '[' + min[1];
1479
1480 if (diff > 1) {
1481 pattern += '-';
1482 }
1483
1484 pattern += (parseInt(max[1], 16) - 1).toString(16) + ']';
1485 break;
1486 }
1487
1488 break;
1489 }
1490
1491 pattern += '[0-9a-f]';
1492 diff = parseInt(max[1], 16) - parseInt(min[1], 16);
1493 min = '' + (parseInt(min, 16) + diff * 16).toString(16);
1494 re.push(pattern);
1495 } else {
1496 diff = max[1] - min[1];
1497 tmax = min[1] * 1 + diff - 1;
1498 pattern = min[0];
1499
1500 switch (diff) {
1501 case 1:
1502 pattern += min[1];
1503 break;
1504
1505 case 2:
1506 pattern += '[' + min[1] + tmax + ']';
1507 break;
1508
1509 default:
1510 pattern += '[' + min[1] + '-' + tmax + ']';
1511 break;
1512 }
1513
1514 pattern += '[0-9]';
1515 min = '' + (min * 1 + diff * 10);
1516 re.push(pattern);
1517 }
1518 }
1519
1520 pattern = ''; //if digits are different, get to same
1521
1522 if (min[2] != max[2]) {
1523 if (hex) {
1524 pattern = min[0] + min[1];
1525 diff = parseInt(max[2], 16) - parseInt(min[2], 16);
1526
1527 if (parseInt(min[2], 16) > 9) {
1528 minV = 'h';
1529 } else {
1530 minV = 'd';
1531 }
1532
1533 if (parseInt(max[2], 16) > 9) {
1534 maxV = 'h';
1535 } else {
1536 maxV = 'd';
1537 }
1538
1539 switch (minV + maxV) {
1540 case "dd":
1541 pattern += '[' + min[2];
1542
1543 if (diff > 1) {
1544 pattern += '-';
1545 }
1546
1547 pattern += max[2] + ']';
1548 break;
1549
1550 case "dh":
1551 diff = 9 - min[2]; //firs get up to 9
1552
1553 switch (diff) {
1554 case 0:
1555 pattern += '[9';
1556 break;
1557
1558 case 1:
1559 pattern += '[89';
1560 break;
1561
1562 default:
1563 pattern += '[' + min[2] + '-9';
1564 break;
1565 }
1566
1567 switch (max[2]) {
1568 case 'a':
1569 pattern += 'a]';
1570 break;
1571
1572 case 'b':
1573 pattern += 'ab]';
1574 break;
1575
1576 default:
1577 pattern += 'a-' + max[2] + ']';
1578 break;
1579 }
1580
1581 break;
1582
1583 case "hh":
1584 pattern += '[' + min[2];
1585
1586 if (diff > 1) {
1587 pattern += '-';
1588 }
1589
1590 pattern += max[2] + ']';
1591 break;
1592 }
1593
1594 diff = parseInt(max[2], 16) - parseInt(min[2], 16);
1595 min = '' + (parseInt(min, 16) + diff).toString(16);
1596 re.push(pattern);
1597 } else {
1598 diff = max[2] - min[2];
1599 pattern = min[0] + min[1];
1600
1601 switch (diff) {
1602 case 0:
1603 pattern += min[2];
1604 break;
1605
1606 case 1:
1607 pattern += '[' + min[2] + max[2] + ']';
1608 break;
1609
1610 default:
1611 pattern += '[' + min[2] + '-' + max[2] + ']';
1612 break;
1613 }
1614
1615 min = '' + (min * 1 + diff);
1616 re.push(pattern);
1617 }
1618 }
1619
1620 pattern = ''; //last place is whole hundred
1621
1622 if (min[2] == '0' && max[2] == '0') {
1623 pattern = max;
1624 re.push(pattern);
1625 }
1626
1627 pattern = '';
1628 cnt = re.length;
1629
1630 if (cnt == 1) {
1631 pattern = re[0];
1632 } else {
1633 pattern = re.join(')|(');
1634 pattern = '((' + pattern + '))';
1635 }
1636
1637 return pattern;
1638};
1639
1640/**
1641 * Function to transform an FSW query string to one or more regular expressions
1642 * @function fswquery.regex
1643 * @param {string} query - an FSW query string
1644 * @returns {string[]} an array of one or more regular expressions
1645 * @example
1646 * fswquery.regex('QS100uuS20500480x520')
1647 *
1648 * return [
1649 * '(A(S[123][0-9a-f]{2}[0-5][0-9a-f])+)?[BLMR]([0-9]{3}x[0-9]{3})(S[123][0-9a-f]{2}[0-5][0-9a-f][0-9]{3}x[0-9]{3})*S100[0-5][0-9a-f][0-9]{3}x[0-9]{3}(S[123][0-9a-f]{2}[0-5][0-9a-f][0-9]{3}x[0-9]{3})*',
1650 * '(A(S[123][0-9a-f]{2}[0-5][0-9a-f])+)?[BLMR]([0-9]{3}x[0-9]{3})(S[123][0-9a-f]{2}[0-5][0-9a-f][0-9]{3}x[0-9]{3})*S20500((4[6-9][0-9])|(500))x((5[0-3][0-9])|(540))(S[123][0-9a-f]{2}[0-5][0-9a-f][0-9]{3}x[0-9]{3})*'
1651 * ]
1652 */
1653
1654const regex = query => {
1655 query = query.match(new RegExp(`^${re$3.full}`))[0];
1656
1657 if (!query) {
1658 return '';
1659 }
1660
1661 var matches;
1662 var i;
1663 var fsw_pattern;
1664 var part;
1665 var from;
1666 var to;
1667 var re_range;
1668 var segment;
1669 var x;
1670 var y;
1671 var base;
1672 var fill;
1673 var rotate;
1674 var fuzz = 20;
1675 var re_sym = 'S[123][0-9a-f]{2}[0-5][0-9a-f]';
1676 var re_coord = '[0-9]{3}x[0-9]{3}';
1677 var re_word = '[BLMR](' + re_coord + ')(' + re_sym + re_coord + ')*';
1678 var re_sortable = '(A(' + re_sym + ')+)';
1679 var q_range = 'R[123][0-9a-f]{2}t[123][0-9a-f]{2}';
1680 var q_sym = 'S[123][0-9a-f]{2}[0-5u][0-9a-fu]';
1681 var q_coord = '([0-9]{3}x[0-9]{3})?';
1682 var q_var = '(V[0-9]+)';
1683 var q_style = '(' + re$1.full + ')?';
1684 var q_sortable;
1685
1686 if (query == 'Q') {
1687 return [re_sortable + "?" + re_word];
1688 }
1689
1690 if (query == 'Q-') {
1691 return [re_sortable + "?" + re_word + q_style];
1692 }
1693
1694 if (query == 'QT') {
1695 return [re_sortable + re_word];
1696 }
1697
1698 if (query == 'QT-') {
1699 return [re_sortable + re_word + q_style];
1700 }
1701
1702 var segments = [];
1703 var sortable = query.indexOf('T') + 1;
1704
1705 if (sortable) {
1706 q_sortable = '(A';
1707 var qat = query.slice(0, sortable);
1708 query = query.replace(qat, '');
1709
1710 if (qat == 'QT') {
1711 q_sortable += '(' + re_sym + ')+)';
1712 } else {
1713 matches = qat.match(new RegExp('(' + q_sym + '|' + q_range + ')', 'g'));
1714
1715 if (matches) {
1716 var matched;
1717
1718 for (i = 0; i < matches.length; i += 1) {
1719 matched = matches[i].match(new RegExp(q_sym));
1720
1721 if (matched) {
1722 segment = matched[0].slice(0, 4);
1723 fill = matched[0].slice(4, 5);
1724
1725 if (fill == 'u') {
1726 segment += '[0-5]';
1727 } else {
1728 segment += fill;
1729 }
1730
1731 rotate = matched[0].slice(5, 6);
1732
1733 if (rotate == 'u') {
1734 segment += '[0-9a-f]';
1735 } else {
1736 segment += rotate;
1737 }
1738
1739 q_sortable += segment;
1740 } else {
1741 from = matches[i].slice(1, 4);
1742 to = matches[i].slice(5, 8);
1743 re_range = range(from, to, 'hex');
1744 segment = 'S' + re_range + '[0-5][0-9a-f]';
1745 q_sortable += segment;
1746 }
1747 }
1748
1749 q_sortable += '(' + re_sym + ')*)';
1750 }
1751 }
1752 } //get the variance
1753
1754
1755 matches = query.match(new RegExp(q_var, 'g'));
1756
1757 if (matches) {
1758 fuzz = matches.toString().slice(1) * 1;
1759 } //this gets all symbols with or without location
1760
1761
1762 fsw_pattern = q_sym + q_coord;
1763 matches = query.match(new RegExp(fsw_pattern, 'g'));
1764
1765 if (matches) {
1766 for (i = 0; i < matches.length; i += 1) {
1767 part = matches[i].toString();
1768 base = part.slice(1, 4);
1769 segment = 'S' + base;
1770 fill = part.slice(4, 5);
1771
1772 if (fill == 'u') {
1773 segment += '[0-5]';
1774 } else {
1775 segment += fill;
1776 }
1777
1778 rotate = part.slice(5, 6);
1779
1780 if (rotate == 'u') {
1781 segment += '[0-9a-f]';
1782 } else {
1783 segment += rotate;
1784 }
1785
1786 if (part.length > 6) {
1787 x = part.slice(6, 9) * 1;
1788 y = part.slice(10, 13) * 1; //now get the x segment range+++
1789
1790 segment += range(x - fuzz, x + fuzz);
1791 segment += 'x';
1792 segment += range(y - fuzz, y + fuzz);
1793 } else {
1794 segment += re_coord;
1795 } //now I have the specific search symbol
1796 // add to general ksw word
1797
1798
1799 segment = re_word + segment + '(' + re_sym + re_coord + ')*';
1800
1801 if (sortable) {
1802 segment = q_sortable + segment;
1803 } else {
1804 segment = re_sortable + "?" + segment;
1805 }
1806
1807 if (query.indexOf('-') > 0) {
1808 segment += q_style;
1809 }
1810
1811 segments.push(segment);
1812 }
1813 } //this gets all ranges
1814
1815
1816 fsw_pattern = q_range + q_coord;
1817 matches = query.match(new RegExp(fsw_pattern, 'g'));
1818
1819 if (matches) {
1820 for (i = 0; i < matches.length; i += 1) {
1821 part = matches[i].toString();
1822 from = part.slice(1, 4);
1823 to = part.slice(5, 8);
1824 re_range = range(from, to, "hex");
1825 segment = 'S' + re_range + '[0-5][0-9a-f]';
1826
1827 if (part.length > 8) {
1828 x = part.slice(8, 11) * 1;
1829 y = part.slice(12, 15) * 1; //now get the x segment range+++
1830
1831 segment += range(x - fuzz, x + fuzz);
1832 segment += 'x';
1833 segment += range(y - fuzz, y + fuzz);
1834 } else {
1835 segment += re_coord;
1836 } // add to general ksw word
1837
1838
1839 segment = re_word + segment + '(' + re_sym + re_coord + ')*';
1840
1841 if (sortable) {
1842 segment = q_sortable + segment;
1843 } else {
1844 segment = re_sortable + "?" + segment;
1845 }
1846
1847 if (query.indexOf('-') > 0) {
1848 segment += q_style;
1849 }
1850
1851 segments.push(segment);
1852 }
1853 }
1854
1855 if (!segments.length) {
1856 if (query.indexOf('-') > 0) {
1857 segment += q_style;
1858 }
1859
1860 segments.push(q_sortable + re_word);
1861 }
1862
1863 return segments;
1864};
1865
1866/**
1867 * Function that uses a query string to match signs from a string of text.
1868 * @function fswquery.results
1869 * @param {string} query - an FSW query string
1870 * @param {string} text - a string of text containing multiple signs
1871 * @returns {string[]} an array of FSW signs
1872 * @example
1873 * fswquery.results('QAS10011T','AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475 AS15a21S15a07S21100S2df04S2df14M521x538S15a07494x488S15a21498x489S2df04498x517S2df14497x461S21100479x486 AS1f010S10018S20600M519x524S10018485x494S1f010490x494S20600481x476')
1874 *
1875 * return [
1876 * 'AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475'
1877 * ]
1878 */
1879
1880const results = (query, text) => {
1881 if (!text) {
1882 return [];
1883 }
1884
1885 let pattern;
1886 let matches;
1887 let parts;
1888 let words;
1889 let re = regex(query);
1890
1891 if (!re) {
1892 return [];
1893 }
1894
1895 let i;
1896
1897 for (i = 0; i < re.length; i += 1) {
1898 pattern = re[i];
1899 matches = text.match(new RegExp(pattern, 'g'));
1900
1901 if (matches) {
1902 text = matches.join(' ');
1903 } else {
1904 text = '';
1905 }
1906 }
1907
1908 if (text) {
1909 parts = text.split(' ');
1910 words = parts.filter(function (element) {
1911 return element in parts ? false : parts[element] = true;
1912 }, {});
1913 } else {
1914 words = [];
1915 }
1916
1917 return words;
1918}; //needs rewritten, but it works
1919
1920/**
1921 * Function that uses an FSW query string to match signs from multiple lines of text.
1922 * @function fswquery.lines
1923 * @param {string} query - an FSW query string
1924 * @param {string} text - multiple lines of text, each starting with an FSW sign
1925 * @returns {string[]} an array of lines of text, each starting with an FSW sign
1926 * @example
1927 * fswquery.lines('QAS10011T',`AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475 line one
1928 * AS15a21S15a07S21100S2df04S2df14M521x538S15a07494x488S15a21498x489S2df04498x517S2df14497x461S21100479x486 line two
1929 * AS1f010S10018S20600M519x524S10018485x494S1f010490x494S20600481x476 line three`)
1930 *
1931 * return [
1932 * 'AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475 line one'
1933 * ]
1934 */
1935
1936
1937const lines = (query, text) => {
1938 if (!text) {
1939 return [];
1940 }
1941
1942 let pattern;
1943 let matches;
1944 let parts;
1945 let words;
1946 let re = regex(query);
1947
1948 if (!re) {
1949 return [];
1950 }
1951
1952 let i;
1953
1954 for (i = 0; i < re.length; i += 1) {
1955 pattern = re[i];
1956 pattern = '^' + pattern + '.*';
1957 matches = text.match(new RegExp(pattern, 'mg'));
1958
1959 if (matches) {
1960 text = matches.join("\n");
1961 } else {
1962 text = '';
1963 }
1964 }
1965
1966 if (text) {
1967 parts = text.split("\n");
1968 words = parts.filter(function (element) {
1969 return element in parts ? false : parts[element] = true;
1970 }, {});
1971 } else {
1972 words = [];
1973 }
1974
1975 return words;
1976};
1977
1978/** The fswquery module contains functions for handling the FSW query language.
1979 * [Query Language definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.6)
1980 * @module fswquery
1981 */
1982
1983var index$3 = /*#__PURE__*/Object.freeze({
1984 __proto__: null,
1985 re: re$3,
1986 parse: parse$2,
1987 compose: compose$2,
1988 fsw2query: fsw2query,
1989 range: range,
1990 regex: regex,
1991 results: results,
1992 lines: lines
1993});
1994
1995const parse$3 = {
1996 /**
1997 * Function to parse an swu symbol with optional coordinate and style string
1998 * @function swu.parse.symbol
1999 * @param {string} swuSym - an swu symbol
2000 * @returns {object} elements of swu symbol
2001 * @example
2002 * swu.parse.symbol('񀀁𝤆𝤆-C')
2003 *
2004 * return {
2005 * 'symbol': '񀀁',
2006 * 'coord': [500, 500],
2007 * 'style': '-C'
2008 * }
2009 */
2010 symbol: swuSym => {
2011 const regex = `^(${re$2.symbol})(${re$2.coord})?(${re$1.full})?`;
2012 const symbol = typeof swuSym === 'string' ? swuSym.match(new RegExp(regex)) : undefined;
2013 return {
2014 'symbol': symbol ? symbol[1] : undefined,
2015 'coord': symbol && symbol[2] ? swu2coord(symbol[2]) : undefined,
2016 'style': symbol ? symbol[3] : undefined
2017 };
2018 },
2019
2020 /**
2021 * Function to parse an swu sign with style string
2022 * @function swu.parse.sign
2023 * @param {string} swuSign - an swu sign
2024 * @returns {object} elements of swu sign
2025 * @example
2026 * swu.parse.sign('𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭-C')
2027 *
2028 * return {
2029 * sequence: ['񀀒','񀀚','񋚥','񋛩''],
2030 * box: '𝠃',
2031 * max: [525, 535],
2032 * spatials: [
2033 * {
2034 * symbol: '񋛩',
2035 * coord: [483, 510]
2036 * },
2037 * {
2038 * symbol: '񀀒',
2039 * coord: [501, 466]
2040 * },
2041 * {
2042 * symbol: '񋚥',
2043 * coord: [510, 500]
2044 * },
2045 * {
2046 * symbol: '񀀚',
2047 * coord: [476, 475]
2048 * }
2049 * ],
2050 * style: '-C'
2051 * }
2052 */
2053 sign: swuSign => {
2054 const regex = `^(${re$2.prefix})?(${re$2.signbox})(${re$1.full})?`;
2055 const sign = typeof swuSign === 'string' ? swuSign.match(new RegExp(regex)) : undefined;
2056
2057 if (sign) {
2058 return {
2059 'sequence': sign[1] ? sign[1].slice(2).match(/.{2}/g) : undefined,
2060 'box': sign[2].slice(0, 2),
2061 'max': swu2coord(sign[2].slice(2, 6)),
2062 'spatials': sign[2].length < 7 ? undefined : sign[2].slice(6).match(/(.{6})/g).map(m => {
2063 return {
2064 symbol: m.slice(0, 2),
2065 coord: swu2coord(m.slice(2))
2066 };
2067 }),
2068 'style': sign[3]
2069 };
2070 } else {
2071 return {};
2072 }
2073 }
2074};
2075/**
2076 * Function to encode SWU characters using the UTF-16 escape format.
2077 * @function swu.encode
2078 * @param {string} swu - SWU characters
2079 * @returns {string} UTF-16 escape format
2080 * @example
2081 * swu.encode('񀀁𝤆𝤆')
2082 *
2083 * return '\\uD8C0\\uDC01\\uD836\\uDD06\\uD836\\uDD06'
2084 */
2085
2086const encode = text => text.replace(/[\u007F-\uFFFF]/g, function (chr) {
2087 return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4).toUpperCase();
2088});
2089/**
2090 * Function to decode UTF-16 escape format to SWU characters.
2091 * @function swu.decode
2092 * @param {string} encoded - UTF-16 escape format
2093 * @returns {string} SWU characters
2094 * @example
2095 * swu.decode('\\uD8C0\\uDC01\\uD836\\uDD06\\uD836\\uDD06')
2096 *
2097 * return '񀀁𝤆𝤆'
2098 */
2099
2100
2101const decode = encoded => encoded.replace(/\\u([0-9A-F]{4})/g, function (match, chr) {
2102 return String.fromCharCode(parseInt(chr, 16));
2103});
2104/**
2105 * Function to decompose an SWU character into UTF-16 surrogate pairs.
2106 * @function swu.pair
2107 * @param {string} swuChar - an SWU character
2108 * @returns {string[]} an array of UTF-16 surrogate pairs
2109 * @example
2110 * swu.pair('񀀁')
2111 *
2112 * return ['D8C0', 'DC01']
2113 */
2114
2115
2116const pair = swuChar => [swuChar.charCodeAt(0).toString(16).toUpperCase(), swuChar.charCodeAt(1).toString(16).toUpperCase()];
2117
2118const compose$3 = {
2119 /**
2120 * Function to compose an swu symbol with optional coordinate and style string
2121 * @function swu.compose.symbol
2122 * @param {object} swuSymObject - an swu symbol object
2123 * @param {string} swuSymObject.symbol - an swu symbol key
2124 * @param {number[]} swuSymObject.coord - top-left coordinate of symbol with 500,500 center
2125 * @param {string} swuSymObject.style - a style string for custom appearance
2126 * @returns {string} an swu symbol string
2127 * @example
2128 * swu.compose.symbol({
2129 * 'symbol': '񀀁',
2130 * 'coord': [500, 500],
2131 * 'style': '-C'
2132 * })
2133 *
2134 * return '񀀁𝤆𝤆-C'
2135 */
2136 symbol: swuSymObject => {
2137 if (typeof swuSymObject !== 'object' || swuSymObject === null) return undefined;
2138
2139 if (typeof swuSymObject.symbol === 'string') {
2140 const symbol = (swuSymObject.symbol.match(re$2.symbol) || [''])[0];
2141
2142 if (symbol) {
2143 const x = swuSymObject.coord && swuSymObject.coord[0] || '';
2144 const y = swuSymObject.coord && swuSymObject.coord[1] || '';
2145 const coord = x && y ? coord2swu([x, y]) : '';
2146 const styleStr = typeof swuSymObject.style === 'string' && (swuSymObject.style.match(re$1.full) || [''])[0] || '';
2147 return symbol + coord + styleStr;
2148 }
2149 }
2150
2151 return undefined;
2152 },
2153
2154 /**
2155 * Function to compose an swu sign with style string
2156 * @function swu.compose.sign
2157 * @param {string[]} swuSignObject.sequence - an ordered array of symbols
2158 * @param {string} swuSignObject.box - a choice BLMR: horizontal Box, Left, Middle, and Right lane
2159 * @param {number[]} swuSymObject.max - max bottom left coordinate of the signbox space
2160 * @param {{symbol:string,coord:number[]}[]} swuSymObject.spatials - array of symbols with top-left coordinate placement
2161 * @param {string} swuSymObject.style - a style string for custom appearance
2162 * @returns {string} an swu sign string
2163 * @example
2164 * swu.compose.sign({
2165 * sequence: ['񀀒','񀀚','񋚥','񋛩''],
2166 * box: '𝠃',
2167 * max: [525, 535],
2168 * spatials: [
2169 * {
2170 * symbol: '񋛩',
2171 * coord: [483, 510]
2172 * },
2173 * {
2174 * symbol: '񀀒',
2175 * coord: [501, 466]
2176 * },
2177 * {
2178 * symbol: '񋚥',
2179 * coord: [510, 500]
2180 * },
2181 * {
2182 * symbol: '񀀚',
2183 * coord: [476, 475]
2184 * }
2185 * ],
2186 * style: '-C'
2187 * })
2188 *
2189 * return '𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭-C'
2190 */
2191 sign: swuSignObject => {
2192 if (typeof swuSignObject !== 'object' || swuSignObject === null) return undefined;
2193 let box = typeof swuSignObject.box !== 'string' ? '𝠃' : (swuSignObject.box + '𝠃').match(re$2.box);
2194 const x = swuSignObject.max && swuSignObject.max[0] || '';
2195 const y = swuSignObject.max && swuSignObject.max[1] || '';
2196 const max = x && y ? coord2swu([x, y]) : undefined;
2197 if (!max) return undefined;
2198 let prefix = '';
2199
2200 if (swuSignObject.sequence && Array.isArray(swuSignObject.sequence)) {
2201 prefix = swuSignObject.sequence.map(key => (key.match(re$2.symbol) || [''])[0]).join('');
2202 prefix = prefix ? '𝠀' + prefix : '';
2203 }
2204
2205 let signbox = '';
2206
2207 if (swuSignObject.spatials && Array.isArray(swuSignObject.spatials)) {
2208 signbox = swuSignObject.spatials.map(spatial => {
2209 if (typeof spatial.symbol === 'string') {
2210 const symbol = (spatial.symbol.match(re$2.symbol) || [''])[0];
2211
2212 if (symbol) {
2213 const x = spatial.coord && spatial.coord[0] || '';
2214 const y = spatial.coord && spatial.coord[1] || '';
2215 const coord = x && y ? coord2swu([x, y]) : '';
2216
2217 if (coord) {
2218 return symbol + coord;
2219 }
2220 }
2221 }
2222
2223 return '';
2224 }).join('');
2225 }
2226
2227 const styleStr = typeof swuSignObject.style === 'string' && (swuSignObject.style.match(re$1.full) || [''])[0] || '';
2228 return prefix + box + max + signbox + styleStr;
2229 }
2230};
2231
2232/**
2233 * Array of plane 4 code points for kinds of symbols: writing, location, and punctuation.
2234 * @alias swu.kind
2235 * @type {array}
2236 */
2237
2238const kind$1 = [0x40001, 0x4efa1, 0x4f2a1];
2239/**
2240 * Array of plane 4 code points for categories of symbols: hand, movement, dynamics, head, trunk & limb, location, and punctuation.
2241 * @alias swu.category
2242 * @type {array}
2243 */
2244
2245const category$1 = [0x40001, 0x461e1, 0x4bca1, 0x4bfa1, 0x4e8e1, 0x4efa1, 0x4f2a1];
2246/**
2247 * Array of plane 4 code points for the 30 symbol groups.
2248 * @alias swu.group
2249 * @type {array}
2250 */
2251
2252const group$1 = [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];
2253/**
2254 * Object of symbol ranges with starting and ending code points on plane 4.
2255 *
2256 * { all, writing, hand, movement, dynamic, head, hcenter, vcenter, trunk, limb, location, punctuation }
2257 * @alias swu.ranges
2258 * @type {object}
2259 */
2260
2261const ranges$1 = {
2262 'all': [0x40001, 0x4f480],
2263 'writing': [0x40001, 0x4efa0],
2264 'hand': [0x40001, 0x461e0],
2265 'movement': [0x461e1, 0x4bca0],
2266 'dynamic': [0x4bca1, 0x4bfa0],
2267 'head': [0x4bfa1, 0x4e8e0],
2268 'hcenter': [0x4bfa1, 0x4e8e0],
2269 'vcenter': [0x4bfa1, 0x4ec40],
2270 'trunk': [0x4e8e1, 0x4ec40],
2271 'limb': [0x4ec41, 0x4efa0],
2272 'location': [0x4efa1, 0x4f2a0],
2273 'punctuation': [0x4f2a1, 0x4f480]
2274};
2275/**
2276 * Function to test if symbol is of a certain type.
2277 * @function swu.isType
2278 * @param {string} swuSym - an SWU symbol character
2279 * @param {string} type - the name of a symbol range
2280 * @returns {boolean} is symbol of specified type
2281 * @example
2282 * swu.isType('񀀁', 'hand')
2283 *
2284 * return true
2285 */
2286
2287const isType$1 = (swuSym, type) => {
2288 const parsed = parse$3.symbol(swuSym);
2289
2290 if (parsed.symbol) {
2291 const code = swu2code(parsed.symbol);
2292 const range = ranges$1[type];
2293
2294 if (range) {
2295 return range[0] <= code && range[1] >= code;
2296 }
2297 }
2298
2299 return false;
2300};
2301
2302/**
2303 * Array of colors associated with the seven symbol categories.
2304 * @alias swu.colors
2305 * @type {array}
2306 */
2307
2308const colors$1 = ['#0000CC', '#CC0000', '#FF0099', '#006600', '#000000', '#884411', '#FF9900'];
2309/**
2310 * Function that returns the standardized color for a symbol.
2311 * @function swu.colorize
2312 * @param {string} swuSym - an SWU symbol character
2313 * @returns {string} name of standardized color for symbol
2314 * @example
2315 * swu.colorize('񀀁')
2316 *
2317 * return '#0000CC'
2318 */
2319
2320const colorize$1 = swuSym => {
2321 const parsed = parse$3.symbol(swuSym);
2322 let color = '#000000';
2323
2324 if (parsed.symbol) {
2325 const code = swu2code(parsed.symbol);
2326 const index = category$1.findIndex(val => val > code);
2327 color = colors$1[index < 0 ? 6 : index - 1];
2328 }
2329
2330 return color;
2331};
2332
2333/** The swu module contains functions for handling SignWriitng in Unicode (SWu) characters.
2334 * [SWU characters definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2.2)
2335 * @module swu
2336 */
2337
2338var index$4 = /*#__PURE__*/Object.freeze({
2339 __proto__: null,
2340 re: re$2,
2341 parse: parse$3,
2342 encode: encode,
2343 decode: decode,
2344 pair: pair,
2345 compose: compose$3,
2346 kind: kind$1,
2347 category: category$1,
2348 group: group$1,
2349 ranges: ranges$1,
2350 isType: isType$1,
2351 colors: colors$1,
2352 colorize: colorize$1
2353});
2354
2355/**
2356 * Object of regular expressions for SWU query strings
2357 *
2358 * { base, coord, var, symbol, range, prefix, signbox, full }
2359 * @alias swuquery.re
2360 * @type {object}
2361 */
2362let re$4 = {
2363 'base': '(?:(?:\uD8C0[\uDC01-\uDFFF])|(?:[\uD8C1-\uD8FC][\uDC00-\uDFFF])|(?:\uD8FD[\uDC00-\uDC80]))',
2364 'coord': '(?:(?:\uD836[\uDC0C-\uDDFF]){2})?',
2365 'var': 'V[0-9]+'
2366};
2367re$4.symbol = `${re$4.base}f?r?`;
2368re$4.range = `R${re$4.base}${re$4.base}`;
2369re$4.prefix = `(?:A(?:${re$4.symbol}|${re$4.range})+)?T`;
2370re$4.signbox = `(?:${re$4.symbol}${re$4.coord}|${re$4.range}${re$4.coord})*`;
2371re$4.full = `Q(${re$4.prefix})?(${re$4.signbox})?(${re$4.var})?(-?)`;
2372
2373const parsePrefix$1 = text => {
2374 return {
2375 required: true,
2376 parts: text == 'T' ? undefined : text.match(new RegExp(`(${re$4.symbol}|${re$4.range})`, 'g')).map(part => part[0] != 'R' ? part : [part.slice(1, 3), part.slice(3, 5)])
2377 };
2378};
2379
2380const parseSignbox$1 = text => {
2381 return text.match(new RegExp(`(${re$4.symbol}${re$4.coord}|${re$4.range}${re$4.coord})`, 'g')).map(part => {
2382 let coord, front;
2383
2384 if (part.length > 5) {
2385 coord = swu2coord(part.slice(-4));
2386 front = part.slice(0, -4);
2387 } else {
2388 front = part;
2389 }
2390
2391 if (!front.includes('R')) {
2392 return {
2393 symbol: front,
2394 coord: coord
2395 };
2396 } else {
2397 return {
2398 range: [front.slice(1, 3), front.slice(3, 5)],
2399 coord: coord
2400 };
2401 }
2402 });
2403};
2404/**
2405 * Function to parse SWU query string to object
2406 * @function swuquery.parse
2407 * @param {string} swuQueryString - an SWU query string
2408 * @returns {object} elements of an SWU query string
2409 * @example
2410 * swuquery.parse('QA񀀁R񀀁񆆑񆇡T񆀁R񀀁񀇱𝤆𝤆V5-')
2411 *
2412 * return {
2413 * query: true,
2414 * prefix: {
2415 * required: true,
2416 * parts: [
2417 * '񀀁',
2418 * ['񀀁', '񆆑'],
2419 * '񆇡'
2420 * ]
2421 * },
2422 * signbox: [
2423 * { symbol: '񆀁' },
2424 * {
2425 * range: ['񀀁', '񀇱'],
2426 * coord: [500, 500]
2427 * }
2428 * ],
2429 * variance: 5,
2430 * style: true
2431 * }
2432 */
2433
2434
2435const parse$4 = swuQueryString => {
2436 const query = typeof swuQueryString === 'string' ? swuQueryString.match(new RegExp(`^${re$4.full}`)) : undefined;
2437 return {
2438 'query': query ? true : undefined,
2439 'prefix': query && query[1] ? parsePrefix$1(query[1]) : undefined,
2440 'signbox': query && query[2] ? parseSignbox$1(query[2]) : undefined,
2441 'variance': query && query[3] ? parseInt(query[3].slice(1)) : undefined,
2442 'style': query && query[4] ? true : undefined
2443 };
2444};
2445
2446/**
2447 * Function to compose SWU query string from object
2448 * @function swuquery.compose
2449 * @param {object} swuQueryObject - an object of style options
2450 * @param {boolean} swuQueryObject.query - required true for SWU query object
2451 * @param {object} swuQueryObject.prefix - an object for prefix elements
2452 * @param {boolean} swuQueryObject.prefix.required - true if sorting prefix is required
2453 * @param {(string|string[])[]} swuQueryObject.prefix.parts - array of symbol strings and range arrays
2454 * @param {({symbol:string,coord:number[]}|{range:string[],coord:number[]})[]} swuQueryObject.signbox - array of objects for symbols and ranges with optional coordinates
2455 * @param {number} swuQueryObject.variance - amount that x or y coordinates can vary and find a match, defaults to 20
2456 * @param {boolean} swuQueryObject.style - boolean value for including style string in matches
2457 * @returns {string} SWU query string
2458 * @example
2459 * swuquery.compose({
2460 * query: true,
2461 * prefix: {
2462 * required: true,
2463 * parts: [
2464 * '񀀁',
2465 * ['񀀁', '񆆑'],
2466 * '񆇡'
2467 * ]
2468 * },
2469 * signbox: [
2470 * { symbol: '񆀁' },
2471 * {
2472 * range: ['񀀁', '񀇱'],
2473 * coord: [500, 500]
2474 * }
2475 * ],
2476 * variance: 5,
2477 * style: true
2478 * })
2479 *
2480 * return 'QA񀀁R񀀁񆆑񆇡T񆀁R񀀁񀇱𝤆𝤆V5-'
2481 */
2482
2483const compose$4 = swuQueryObject => {
2484 if (!swuQueryObject || !swuQueryObject.query) {
2485 return undefined;
2486 }
2487
2488 let query = 'Q';
2489
2490 if (swuQueryObject.prefix && swuQueryObject.prefix.required) {
2491 if (Array.isArray(swuQueryObject.prefix.parts)) {
2492 query += 'A';
2493 query += swuQueryObject.prefix.parts.map(part => {
2494 if (typeof part === 'string') {
2495 return part;
2496 } else {
2497 if (Array.isArray(part) && part.length == 2) {
2498 return `R${part[0]}${part[1]}`;
2499 }
2500 }
2501 }).join('');
2502 }
2503
2504 query += 'T';
2505 }
2506
2507 if (Array.isArray(swuQueryObject.signbox)) {
2508 query += swuQueryObject.signbox.map(part => {
2509 let out;
2510
2511 if (part.symbol) {
2512 out = part.symbol;
2513 } else {
2514 if (part.range && Array.isArray(part.range) && part.range.length == 2) {
2515 out = `R${part.range[0]}${part.range[1]}`;
2516 }
2517 }
2518
2519 return out + (Array.isArray(part.coord) && part.coord.length == 2 ? coord2swu(part.coord) : '');
2520 }).join('');
2521 }
2522
2523 query += swuQueryObject.style ? '-' : '';
2524 query = query.match(new RegExp(`^${re$4.full}`))[0];
2525 return query;
2526};
2527
2528/**
2529 * Function to convert an SWU sign to a query string
2530 *
2531 * For the flags parameter, use one or more of the following.
2532 * - A: exact symbol in temporal prefix
2533 * - a: general symbol in temporal prefix
2534 * - S: exact symbol in spatial signbox
2535 * - s: general symbol in spatial signbox
2536 * - L: spatial signbox symbol at location
2537 * @function swuquery.swu2query
2538 * @param {string} swuSign - SWU sign
2539 * @param {string} flags - flags for query string creation
2540 * @returns {string} SWU query string
2541 * @example
2542 * swuquery.swu2query('𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭', 'ASL')
2543 *
2544 * return 'QA񀀒񀀚񋚥񋛩T񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭'
2545 */
2546
2547const swu2query = (swuSign, flags) => {
2548 let query = '';
2549 const parsed = parse$3.sign(swuSign);
2550
2551 if (parsed.box) {
2552 const A_flag = flags.indexOf('A') > -1;
2553 const a_flag = flags.indexOf('a') > -1;
2554 const S_flag = flags.indexOf('S') > -1;
2555 const s_flag = flags.indexOf('s') > -1;
2556 const L_flag = flags.indexOf('L') > -1;
2557
2558 if (A_flag || a_flag || S_flag || s_flag) {
2559 if ((A_flag || a_flag) && parsed.sequence) {
2560 query += 'A';
2561 query += parsed.sequence.map(sym => sym + (a_flag ? 'fr' : '')).join('');
2562 query += 'T';
2563 }
2564
2565 if ((S_flag || s_flag) && parsed.spatials) {
2566 query += parsed.spatials.map(spatial => spatial.symbol + (s_flag ? 'fr' : '') + (L_flag ? coord2swu(spatial.coord) : '')).join('');
2567 }
2568 }
2569
2570 return query ? "Q" + query : undefined;
2571 } else {
2572 return undefined;
2573 }
2574};
2575
2576/**
2577 * Function to transform a range of SWU characters to a regular expression
2578 * @function swuquery.range
2579 * @param {string} min - an SWU character
2580 * @param {string} max - an SWU character
2581 * @returns {string} a regular expression that matches a range of SWU characters
2582 * @example
2583 * swuquery.range('񀀁', '񀇡')
2584 *
2585 * return '\uD8C0[\uDC01-\uDDE1]'
2586 * @example
2587 * swuquery.range('𝣔', '𝤸')
2588 *
2589 * return '\uD836[\uDCD4-\uDD38]'
2590 */
2591
2592const range$1 = (min, max) => {
2593 if (min > max) return '';
2594 let pattern = '';
2595 let cnt;
2596 let re = [];
2597 min = pair(min);
2598 max = pair(max);
2599 if (min.length != 2 && max.length != 2) return ''; // HEAD // min[0] with range of min[1] to (DFFF or max[1])
2600
2601 if (min[0] == max[0]) {
2602 if (min[1] == max[1]) {
2603 pattern = '\\u' + min[0] + '\\u' + min[1];
2604 re.push(pattern);
2605 } else {
2606 pattern = '\\u' + min[0] + '[\\u' + min[1] + '-\\u' + max[1] + ']';
2607 re.push(pattern);
2608 }
2609 } else {
2610 if (min[1] == "DFFF") {
2611 pattern = '\\u' + min[0] + '\\uDFFF';
2612 } else {
2613 pattern = '\\u' + min[0] + '[\\u' + min[1] + '-\\uDFFF]';
2614 }
2615
2616 re.push(pattern); // BODY // range of (min[0] +1) to (max[0] -1) with all DC00-DFFF
2617
2618 let diff = parseInt(max[0], 16) - parseInt(min[0], 16);
2619
2620 if (diff == 2) {
2621 pattern = '\\u' + (parseInt(min[0], 16) + 1).toString(16).toUpperCase();
2622 pattern += '[\\uDC00-\\uDFFF]';
2623 re.push(pattern);
2624 }
2625
2626 if (diff > 2) {
2627 pattern = '[';
2628 pattern += '\\u' + (parseInt(min[0], 16) + 1).toString(16).toUpperCase();
2629 pattern += '-\\u' + (parseInt(max[0], 16) - 1).toString(16).toUpperCase();
2630 pattern += '][\\uDC00-\\uDFFF]';
2631 re.push(pattern);
2632 } // TAIL // max[0] with range of DC00 to max[1]
2633
2634
2635 if (max[1] == "DC00") {
2636 pattern = '\\u' + max[0] + '\\uDC00';
2637 } else {
2638 pattern = '\\u' + max[0] + '[\\uDC00-\\u' + max[1] + ']';
2639 }
2640
2641 re.push(pattern);
2642 }
2643
2644 cnt = re.length;
2645
2646 if (cnt == 1) {
2647 pattern = re[0];
2648 } else {
2649 pattern = re.join(')|(');
2650 pattern = '((' + pattern + '))';
2651 }
2652
2653 return decode(pattern);
2654};
2655
2656/**
2657 * Function to transform an SWU symbol with fill and rotation flags to a regular expression
2658 * @function swuquery.symbolRanges
2659 * @param {string} symbolFR - an SWU character with optional flags of 'f' for any fill and 'r' for any rotation
2660 * @returns {string} a regular expression that matches one or more ranges of SWU symbols
2661 * @example <caption>Match an exact symbol</caption>
2662 * swuquery.symbolRanges('񀀁')
2663 *
2664 * return '\uD8C0\uDC01');
2665 * @example <caption>Match a symbol with any fill</caption>
2666 * swuquery.symbolRanges('񀀁f')
2667 *
2668 * return '(\uD8C0\uDC01|\uD8C0\uDC11|\uD8C0\uDC21|\uD8C0\uDC31|\uD8C0\uDC41|\uD8C0\uDC51)'
2669 * @example <caption>Match a symbol with any rotation</caption>
2670 * swuquery.symbolRanges('񀀁r')
2671 *
2672 * return '\uD8C0[\uDC01-\uDC10]'
2673 * @example <caption>Match a symbol with any fill or rotation</caption>
2674 * swuquery.symbolRanges('񀀁fr')
2675 *
2676 * return '\uD8C0[\uDC01-\uDC60]'
2677 */
2678
2679const symbolRanges = symbolFR => {
2680 let match = symbolFR.match(new RegExp(re$4.symbol));
2681
2682 if (match) {
2683 let sym = match[0].slice(0, 2);
2684 let key = swu2key(sym);
2685 let base = key.slice(0, 4);
2686 let start, end;
2687
2688 if (match[0].slice(-2) == 'fr') {
2689 start = key2swu(base + "00");
2690 end = key2swu(base + "5f");
2691 return range$1(start, end);
2692 } else if (match[0].slice(-1) == 'r') {
2693 start = key2swu(key.slice(0, 5) + '0');
2694 end = key2swu(key.slice(0, 5) + 'f');
2695 return range$1(start, end);
2696 } else if (match[0].slice(-1) == 'f') {
2697 let list = [0, 1, 2, 3, 4, 5].map(function (f) {
2698 return key2swu(base + f + key.slice(-1));
2699 });
2700 return "(" + list.join("|") + ")";
2701 } else {
2702 return sym;
2703 }
2704 } else {
2705 return '';
2706 }
2707};
2708
2709/**
2710 * Function to transform an SWU query string to one or more regular expressions
2711 * @function swuquery.regex
2712 * @param {string} query - an SWU query string
2713 * @returns {string[]} an array of one or more regular expressions
2714 * @example
2715 * swuquery.regex('QA񀀒T')
2716 *
2717 * return [
2718 * '(\uD836\uDC00\uD8C0\uDC12((?:(?:\uD8C0[\uDC01-\uDFFF])|(?:[\uD8C1-\uD8FC][\uDC00-\uDFFF])|(?:\uD8FD[\uDC00-\uDC80])))*)\uD836[\uDC01-\uDC04](?:\uD836[\uDC0C-\uDDFF]){2}((?:(?:\uD8C0[\uDC01-\uDFFF])|(?:[\uD8C1-\uD8FC][\uDC00-\uDFFF])|(?:\uD8FD[\uDC00-\uDC80]))(?:\uD836[\uDC0C-\uDDFF]){2})*'
2719 * ]
2720 */
2721
2722const regex$1 = query => {
2723 query = query.match(new RegExp(`^${re$4.full}`))[0];
2724
2725 if (!query) {
2726 return '';
2727 }
2728
2729 let matches;
2730 let i;
2731 let part;
2732 let from;
2733 let to;
2734 let coord;
2735 let segment;
2736 let x;
2737 let y;
2738 let fuzz = 20;
2739 let re_sym = re$2.symbol;
2740 let re_coord = re$2.coord;
2741 let re_signbox = re$2.box;
2742 let re_seq = re$2.sort;
2743 let re_word = re_signbox + re_coord + '(' + re_sym + re_coord + ')*';
2744 let re_sortable = '(' + re_seq + '(' + re_sym + ')+)';
2745 let q_range = 'R' + re_sym + re_sym;
2746 let q_sym = re_sym + 'f?r?';
2747 let q_coord = '(' + re_coord + ')?';
2748 let q_var = '(V[0-9]+)';
2749 let q_style = '(' + re$1.full + ')?';
2750 let q_sortable;
2751
2752 if (query == 'Q') {
2753 return [re$2.sign];
2754 }
2755
2756 if (query == 'Q-') {
2757 return [re$2.sign + "(" + re$1.full + ")?"];
2758 }
2759
2760 if (query == 'QT') {
2761 return [re$2.sortable];
2762 }
2763
2764 if (query == 'QT-') {
2765 return [re$2.sortable + "(" + re$1.full + ")?"];
2766 }
2767
2768 let segments = [];
2769 let sym;
2770 let sortable = query.indexOf('T') + 1;
2771
2772 if (sortable) {
2773 q_sortable = '(' + re$2.sort;
2774 let qat = query.slice(0, sortable);
2775 query = query.replace(qat, '');
2776
2777 if (qat == 'QT') {
2778 q_sortable += '(' + re_sym + ')+)';
2779 } else {
2780 matches = qat.match(new RegExp('(' + q_sym + '|' + q_range + ')', 'g'));
2781
2782 if (matches) {
2783 let matched;
2784
2785 for (i = 0; i < matches.length; i += 1) {
2786 matched = matches[i].match(new RegExp('^' + q_sym));
2787
2788 if (matched) {
2789 q_sortable += symbolRanges(matched[0]);
2790 } else {
2791 from = swu2key(matches[i].slice(1, 3));
2792 to = swu2key(matches[i].slice(-2));
2793 from = key2swu(from.slice(0, 4) + '00');
2794 to = key2swu(to.slice(0, 4) + '5f');
2795 q_sortable += range$1(from, to);
2796 }
2797 }
2798
2799 q_sortable += '(' + re_sym + ')*)';
2800 }
2801 }
2802 } //get the variance
2803
2804
2805 matches = query.match(new RegExp(q_var, 'g'));
2806
2807 if (matches) {
2808 fuzz = matches.toString().slice(1) * 1;
2809 } //this gets all symbols with or without location
2810 matches = query.match(new RegExp("(" + q_range + q_coord + "|" + q_sym + q_coord + ")", 'g'));
2811
2812 if (matches) {
2813 for (i = 0; i < matches.length; i += 1) {
2814 part = matches[i].toString();
2815
2816 if (part[0] != "R") {
2817 sym = part.match(new RegExp(q_sym))[0];
2818 segment = symbolRanges(sym);
2819
2820 if (sym.length > part.length) {
2821 coord = swu2coord(part.slice(-4));
2822 x = coord[0];
2823 y = coord[1]; //now get the x segment range+++
2824
2825 segment += range$1(coord2swu([x - fuzz, x + fuzz]));
2826 segment += range$1(coord2swu([y - fuzz, y + fuzz]));
2827 } else {
2828 segment += re_coord;
2829 } //now I have the specific search symbol
2830 // add to general swu word
2831
2832
2833 segment = re_word + segment + '(' + re_sym + re_coord + ')*';
2834
2835 if (sortable) {
2836 segment = q_sortable + segment;
2837 } else {
2838 segment = re_sortable + "?" + segment;
2839 }
2840
2841 if (query.indexOf('-') > 0) {
2842 segment += q_style;
2843 }
2844
2845 segments.push(segment);
2846 } else {
2847 //ranges
2848 part = matches[i].toString();
2849 from = swu2key(part.slice(1, 3));
2850 to = swu2key(part.slice(3, 5));
2851 from = key2swu(from.slice(0, 4) + '00');
2852 to = key2swu(to.slice(0, 4) + '5f');
2853 segment = range$1(from, to);
2854
2855 if (part.length > 5) {
2856 coord = swu2coord(part.slice(5, 9));
2857 x = coord[0];
2858 y = coord[1]; //now get the x segment range+++
2859
2860 segment += range$1(coord2swu([x - fuzz, x + fuzz]));
2861 segment += range$1(coord2swu([y - fuzz, y + fuzz]));
2862 } else {
2863 segment += re_coord;
2864 } // add to general swu word
2865
2866
2867 segment = re_word + segment + '(' + re_sym + re_coord + ')*';
2868
2869 if (sortable) {
2870 segment = q_sortable + segment;
2871 } else {
2872 segment = re_sortable + "?" + segment;
2873 }
2874
2875 if (query.indexOf('-') > 0) {
2876 segment += q_style;
2877 }
2878
2879 segments.push(segment);
2880 }
2881 }
2882 }
2883
2884 if (!segments.length) {
2885 if (query.indexOf('-') > 0) {
2886 segment += q_style;
2887 }
2888
2889 segments.push(q_sortable + re_word);
2890 }
2891
2892 return segments;
2893};
2894
2895/**
2896 * Function that uses a query string to match signs from a string of text.
2897 * @function swuquery.results
2898 * @param {string} query - an SWU query string
2899 * @param {string} text - a string of text containing multiple signs
2900 * @returns {string[]} an array of SWU signs
2901 * @example
2902 * swuquery.results('QA񀀒T','𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭 𝠀񂇢񂇈񆙡񋎥񋎵𝠃𝤛𝤬񂇈𝤀𝣺񂇢𝤄𝣻񋎥𝤄𝤗񋎵𝤃𝣟񆙡𝣱𝣸 𝠀񅨑񀀙񆉁𝠃𝤙𝤞񀀙𝣷𝤀񅨑𝣼𝤀񆉁𝣳𝣮')
2903 *
2904 * return [
2905 * '𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭'
2906 * ]
2907 */
2908
2909const results$1 = (query, text) => {
2910 if (!text) {
2911 return [];
2912 }
2913
2914 let pattern;
2915 let matches;
2916 let parts;
2917 let words;
2918 let res = regex$1(query);
2919
2920 if (!res) {
2921 return [];
2922 }
2923
2924 let i;
2925
2926 for (i = 0; i < res.length; i += 1) {
2927 pattern = res[i];
2928 matches = text.match(new RegExp(pattern, 'g'));
2929
2930 if (matches) {
2931 text = matches.join(' ');
2932 } else {
2933 text = '';
2934 }
2935 }
2936
2937 if (text) {
2938 parts = text.split(' ');
2939 words = parts.filter(function (element) {
2940 return element in parts ? false : parts[element] = true;
2941 }, {});
2942 } else {
2943 words = [];
2944 }
2945
2946 return words;
2947}; //needs rewritten, but it works
2948
2949/**
2950 * Function that uses an SWU query string to match signs from multiple lines of text.
2951 * @function swuquery.lines
2952 * @param {string} query - an SWU query string
2953 * @param {string} text - multiple lines of text, each starting with an SWU sign
2954 * @returns {string[]} an array of lines of text, each starting with an SWU sign
2955 * @example
2956 * swuquery.lines('QA񀀒T',`𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭 line one
2957 * 𝠀񂇢񂇈񆙡񋎥񋎵𝠃𝤛𝤬񂇈𝤀𝣺񂇢𝤄𝣻񋎥𝤄𝤗񋎵𝤃𝣟񆙡𝣱𝣸 line two
2958 * 𝠀񅨑񀀙񆉁𝠃𝤙𝤞񀀙𝣷𝤀񅨑𝣼𝤀񆉁𝣳𝣮 line three`)
2959 *
2960 * return [
2961 * '𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭 line one'
2962 * ]
2963 */
2964
2965
2966const lines$1 = (query, text) => {
2967 if (!text) {
2968 return [];
2969 }
2970
2971 let pattern;
2972 let matches;
2973 let parts;
2974 let words;
2975 let res = regex$1(query);
2976
2977 if (!res) {
2978 return [];
2979 }
2980
2981 let i;
2982
2983 for (i = 0; i < res.length; i += 1) {
2984 pattern = res[i];
2985 pattern = '^' + pattern + '.*';
2986 matches = text.match(new RegExp(pattern, 'mg'));
2987
2988 if (matches) {
2989 text = matches.join("\n");
2990 } else {
2991 text = '';
2992 }
2993 }
2994
2995 if (text) {
2996 parts = text.split("\n");
2997 words = parts.filter(function (element) {
2998 return element in parts ? false : parts[element] = true;
2999 }, {});
3000 } else {
3001 words = [];
3002 }
3003
3004 return words;
3005};
3006
3007/** The swuquery module contains functions for handling the SWU query language.
3008 * [Query Language definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.6)
3009 * @module swuquery
3010 */
3011
3012var index$5 = /*#__PURE__*/Object.freeze({
3013 __proto__: null,
3014 re: re$4,
3015 parse: parse$4,
3016 compose: compose$4,
3017 swu2query: swu2query,
3018 range: range$1,
3019 symbolRanges: symbolRanges,
3020 regex: regex$1,
3021 results: results$1,
3022 lines: lines$1
3023});
3024
3025export { index$1 as convert, index$2 as fsw, index$3 as fswquery, index as style, index$4 as swu, index$5 as swuquery };
3026
3027/* support ongoing development on https://patreon.com/signwriting */