UNPKG

86.1 kBJavaScriptView Raw
1/**
2* Sutton SignWriting Core Module v1.3.1 (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$4 = {
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$4.prefix = `(?:${re$4.sort}(?:${re$4.symbol})+)`;
21re$4.spatial = `${re$4.symbol}${re$4.coord}`;
22re$4.signbox = `${re$4.box}${re$4.coord}(?:${re$4.spatial})*`;
23re$4.sign = `${re$4.prefix}?${re$4.signbox}`;
24re$4.sortable = `${re$4.prefix}${re$4.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$3 = {
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$3.colorbase = `(?:${re$3.colorhex}|${re$3.colorname})`;
44re$3.color = `_${re$3.colorbase}_`;
45re$3.colors = `_${re$3.colorbase}(?:,${re$3.colorbase})?_`;
46re$3.background = `G${re$3.color}`;
47re$3.detail = `D${re$3.colors}`;
48re$3.detailsym = `D[0-9]{2}${re$3.colors}`;
49re$3.classes = `${re$3.classbase}(?: ${re$3.classbase})*`;
50re$3.full = `-(${re$3.colorize})?(${re$3.padding})?(${re$3.background})?(${re$3.detail})?(${re$3.zoom})?(?:-((?:${re$3.detailsym})*)((?:${re$3.zoomsym})*))?(?:-(${re$3.classes})?!(?:(${re$3.id})!)?)?`;
51
52const prefixColor = color => {
53 const regex = new RegExp(`^${re$3.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$4 = styleString => {
74 const regex = `^${re$3.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$3.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$3.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$4 = 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$3.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$3.colorbase)[0];
162 const detail2 = !styleObject.detail || !styleObject.detail[1] || !(typeof styleObject.detail[1] === 'string') ? undefined : styleObject.detail[1].match(re$3.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$3.colorbase)[0];
182 const detail2 = !styleObject.detail || !styleObject.detail[1] ? undefined : styleObject.detail[1].match(re$3.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$3.classes)[0];
218 style3 += !classes ? '' : classes;
219 const id = !styleObject.id || !(typeof styleObject.id === 'string') ? undefined : styleObject.id.match(re$3.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$5 = /*#__PURE__*/Object.freeze({
231 __proto__: null,
232 re: re$3,
233 parse: parse$4,
234 compose: compose$4
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$4.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$4.box + re$4.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$4.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$4 = /*#__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$3 = {
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$4.symbol})(${re$4.coord})?(${re$3.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$4.prefix})?(${re$4.signbox})(${re$3.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$3 = {
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$4.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$4.coord) || [''])[0] || '';
698 const styleStr = typeof fswSymObject.style === 'string' && (fswSymObject.style.match(re$3.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$4.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$4.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$4.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$4.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$4.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$3.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$1 = [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$1 = [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$1 = [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$1 = {
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$1 = (key, type) => {
839 const parsed = parse$3.symbol(key);
840
841 if (parsed.symbol) {
842 const dec = parseInt(parsed.symbol.slice(1, 4), 16);
843 const range = ranges$1[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$1 = ['#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$1 = key => {
872 const parsed = parse$3.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$1.findIndex(val => val > dec);
878 color = colors$1[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$3 = /*#__PURE__*/Object.freeze({
890 __proto__: null,
891 re: re$4,
892 parse: parse$3,
893 compose: compose$3,
894 kind: kind$1,
895 category: category$1,
896 group: group$1,
897 ranges: ranges$1,
898 isType: isType$1,
899 colors: colors$1,
900 colorize: colorize$1
901});
902
903/**
904 * Object of regular expressions for FSW query strings
905 *
906 * { base, coord, var, symbol, range, item, list, prefix, signbox, full }
907 * @alias fswquery.re
908 * @type {object}
909 */
910let re$1 = {
911 'base': '[123][0-9a-f]{2}',
912 'coord': '(?:[0-9]{3}x[0-9]{3})?',
913 'var': 'V[0-9]+'
914};
915re$1.symbol = `S${re$1.base}[0-5u][0-9a-fu]`;
916re$1.range = `R${re$1.base}t${re$1.base}`;
917re$1.item = `(?:${re$1.symbol}|${re$1.range})`;
918re$1.list = `${re$1.item}(?:o${re$1.item})*`;
919re$1.prefix = `(?:A(?:${re$1.list})+)?T`;
920re$1.signbox = `(?:${re$1.list}${re$1.coord})*`;
921re$1.full = `Q(${re$1.prefix})?(${re$1.signbox})?(${re$1.var})?(-?)`;
922
923const parsePrefix$1 = text => {
924 return {
925 required: true,
926 parts: text == 'T' ? undefined : text.match(new RegExp(`${re$1.list}`, 'g')).map(part => {
927 if (part.includes('o')) {
928 return ['or'].concat(part.match(new RegExp(`(${re$1.item})`, 'g')).map(part => part[0] == 'S' ? part : part.slice(1).split('t')));
929 } else {
930 return part[0] == 'S' ? part : part.slice(1).split('t');
931 }
932 })
933 };
934};
935
936const parseSignbox$1 = text => {
937 return text.match(new RegExp(`(${re$1.list}${re$1.coord})`, 'g')).map(part => {
938 let coord, front;
939
940 if (part.includes('x')) {
941 coord = fsw2coord(part.slice(-7));
942 front = part.slice(0, -7);
943 } else {
944 front = part;
945 }
946
947 if (front.includes('o')) {
948 return {
949 or: front.split('o').map(part => {
950 if (part.includes('S')) {
951 return part;
952 } else {
953 return part.slice(1).split('t');
954 }
955 }),
956 coord,
957 coord
958 };
959 } else if (front.includes('S')) {
960 return {
961 symbol: front,
962 coord: coord
963 };
964 } else {
965 return {
966 range: front.slice(1).split('t'),
967 coord: coord
968 };
969 }
970 });
971};
972/**
973 * Function to parse FSW query string to object
974 * @function fswquery.parse
975 * @param {string} fswQueryString - an FSW query string
976 * @returns {object} elements of an FSW query string
977 * @example
978 * fswquery.parse('QAS10000S10500oS20500oR2fft304TS100uuR205t206oS207uu510x510V5-')
979 *
980 * return {
981 * "query": true,
982 * "prefix": {
983 * "required": true,
984 * "parts": [
985 * "S10000",
986 * [
987 * "or",
988 * "S10500",
989 * "S20500",
990 * [
991 * "2ff",
992 * "304"
993 * ]
994 * ]
995 * ]
996 * },
997 * "signbox": [
998 * {
999 * "symbol": "S100uu"
1000 * },
1001 * {
1002 * "or": [
1003 * [
1004 * "205",
1005 * "206"
1006 * ],
1007 * "S207uu"
1008 * ],
1009 * "coord": [
1010 * 510,
1011 * 510
1012 * ]
1013 * }
1014 * ],
1015 * "variance": 5,
1016 * "style": true
1017 * }
1018 */
1019
1020
1021const parse$2 = fswQueryString => {
1022 const query = typeof fswQueryString === 'string' ? fswQueryString.match(new RegExp(`^${re$1.full}`)) : undefined;
1023 return {
1024 'query': query ? true : undefined,
1025 'prefix': query && query[1] ? parsePrefix$1(query[1]) : undefined,
1026 'signbox': query && query[2] ? parseSignbox$1(query[2]) : undefined,
1027 'variance': query && query[3] ? parseInt(query[3].slice(1)) : undefined,
1028 'style': query && query[4] ? true : undefined
1029 };
1030};
1031
1032/**
1033 * Function to compose FSW query string from object
1034 * @function fswquery.compose
1035 * @param {object} fswQueryObject - an object of style options
1036 * @param {boolean} fswQueryObject.query - required true for FSW query object
1037 * @param {object} fswQueryObject.prefix - an object for prefix elements
1038 * @param {boolean} fswQueryObject.prefix.required - true if sorting prefix is required
1039 * @param {(string|string[]|(string|string[])[])[]} fswQueryObject.prefix.parts - array of symbol strings, range arrays, and OR arrays of strings and range arrays
1040 * @param {({symbol:string,coord:number[]}|{range:string[],coord:number[]}|{or:(string|string[])[],coord:number[]})[]} fswQueryObject.signbox - array of objects for symbols, ranges, and list of symbols or ranges, with optional coordinates
1041 * @param {number} fswQueryObject.variance - amount that x or y coordinates can vary and find a match, defaults to 20
1042 * @param {boolean} fswQueryObject.style - boolean value for including style string in matches
1043 * @returns {string} FSW query string
1044 * @example
1045 * fswquery.compose({
1046 * query: true,
1047 * prefix: {
1048 * required: true,
1049 * parts: [
1050 * 'S10000',
1051 * ['100', '204'],
1052 * 'S20500'
1053 * ]
1054 * },
1055 * signbox: [
1056 * { symbol: 'S20000' },
1057 * {
1058 * range: ['100', '105'],
1059 * coord: [500, 500]
1060 * }
1061 * ],
1062 * variance: 5,
1063 * style: true
1064 * })
1065 *
1066 * return 'QAS10000R100t204S20500TS20000R100t105500x500V5-'
1067 */
1068
1069const compose$2 = fswQueryObject => {
1070 if (!fswQueryObject || !fswQueryObject.query) {
1071 return undefined;
1072 }
1073
1074 let query = 'Q';
1075
1076 if (fswQueryObject.prefix && fswQueryObject.prefix.required) {
1077 if (Array.isArray(fswQueryObject.prefix.parts)) {
1078 query += 'A';
1079 query += fswQueryObject.prefix.parts.map(part => {
1080 if (typeof part === 'string') {
1081 return part;
1082 } else {
1083 if (Array.isArray(part) && part.length == 2) {
1084 return `R${part[0]}t${part[1]}`;
1085 } else if (Array.isArray(part) && part.length > 2 && part[0] == 'or') {
1086 part.shift();
1087 return part.map(part => {
1088 if (typeof part === 'string') {
1089 return part;
1090 } else {
1091 if (Array.isArray(part) && part.length == 2) {
1092 return `R${part[0]}t${part[1]}`;
1093 }
1094 }
1095 }).join('o');
1096 }
1097 }
1098 }).join('');
1099 }
1100
1101 query += 'T';
1102 }
1103
1104 if (Array.isArray(fswQueryObject.signbox)) {
1105 query += fswQueryObject.signbox.map(part => {
1106 let out;
1107
1108 if (part.or) {
1109 out = part.or.map(item => {
1110 if (typeof item === 'string') {
1111 return item;
1112 } else {
1113 if (Array.isArray(item) && item.length == 2) {
1114 return `R${item[0]}t${item[1]}`;
1115 }
1116 }
1117 }).join('o');
1118 } else if (part.symbol) {
1119 out = part.symbol;
1120 } else {
1121 if (part.range && Array.isArray(part.range) && part.range.length == 2) {
1122 out = `R${part.range[0]}t${part.range[1]}`;
1123 }
1124 }
1125
1126 return out + (Array.isArray(part.coord) && part.coord.length == 2 ? part.coord.join('x') : '');
1127 }).join('');
1128 }
1129
1130 query += fswQueryObject.style ? '-' : '';
1131 query = query.match(new RegExp(`^${re$1.full}`))[0];
1132 return query;
1133};
1134
1135/**
1136 * Function to convert an FSW sign to a query string
1137 *
1138 * For the flags parameter, use one or more of the following.
1139 * - A: exact symbol in temporal prefix
1140 * - a: general symbol in temporal prefix
1141 * - S: exact symbol in spatial signbox
1142 * - s: general symbol in spatial signbox
1143 * - L: spatial signbox symbol at location
1144 * @function fswquery.fsw2query
1145 * @param {string} fswSign - FSW sign
1146 * @param {string} flags - flags for query string creation
1147 * @returns {string} FSW query string
1148 * @example
1149 * fswquery.fsw2query('AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475', 'ASL')
1150 *
1151 * return 'QAS10011S10019S2e704S2e748TS2e748483x510S10011501x466S2e704510x500S10019476x475'
1152 */
1153
1154const fsw2query = (fswSign, flags) => {
1155 let query = '';
1156 const parsed = parse$3.sign(fswSign);
1157
1158 if (parsed.box) {
1159 const A_flag = flags.indexOf('A') > -1;
1160 const a_flag = flags.indexOf('a') > -1;
1161 const S_flag = flags.indexOf('S') > -1;
1162 const s_flag = flags.indexOf('s') > -1;
1163 const L_flag = flags.indexOf('L') > -1;
1164
1165 if (A_flag || a_flag || S_flag || s_flag) {
1166 if ((A_flag || a_flag) && parsed.sequence) {
1167 query += 'A';
1168 query += parsed.sequence.map(sym => sym.slice(0, 4) + (a_flag ? 'uu' : sym.slice(4, 6))).join('');
1169 query += 'T';
1170 }
1171
1172 if ((S_flag || s_flag) && parsed.spatials) {
1173 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('');
1174 }
1175 }
1176
1177 return query ? "Q" + query : undefined;
1178 } else {
1179 return undefined;
1180 }
1181};
1182
1183//needs rewritten, but it works
1184
1185/**
1186 * Function to transform a range to a regular expression
1187 * @function fswquery.range
1188 * @param {(number|string)} min - either a decimal number or hexidecimal string
1189 * @param {(number|string)} max - either a decimal number or hexidecimal string
1190 * @param {boolean?} hex - if true, the regular expression will match a hexidecimal range
1191 * @returns {string} a regular expression that matches a range
1192 * @example
1193 * fswquery.range(500,750)
1194 *
1195 * return '(([56][0-9][0-9])|(7[0-4][0-9])|(750))'
1196 * @example
1197 * fswquery.range('100','10e',true)
1198 *
1199 * return '10[0-9a-e]'
1200 */
1201const range$1 = (min, max, hex) => {
1202 let pattern;
1203 let re;
1204 let diff;
1205 let tmax;
1206 let cnt;
1207 let minV;
1208 let maxV;
1209
1210 if (!hex) {
1211 hex = '';
1212 }
1213
1214 min = ("000" + min).slice(-3);
1215 max = '' + max;
1216 pattern = '';
1217
1218 if (min === max) {
1219 return min;
1220 } //ending pattern will be series of connected OR ranges
1221
1222
1223 re = []; //first pattern+ 10's don't match and the min 1's are not zero
1224 //odd number to 9
1225
1226 if (!(min[0] == max[0] && min[1] == max[1])) {
1227 if (min[2] != '0') {
1228 pattern = min[0] + min[1];
1229
1230 if (hex) {
1231 //switch for dex
1232 switch (min[2]) {
1233 case "f":
1234 pattern += 'f';
1235 break;
1236
1237 case "e":
1238 pattern += '[ef]';
1239 break;
1240
1241 case "d":
1242 case "c":
1243 case "b":
1244 case "a":
1245 pattern += '[' + min[2] + '-f]';
1246 break;
1247
1248 default:
1249 switch (min[2]) {
1250 case "9":
1251 pattern += '[9a-f]';
1252 break;
1253
1254 case "8":
1255 pattern += '[89a-f]';
1256 break;
1257
1258 default:
1259 pattern += '[' + min[2] + '-9a-f]';
1260 break;
1261 }
1262
1263 break;
1264 }
1265
1266 diff = 15 - parseInt(min[2], 16) + 1;
1267 min = '' + (parseInt(min, 16) + diff).toString(16);
1268 re.push(pattern);
1269 } else {
1270 //switch for dex
1271 switch (min[2]) {
1272 case "9":
1273 pattern += '9';
1274 break;
1275
1276 case "8":
1277 pattern += '[89]';
1278 break;
1279
1280 default:
1281 pattern += '[' + min[2] + '-9]';
1282 break;
1283 }
1284
1285 diff = 9 - min[2] + 1;
1286 min = '' + (min * 1 + diff);
1287 re.push(pattern);
1288 }
1289 }
1290 }
1291
1292 pattern = ''; //if hundreds are different, get odd to 99 or ff
1293
1294 if (min[0] != max[0]) {
1295 if (min[1] != '0') {
1296 if (hex) {
1297 //scrape to ff
1298 pattern = min[0];
1299
1300 switch (min[1]) {
1301 case "f":
1302 pattern += 'f';
1303 break;
1304
1305 case "e":
1306 pattern += '[ef]';
1307 break;
1308
1309 case "d":
1310 case "c":
1311 case "b":
1312 case "a":
1313 pattern += '[' + min[1] + '-f]';
1314 break;
1315
1316 case "9":
1317 pattern += '[9a-f]';
1318 break;
1319
1320 case "8":
1321 pattern += '[89a-f]';
1322 break;
1323
1324 default:
1325 pattern += '[' + min[1] + '-9a-f]';
1326 break;
1327 }
1328
1329 pattern += '[0-9a-f]';
1330 diff = 15 - parseInt(min[1], 16) + 1;
1331 min = '' + (parseInt(min, 16) + diff * 16).toString(16);
1332 re.push(pattern);
1333 } else {
1334 //scrape to 99
1335 pattern = min[0];
1336 diff = 9 - min[1] + 1;
1337
1338 switch (min[1]) {
1339 case "9":
1340 pattern += '9';
1341 break;
1342
1343 case "8":
1344 pattern += '[89]';
1345 break;
1346
1347 default:
1348 pattern += '[' + min[1] + '-9]';
1349 break;
1350 }
1351
1352 pattern += '[0-9]';
1353 diff = 9 - min[1] + 1;
1354 min = '' + (min * 1 + diff * 10);
1355 re.push(pattern);
1356 }
1357 }
1358 }
1359
1360 pattern = ''; //if hundreds are different, get to same
1361
1362 if (min[0] != max[0]) {
1363 if (hex) {
1364 diff = parseInt(max[0], 16) - parseInt(min[0], 16);
1365 tmax = (parseInt(min[0], 16) + diff - 1).toString(16);
1366
1367 switch (diff) {
1368 case 1:
1369 pattern = min[0];
1370 break;
1371
1372 case 2:
1373 pattern = '[' + min[0] + tmax + ']';
1374 break;
1375
1376 default:
1377 if (parseInt(min[0], 16) > 9) {
1378 minV = 'h';
1379 } else {
1380 minV = 'd';
1381 }
1382
1383 if (parseInt(tmax, 16) > 9) {
1384 maxV = 'h';
1385 } else {
1386 maxV = 'd';
1387 }
1388
1389 switch (minV + maxV) {
1390 case "dd":
1391 pattern += '[' + min[0] + '-' + tmax + ']';
1392 break;
1393
1394 case "dh":
1395 diff = 9 - min[0]; //firs get up to 9
1396
1397 switch (diff) {
1398 case 0:
1399 pattern += '[9';
1400 break;
1401
1402 case 1:
1403 pattern += '[89';
1404 break;
1405
1406 default:
1407 pattern += '[' + min[0] + '-9';
1408 break;
1409 }
1410
1411 switch (tmax[0]) {
1412 case 'a':
1413 pattern += 'a]';
1414 break;
1415
1416 case 'b':
1417 pattern += 'ab]';
1418 break;
1419
1420 default:
1421 pattern += 'a-' + tmax + ']';
1422 break;
1423 }
1424
1425 break;
1426
1427 case "hh":
1428 pattern += '[' + min[0] + '-' + tmax + ']';
1429 break;
1430 }
1431
1432 }
1433
1434 pattern += '[0-9a-f][0-9a-f]';
1435 diff = parseInt(max[0], 16) - parseInt(min[0], 16);
1436 min = '' + (parseInt(min, 16) + diff * 256).toString(16);
1437 re.push(pattern);
1438 } else {
1439 diff = max[0] - min[0];
1440 tmax = min[0] * 1 + diff - 1;
1441
1442 switch (diff) {
1443 case 1:
1444 pattern = min[0];
1445 break;
1446
1447 case 2:
1448 pattern = '[' + min[0] + tmax + ']';
1449 break;
1450
1451 default:
1452 pattern = '[' + min[0] + '-' + tmax + ']';
1453 break;
1454 }
1455
1456 pattern += '[0-9][0-9]';
1457 min = '' + (min * 1 + diff * 100);
1458 re.push(pattern);
1459 }
1460 }
1461
1462 pattern = ''; //if tens are different, get to same
1463
1464 if (min[1] != max[1]) {
1465 if (hex) {
1466 diff = parseInt(max[1], 16) - parseInt(min[1], 16);
1467 tmax = (parseInt(min[1], 16) + diff - 1).toString(16);
1468 pattern = min[0];
1469
1470 switch (diff) {
1471 case 1:
1472 pattern += min[1];
1473 break;
1474
1475 case 2:
1476 pattern += '[' + min[1] + tmax + ']';
1477 break;
1478
1479 default:
1480 if (parseInt(min[1], 16) > 9) {
1481 minV = 'h';
1482 } else {
1483 minV = 'd';
1484 }
1485
1486 if (parseInt(tmax, 16) > 9) {
1487 maxV = 'h';
1488 } else {
1489 maxV = 'd';
1490 }
1491
1492 switch (minV + maxV) {
1493 case "dd":
1494 pattern += '[' + min[1];
1495
1496 if (diff > 1) {
1497 pattern += '-';
1498 }
1499
1500 pattern += tmax + ']';
1501 break;
1502
1503 case "dh":
1504 diff = 9 - min[1]; //firs get up to 9
1505
1506 switch (diff) {
1507 case 0:
1508 pattern += '[9';
1509 break;
1510
1511 case 1:
1512 pattern += '[89';
1513 break;
1514
1515 default:
1516 pattern += '[' + min[1] + '-9';
1517 break;
1518 }
1519
1520 switch (max[1]) {
1521 case 'a':
1522 pattern += ']';
1523 break;
1524
1525 case 'b':
1526 pattern += 'a]';
1527 break;
1528
1529 default:
1530 pattern += 'a-' + (parseInt(max[1], 16) - 1).toString(16) + ']';
1531 break;
1532 }
1533
1534 break;
1535
1536 case "hh":
1537 pattern += '[' + min[1];
1538
1539 if (diff > 1) {
1540 pattern += '-';
1541 }
1542
1543 pattern += (parseInt(max[1], 16) - 1).toString(16) + ']';
1544 break;
1545 }
1546
1547 break;
1548 }
1549
1550 pattern += '[0-9a-f]';
1551 diff = parseInt(max[1], 16) - parseInt(min[1], 16);
1552 min = '' + (parseInt(min, 16) + diff * 16).toString(16);
1553 re.push(pattern);
1554 } else {
1555 diff = max[1] - min[1];
1556 tmax = min[1] * 1 + diff - 1;
1557 pattern = min[0];
1558
1559 switch (diff) {
1560 case 1:
1561 pattern += min[1];
1562 break;
1563
1564 case 2:
1565 pattern += '[' + min[1] + tmax + ']';
1566 break;
1567
1568 default:
1569 pattern += '[' + min[1] + '-' + tmax + ']';
1570 break;
1571 }
1572
1573 pattern += '[0-9]';
1574 min = '' + (min * 1 + diff * 10);
1575 re.push(pattern);
1576 }
1577 }
1578
1579 pattern = ''; //if digits are different, get to same
1580
1581 if (min[2] != max[2]) {
1582 if (hex) {
1583 pattern = min[0] + min[1];
1584 diff = parseInt(max[2], 16) - parseInt(min[2], 16);
1585
1586 if (parseInt(min[2], 16) > 9) {
1587 minV = 'h';
1588 } else {
1589 minV = 'd';
1590 }
1591
1592 if (parseInt(max[2], 16) > 9) {
1593 maxV = 'h';
1594 } else {
1595 maxV = 'd';
1596 }
1597
1598 switch (minV + maxV) {
1599 case "dd":
1600 pattern += '[' + min[2];
1601
1602 if (diff > 1) {
1603 pattern += '-';
1604 }
1605
1606 pattern += max[2] + ']';
1607 break;
1608
1609 case "dh":
1610 diff = 9 - min[2]; //firs get up to 9
1611
1612 switch (diff) {
1613 case 0:
1614 pattern += '[9';
1615 break;
1616
1617 case 1:
1618 pattern += '[89';
1619 break;
1620
1621 default:
1622 pattern += '[' + min[2] + '-9';
1623 break;
1624 }
1625
1626 switch (max[2]) {
1627 case 'a':
1628 pattern += 'a]';
1629 break;
1630
1631 case 'b':
1632 pattern += 'ab]';
1633 break;
1634
1635 default:
1636 pattern += 'a-' + max[2] + ']';
1637 break;
1638 }
1639
1640 break;
1641
1642 case "hh":
1643 pattern += '[' + min[2];
1644
1645 if (diff > 1) {
1646 pattern += '-';
1647 }
1648
1649 pattern += max[2] + ']';
1650 break;
1651 }
1652
1653 diff = parseInt(max[2], 16) - parseInt(min[2], 16);
1654 min = '' + (parseInt(min, 16) + diff).toString(16);
1655 re.push(pattern);
1656 } else {
1657 diff = max[2] - min[2];
1658 pattern = min[0] + min[1];
1659
1660 switch (diff) {
1661 case 0:
1662 pattern += min[2];
1663 break;
1664
1665 case 1:
1666 pattern += '[' + min[2] + max[2] + ']';
1667 break;
1668
1669 default:
1670 pattern += '[' + min[2] + '-' + max[2] + ']';
1671 break;
1672 }
1673
1674 min = '' + (min * 1 + diff);
1675 re.push(pattern);
1676 }
1677 }
1678
1679 pattern = ''; //last place is whole hundred
1680
1681 if (min[2] == '0' && max[2] == '0') {
1682 pattern = max;
1683 re.push(pattern);
1684 }
1685
1686 pattern = '';
1687 cnt = re.length;
1688
1689 if (cnt == 1) {
1690 pattern = re[0];
1691 } else {
1692 pattern = re.join(')|(');
1693 pattern = '((' + pattern + '))';
1694 }
1695
1696 return pattern;
1697};
1698
1699const regexSymbol = sym => {
1700 let segment = sym.slice(0, 4);
1701 let fill = sym.slice(4, 5);
1702
1703 if (fill == 'u') {
1704 segment += '[0-5]';
1705 } else {
1706 segment += fill;
1707 }
1708
1709 let rotate = sym.slice(5, 6);
1710
1711 if (rotate == 'u') {
1712 segment += '[0-9a-f]';
1713 } else {
1714 segment += rotate;
1715 }
1716
1717 return segment;
1718};
1719
1720const regexRange$1 = symRange => {
1721 let from = symRange.slice(1, 4);
1722 let to = symRange.slice(5, 8);
1723 return 'S' + range$1(from, to, 'hex') + '[0-5][0-9a-f]';
1724}; //needs rewritten, but it works
1725
1726/**
1727 * Function to transform an FSW query string to one or more regular expressions
1728 * @function fswquery.regex
1729 * @param {string} query - an FSW query string
1730 * @returns {string[]} an array of one or more regular expressions
1731 * @example
1732 * fswquery.regex('QS100uuS20500480x520')
1733 *
1734 * return [
1735 * '(?: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})*',
1736 * '(?: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})*'
1737 * ]
1738 */
1739
1740
1741const regex$1 = query => {
1742 query = query.match(new RegExp(`^${re$1.full}`))[0];
1743
1744 if (!query) {
1745 return '';
1746 }
1747
1748 var matches;
1749 var matchesOr;
1750 var matched;
1751 var orList;
1752 var i;
1753 var j;
1754 var segment;
1755 var coord;
1756 var x;
1757 var y;
1758 var fuzz = 20;
1759 var q_style = '(' + re$3.full + ')?';
1760 var q_sortable;
1761
1762 if (query == 'Q') {
1763 return [re$4.prefix + "?" + re$4.signbox];
1764 }
1765
1766 if (query == 'Q-') {
1767 return [re$4.prefix + "?" + re$4.signbox + q_style];
1768 }
1769
1770 if (query == 'QT') {
1771 return [re$4.prefix + re$4.signbox];
1772 }
1773
1774 if (query == 'QT-') {
1775 return [re$4.prefix + re$4.signbox + q_style];
1776 }
1777
1778 var segments = [];
1779 var sortable = query.indexOf('T') + 1;
1780
1781 if (sortable) {
1782 q_sortable = '(A';
1783 var qat = query.slice(0, sortable);
1784 query = query.replace(qat, '');
1785
1786 if (qat == 'QT') {
1787 q_sortable += '(' + re$4.symbol + ')+)';
1788 } else {
1789 matches = qat.match(new RegExp('(' + re$1.list + ')', 'g'));
1790
1791 if (matches) {
1792 for (i = 0; i < matches.length; i += 1) {
1793 orList = [];
1794 matchesOr = matches[i].match(new RegExp('(' + re$1.symbol + '|' + re$1.range + ')', 'g'));
1795
1796 if (matchesOr) {
1797 for (j = 0; j < matchesOr.length; j += 1) {
1798 matched = matchesOr[j].match(new RegExp(re$1.symbol));
1799
1800 if (matched) {
1801 orList.push(regexSymbol(matched[0]));
1802 } else {
1803 orList.push(regexRange$1(matchesOr[j]));
1804 }
1805 }
1806
1807 if (orList.length == 1) {
1808 q_sortable += orList[0];
1809 } else {
1810 q_sortable += '(' + orList.join('|') + ')';
1811 }
1812 }
1813 }
1814
1815 q_sortable += '(' + re$4.symbol + ')*)';
1816 }
1817 }
1818 } //get the variance
1819
1820
1821 matches = query.match(new RegExp(re$1.var, 'g'));
1822
1823 if (matches) {
1824 fuzz = matches.toString().slice(1) * 1;
1825 } //this gets all symbols and ranges with or without location
1826
1827
1828 matches = query.match(new RegExp(re$1.list + re$1.coord, 'g'));
1829
1830 if (matches) {
1831 for (i = 0; i < matches.length; i += 1) {
1832 orList = [];
1833 matchesOr = matches[i].match(new RegExp('(' + re$1.symbol + '|' + re$1.range + ')', 'g'));
1834
1835 if (matchesOr) {
1836 for (j = 0; j < matchesOr.length; j += 1) {
1837 matched = matchesOr[j].match(new RegExp(re$1.symbol));
1838
1839 if (matched) {
1840 orList.push(regexSymbol(matched[0]));
1841 } else {
1842 orList.push(regexRange$1(matchesOr[j]));
1843 }
1844 }
1845
1846 if (orList.length == 1) {
1847 segment = orList[0];
1848 } else {
1849 segment = '(' + orList.join('|') + ')';
1850 }
1851 }
1852
1853 if (matches[i].includes('x')) {
1854 coord = fsw2coord(matches[i].slice(-7));
1855 x = coord[0];
1856 y = coord[1];
1857 segment += range$1(x - fuzz, x + fuzz);
1858 segment += 'x';
1859 segment += range$1(y - fuzz, y + fuzz);
1860 } else {
1861 segment += re$4.coord;
1862 } // add to general fsw word
1863
1864
1865 segment = re$4.signbox + segment + '(' + re$4.symbol + re$4.coord + ')*';
1866
1867 if (sortable) {
1868 segment = q_sortable + segment;
1869 } else {
1870 segment = re$4.prefix + "?" + segment;
1871 }
1872
1873 if (query.indexOf('-') > 0) {
1874 segment += q_style;
1875 }
1876
1877 segments.push(segment);
1878 }
1879 }
1880
1881 if (!segments.length) {
1882 if (query.indexOf('-') > 0) {
1883 segment += q_style;
1884 }
1885
1886 segments.push(q_sortable + re$4.signbox);
1887 }
1888
1889 return segments;
1890};
1891
1892/**
1893 * Function that uses a query string to match signs from a string of text.
1894 * @function fswquery.results
1895 * @param {string} query - an FSW query string
1896 * @param {string} text - a string of text containing multiple signs
1897 * @returns {string[]} an array of FSW signs
1898 * @example
1899 * fswquery.results('QAS10011T','AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475 AS15a21S15a07S21100S2df04S2df14M521x538S15a07494x488S15a21498x489S2df04498x517S2df14497x461S21100479x486 AS1f010S10018S20600M519x524S10018485x494S1f010490x494S20600481x476')
1900 *
1901 * return [
1902 * 'AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475'
1903 * ]
1904 */
1905
1906const results$1 = (query, text) => {
1907 if (!text) {
1908 return [];
1909 }
1910
1911 let pattern;
1912 let matches;
1913 let parts;
1914 let words;
1915 let re = regex$1(query);
1916
1917 if (!re) {
1918 return [];
1919 }
1920
1921 let i;
1922
1923 for (i = 0; i < re.length; i += 1) {
1924 pattern = re[i];
1925 matches = text.match(new RegExp(pattern, 'g'));
1926
1927 if (matches) {
1928 text = matches.join(' ');
1929 } else {
1930 text = '';
1931 }
1932 }
1933
1934 if (text) {
1935 parts = text.split(' ');
1936 words = parts.filter(function (element) {
1937 return element in parts ? false : parts[element] = true;
1938 }, {});
1939 } else {
1940 words = [];
1941 }
1942
1943 return words;
1944}; //needs rewritten, but it works
1945
1946/**
1947 * Function that uses an FSW query string to match signs from multiple lines of text.
1948 * @function fswquery.lines
1949 * @param {string} query - an FSW query string
1950 * @param {string} text - multiple lines of text, each starting with an FSW sign
1951 * @returns {string[]} an array of lines of text, each starting with an FSW sign
1952 * @example
1953 * fswquery.lines('QAS10011T',`AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475 line one
1954 * AS15a21S15a07S21100S2df04S2df14M521x538S15a07494x488S15a21498x489S2df04498x517S2df14497x461S21100479x486 line two
1955 * AS1f010S10018S20600M519x524S10018485x494S1f010490x494S20600481x476 line three`)
1956 *
1957 * return [
1958 * 'AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475 line one'
1959 * ]
1960 */
1961
1962
1963const lines$1 = (query, text) => {
1964 if (!text) {
1965 return [];
1966 }
1967
1968 let pattern;
1969 let matches;
1970 let parts;
1971 let words;
1972 let re = regex$1(query);
1973
1974 if (!re) {
1975 return [];
1976 }
1977
1978 let i;
1979
1980 for (i = 0; i < re.length; i += 1) {
1981 pattern = re[i];
1982 pattern = '^' + pattern + '.*';
1983 matches = text.match(new RegExp(pattern, 'mg'));
1984
1985 if (matches) {
1986 text = matches.join("\n");
1987 } else {
1988 text = '';
1989 }
1990 }
1991
1992 if (text) {
1993 parts = text.split("\n");
1994 words = parts.filter(function (element) {
1995 return element in parts ? false : parts[element] = true;
1996 }, {});
1997 } else {
1998 words = [];
1999 }
2000
2001 return words;
2002};
2003
2004/** The fswquery module contains functions for handling the FSW query language.
2005 * [Query Language definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.6)
2006 * @module fswquery
2007 */
2008
2009var index$2 = /*#__PURE__*/Object.freeze({
2010 __proto__: null,
2011 re: re$1,
2012 parse: parse$2,
2013 compose: compose$2,
2014 fsw2query: fsw2query,
2015 range: range$1,
2016 regex: regex$1,
2017 results: results$1,
2018 lines: lines$1
2019});
2020
2021const parse$1 = {
2022 /**
2023 * Function to parse an swu symbol with optional coordinate and style string
2024 * @function swu.parse.symbol
2025 * @param {string} swuSym - an swu symbol
2026 * @returns {object} elements of swu symbol
2027 * @example
2028 * swu.parse.symbol('񀀁𝤆𝤆-C')
2029 *
2030 * return {
2031 * 'symbol': '񀀁',
2032 * 'coord': [500, 500],
2033 * 'style': '-C'
2034 * }
2035 */
2036 symbol: swuSym => {
2037 const regex = `^(${re$2.symbol})(${re$2.coord})?(${re$3.full})?`;
2038 const symbol = typeof swuSym === 'string' ? swuSym.match(new RegExp(regex)) : undefined;
2039 return {
2040 'symbol': symbol ? symbol[1] : undefined,
2041 'coord': symbol && symbol[2] ? swu2coord(symbol[2]) : undefined,
2042 'style': symbol ? symbol[3] : undefined
2043 };
2044 },
2045
2046 /**
2047 * Function to parse an swu sign with style string
2048 * @function swu.parse.sign
2049 * @param {string} swuSign - an swu sign
2050 * @returns {object} elements of swu sign
2051 * @example
2052 * swu.parse.sign('𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭-C')
2053 *
2054 * return {
2055 * sequence: ['񀀒','񀀚','񋚥','񋛩'],
2056 * box: '𝠃',
2057 * max: [525, 535],
2058 * spatials: [
2059 * {
2060 * symbol: '񋛩',
2061 * coord: [483, 510]
2062 * },
2063 * {
2064 * symbol: '񀀒',
2065 * coord: [501, 466]
2066 * },
2067 * {
2068 * symbol: '񋚥',
2069 * coord: [510, 500]
2070 * },
2071 * {
2072 * symbol: '񀀚',
2073 * coord: [476, 475]
2074 * }
2075 * ],
2076 * style: '-C'
2077 * }
2078 */
2079 sign: swuSign => {
2080 const regex = `^(${re$2.prefix})?(${re$2.signbox})(${re$3.full})?`;
2081 const sign = typeof swuSign === 'string' ? swuSign.match(new RegExp(regex)) : undefined;
2082
2083 if (sign) {
2084 return {
2085 'sequence': sign[1] ? sign[1].slice(2).match(/.{2}/g) : undefined,
2086 'box': sign[2].slice(0, 2),
2087 'max': swu2coord(sign[2].slice(2, 6)),
2088 'spatials': sign[2].length < 7 ? undefined : sign[2].slice(6).match(/(.{6})/g).map(m => {
2089 return {
2090 symbol: m.slice(0, 2),
2091 coord: swu2coord(m.slice(2))
2092 };
2093 }),
2094 'style': sign[3]
2095 };
2096 } else {
2097 return {};
2098 }
2099 }
2100};
2101/**
2102 * Function to encode SWU characters using the UTF-16 escape format.
2103 * @function swu.encode
2104 * @param {string} swu - SWU characters
2105 * @returns {string} UTF-16 escape format
2106 * @example
2107 * swu.encode('񀀁𝤆𝤆')
2108 *
2109 * return '\\uD8C0\\uDC01\\uD836\\uDD06\\uD836\\uDD06'
2110 */
2111
2112const encode = text => text.replace(/[\u007F-\uFFFF]/g, function (chr) {
2113 return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4).toUpperCase();
2114});
2115/**
2116 * Function to decode UTF-16 escape format to SWU characters.
2117 * @function swu.decode
2118 * @param {string} encoded - UTF-16 escape format
2119 * @returns {string} SWU characters
2120 * @example
2121 * swu.decode('\\uD8C0\\uDC01\\uD836\\uDD06\\uD836\\uDD06')
2122 *
2123 * return '񀀁𝤆𝤆'
2124 */
2125
2126
2127const decode = encoded => encoded.replace(/\\u([0-9A-F]{4})/g, function (match, chr) {
2128 return String.fromCharCode(parseInt(chr, 16));
2129});
2130/**
2131 * Function to decompose an SWU character into UTF-16 surrogate pairs.
2132 * @function swu.pair
2133 * @param {string} swuChar - an SWU character
2134 * @returns {string[]} an array of UTF-16 surrogate pairs
2135 * @example
2136 * swu.pair('񀀁')
2137 *
2138 * return ['D8C0', 'DC01']
2139 */
2140
2141
2142const pair = swuChar => [swuChar.charCodeAt(0).toString(16).toUpperCase(), swuChar.charCodeAt(1).toString(16).toUpperCase()];
2143
2144const compose$1 = {
2145 /**
2146 * Function to compose an swu symbol with optional coordinate and style string
2147 * @function swu.compose.symbol
2148 * @param {object} swuSymObject - an swu symbol object
2149 * @param {string} swuSymObject.symbol - an swu symbol key
2150 * @param {number[]} swuSymObject.coord - top-left coordinate of symbol with 500,500 center
2151 * @param {string} swuSymObject.style - a style string for custom appearance
2152 * @returns {string} an swu symbol string
2153 * @example
2154 * swu.compose.symbol({
2155 * 'symbol': '񀀁',
2156 * 'coord': [500, 500],
2157 * 'style': '-C'
2158 * })
2159 *
2160 * return '񀀁𝤆𝤆-C'
2161 */
2162 symbol: swuSymObject => {
2163 if (typeof swuSymObject !== 'object' || swuSymObject === null) return undefined;
2164
2165 if (typeof swuSymObject.symbol === 'string') {
2166 const symbol = (swuSymObject.symbol.match(re$2.symbol) || [''])[0];
2167
2168 if (symbol) {
2169 const x = swuSymObject.coord && swuSymObject.coord[0] || '';
2170 const y = swuSymObject.coord && swuSymObject.coord[1] || '';
2171 const coord = x && y ? coord2swu([x, y]) : '';
2172 const styleStr = typeof swuSymObject.style === 'string' && (swuSymObject.style.match(re$3.full) || [''])[0] || '';
2173 return symbol + coord + styleStr;
2174 }
2175 }
2176
2177 return undefined;
2178 },
2179
2180 /**
2181 * Function to compose an swu sign with style string
2182 * @function swu.compose.sign
2183 * @param {string[]} swuSignObject.sequence - an ordered array of symbols
2184 * @param {string} swuSignObject.box - a choice BLMR: horizontal Box, Left, Middle, and Right lane
2185 * @param {number[]} swuSymObject.max - max bottom left coordinate of the signbox space
2186 * @param {{symbol:string,coord:number[]}[]} swuSymObject.spatials - array of symbols with top-left coordinate placement
2187 * @param {string} swuSymObject.style - a style string for custom appearance
2188 * @returns {string} an swu sign string
2189 * @example
2190 * swu.compose.sign({
2191 * sequence: ['񀀒','񀀚','񋚥','񋛩'],
2192 * box: '𝠃',
2193 * max: [525, 535],
2194 * spatials: [
2195 * {
2196 * symbol: '񋛩',
2197 * coord: [483, 510]
2198 * },
2199 * {
2200 * symbol: '񀀒',
2201 * coord: [501, 466]
2202 * },
2203 * {
2204 * symbol: '񋚥',
2205 * coord: [510, 500]
2206 * },
2207 * {
2208 * symbol: '񀀚',
2209 * coord: [476, 475]
2210 * }
2211 * ],
2212 * style: '-C'
2213 * })
2214 *
2215 * return '𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭-C'
2216 */
2217 sign: swuSignObject => {
2218 if (typeof swuSignObject !== 'object' || swuSignObject === null) return undefined;
2219 let box = typeof swuSignObject.box !== 'string' ? '𝠃' : (swuSignObject.box + '𝠃').match(re$2.box);
2220 const x = swuSignObject.max && swuSignObject.max[0] || '';
2221 const y = swuSignObject.max && swuSignObject.max[1] || '';
2222 const max = x && y ? coord2swu([x, y]) : undefined;
2223 if (!max) return undefined;
2224 let prefix = '';
2225
2226 if (swuSignObject.sequence && Array.isArray(swuSignObject.sequence)) {
2227 prefix = swuSignObject.sequence.map(key => (key.match(re$2.symbol) || [''])[0]).join('');
2228 prefix = prefix ? '𝠀' + prefix : '';
2229 }
2230
2231 let signbox = '';
2232
2233 if (swuSignObject.spatials && Array.isArray(swuSignObject.spatials)) {
2234 signbox = swuSignObject.spatials.map(spatial => {
2235 if (typeof spatial.symbol === 'string') {
2236 const symbol = (spatial.symbol.match(re$2.symbol) || [''])[0];
2237
2238 if (symbol) {
2239 const x = spatial.coord && spatial.coord[0] || '';
2240 const y = spatial.coord && spatial.coord[1] || '';
2241 const coord = x && y ? coord2swu([x, y]) : '';
2242
2243 if (coord) {
2244 return symbol + coord;
2245 }
2246 }
2247 }
2248
2249 return '';
2250 }).join('');
2251 }
2252
2253 const styleStr = typeof swuSignObject.style === 'string' && (swuSignObject.style.match(re$3.full) || [''])[0] || '';
2254 return prefix + box + max + signbox + styleStr;
2255 }
2256};
2257
2258/**
2259 * Array of plane 4 code points for kinds of symbols: writing, location, and punctuation.
2260 * @alias swu.kind
2261 * @type {array}
2262 */
2263
2264const kind = [0x40001, 0x4efa1, 0x4f2a1];
2265/**
2266 * Array of plane 4 code points for categories of symbols: hand, movement, dynamics, head, trunk & limb, location, and punctuation.
2267 * @alias swu.category
2268 * @type {array}
2269 */
2270
2271const category = [0x40001, 0x461e1, 0x4bca1, 0x4bfa1, 0x4e8e1, 0x4efa1, 0x4f2a1];
2272/**
2273 * Array of plane 4 code points for the 30 symbol groups.
2274 * @alias swu.group
2275 * @type {array}
2276 */
2277
2278const 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];
2279/**
2280 * Object of symbol ranges with starting and ending code points on plane 4.
2281 *
2282 * { all, writing, hand, movement, dynamic, head, hcenter, vcenter, trunk, limb, location, punctuation }
2283 * @alias swu.ranges
2284 * @type {object}
2285 */
2286
2287const ranges = {
2288 'all': [0x40001, 0x4f480],
2289 'writing': [0x40001, 0x4efa0],
2290 'hand': [0x40001, 0x461e0],
2291 'movement': [0x461e1, 0x4bca0],
2292 'dynamic': [0x4bca1, 0x4bfa0],
2293 'head': [0x4bfa1, 0x4e8e0],
2294 'hcenter': [0x4bfa1, 0x4e8e0],
2295 'vcenter': [0x4bfa1, 0x4ec40],
2296 'trunk': [0x4e8e1, 0x4ec40],
2297 'limb': [0x4ec41, 0x4efa0],
2298 'location': [0x4efa1, 0x4f2a0],
2299 'punctuation': [0x4f2a1, 0x4f480]
2300};
2301/**
2302 * Function to test if symbol is of a certain type.
2303 * @function swu.isType
2304 * @param {string} swuSym - an SWU symbol character
2305 * @param {string} type - the name of a symbol range
2306 * @returns {boolean} is symbol of specified type
2307 * @example
2308 * swu.isType('񀀁', 'hand')
2309 *
2310 * return true
2311 */
2312
2313const isType = (swuSym, type) => {
2314 const parsed = parse$1.symbol(swuSym);
2315
2316 if (parsed.symbol) {
2317 const code = swu2code(parsed.symbol);
2318 const range = ranges[type];
2319
2320 if (range) {
2321 return range[0] <= code && range[1] >= code;
2322 }
2323 }
2324
2325 return false;
2326};
2327
2328/**
2329 * Array of colors associated with the seven symbol categories.
2330 * @alias swu.colors
2331 * @type {array}
2332 */
2333
2334const colors = ['#0000CC', '#CC0000', '#FF0099', '#006600', '#000000', '#884411', '#FF9900'];
2335/**
2336 * Function that returns the standardized color for a symbol.
2337 * @function swu.colorize
2338 * @param {string} swuSym - an SWU symbol character
2339 * @returns {string} name of standardized color for symbol
2340 * @example
2341 * swu.colorize('񀀁')
2342 *
2343 * return '#0000CC'
2344 */
2345
2346const colorize = swuSym => {
2347 const parsed = parse$1.symbol(swuSym);
2348 let color = '#000000';
2349
2350 if (parsed.symbol) {
2351 const code = swu2code(parsed.symbol);
2352 const index = category.findIndex(val => val > code);
2353 color = colors[index < 0 ? 6 : index - 1];
2354 }
2355
2356 return color;
2357};
2358
2359/** The swu module contains functions for handling SignWriitng in Unicode (SWu) characters.
2360 * [SWU characters definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.2.2)
2361 * @module swu
2362 */
2363
2364var index$1 = /*#__PURE__*/Object.freeze({
2365 __proto__: null,
2366 re: re$2,
2367 parse: parse$1,
2368 encode: encode,
2369 decode: decode,
2370 pair: pair,
2371 compose: compose$1,
2372 kind: kind,
2373 category: category,
2374 group: group,
2375 ranges: ranges,
2376 isType: isType,
2377 colors: colors,
2378 colorize: colorize
2379});
2380
2381/**
2382 * Object of regular expressions for SWU query strings
2383 *
2384 * { base, coord, var, symbol, range, item, list, prefix, signbox, full }
2385 * @alias swuquery.re
2386 * @type {object}
2387 */
2388let re = {
2389 'base': '(?:(?:\uD8C0[\uDC01-\uDFFF])|(?:[\uD8C1-\uD8FC][\uDC00-\uDFFF])|(?:\uD8FD[\uDC00-\uDC80]))',
2390 'coord': '(?:(?:\uD836[\uDC0C-\uDDFF]){2})?',
2391 'var': 'V[0-9]+'
2392};
2393re.symbol = `${re.base}f?r?`;
2394re.range = `R${re.base}${re.base}`;
2395re.item = `(?:${re.symbol}|${re.range})`;
2396re.list = `${re.item}(?:o${re.item})*`;
2397re.prefix = `(?:A(?:${re.list})+)?T`;
2398re.signbox = `(?:${re.list}${re.coord})*`;
2399re.full = `Q(${re.prefix})?(${re.signbox})?(${re.var})?(-?)`;
2400
2401const parsePrefix = text => {
2402 return {
2403 required: true,
2404 parts: text == 'T' ? undefined : text.match(new RegExp(`(${re.list})`, 'g')).map(part => {
2405 if (part.includes('o')) {
2406 return ['or'].concat(part.match(new RegExp(`(${re.item})`, 'g')).map(part => part[0] != 'R' ? part : [part.slice(1, 3), part.slice(3, 5)]));
2407 } else {
2408 return part[0] != 'R' ? part : [part.slice(1, 3), part.slice(3, 5)];
2409 }
2410 })
2411 };
2412};
2413
2414const parseSignbox = text => {
2415 return text.match(new RegExp(`(${re.list}${re.coord})`, 'g')).map(part => {
2416 let coord, front;
2417 coord = part.match(new RegExp(`${re$2.coord}`));
2418
2419 if (coord) {
2420 coord = swu2coord(coord[0]);
2421 front = part.slice(0, -4);
2422 } else {
2423 coord = undefined;
2424 front = part;
2425 }
2426
2427 if (front.includes('o')) {
2428 return {
2429 or: front.split('o').map(part => {
2430 if (!part.includes('R')) {
2431 return part;
2432 } else {
2433 return [part.slice(1, 3), part.slice(3, 5)];
2434 }
2435 }),
2436 coord,
2437 coord
2438 };
2439 } else if (!front.includes('R')) {
2440 return {
2441 symbol: front,
2442 coord: coord
2443 };
2444 } else {
2445 return {
2446 range: [front.slice(1, 3), front.slice(3, 5)],
2447 coord: coord
2448 };
2449 }
2450 });
2451};
2452/**
2453 * Function to parse SWU query string to object
2454 * @function swuquery.parse
2455 * @param {string} swuQueryString - an SWU query string
2456 * @returns {object} elements of an SWU query string
2457 * @example
2458 * swuquery.parse('QA񀀁R񀀁񆆑񆇡T񆀁R񀀁񀇱𝤆𝤆V5-')
2459 *
2460 * return {
2461 * query: true,
2462 * prefix: {
2463 * required: true,
2464 * parts: [
2465 * '񀀁',
2466 * ['񀀁', '񆆑'],
2467 * '񆇡'
2468 * ]
2469 * },
2470 * signbox: [
2471 * { symbol: '񆀁' },
2472 * {
2473 * range: ['񀀁', '񀇱'],
2474 * coord: [500, 500]
2475 * }
2476 * ],
2477 * variance: 5,
2478 * style: true
2479 * }
2480 */
2481
2482
2483const parse = swuQueryString => {
2484 const query = typeof swuQueryString === 'string' ? swuQueryString.match(new RegExp(`^${re.full}`)) : undefined;
2485 return {
2486 'query': query ? true : undefined,
2487 'prefix': query && query[1] ? parsePrefix(query[1]) : undefined,
2488 'signbox': query && query[2] ? parseSignbox(query[2]) : undefined,
2489 'variance': query && query[3] ? parseInt(query[3].slice(1)) : undefined,
2490 'style': query && query[4] ? true : undefined
2491 };
2492};
2493
2494/**
2495 * Function to compose SWU query string from object
2496 * @function swuquery.compose
2497 * @param {object} swuQueryObject - an object of style options
2498 * @param {boolean} swuQueryObject.query - required true for SWU query object
2499 * @param {object} swuQueryObject.prefix - an object for prefix elements
2500 * @param {boolean} swuQueryObject.prefix.required - true if sorting prefix is required
2501 * @param {(string|string[]|(string|string[])[])[]} swuQueryObject.prefix.parts - array of symbol strings, range arrays, and OR arrays of strings and range arrays
2502 * @param {({symbol:string,coord:number[]}|{range:string[],coord:number[]}|{or:(string|string[])[],coord:number[]})[]} swuQueryObject.signbox - array of objects for symbols, ranges, and list of symbols or ranges, with optional coordinates
2503 * @param {number} swuQueryObject.variance - amount that x or y coordinates can vary and find a match, defaults to 20
2504 * @param {boolean} swuQueryObject.style - boolean value for including style string in matches
2505 * @returns {string} SWU query string
2506 * @example
2507 * swuquery.compose({
2508 * query: true,
2509 * prefix: {
2510 * required: true,
2511 * parts: [
2512 * '񀀁',
2513 * ['񀀁', '񆆑'],
2514 * '񆇡'
2515 * ]
2516 * },
2517 * signbox: [
2518 * { symbol: '񆀁' },
2519 * {
2520 * range: ['񀀁', '񀇱'],
2521 * coord: [500, 500]
2522 * }
2523 * ],
2524 * variance: 5,
2525 * style: true
2526 * })
2527 *
2528 * return 'QA񀀁R񀀁񆆑񆇡T񆀁R񀀁񀇱𝤆𝤆V5-'
2529 */
2530
2531const compose = swuQueryObject => {
2532 if (!swuQueryObject || !swuQueryObject.query) {
2533 return undefined;
2534 }
2535
2536 let query = 'Q';
2537
2538 if (swuQueryObject.prefix && swuQueryObject.prefix.required) {
2539 if (Array.isArray(swuQueryObject.prefix.parts)) {
2540 query += 'A';
2541 query += swuQueryObject.prefix.parts.map(part => {
2542 if (typeof part === 'string') {
2543 return part;
2544 } else {
2545 if (Array.isArray(part) && part.length == 2) {
2546 return `R${part[0]}${part[1]}`;
2547 } else if (Array.isArray(part) && part.length > 2 && part[0] == 'or') {
2548 part.shift();
2549 return part.map(part => {
2550 if (typeof part === 'string') {
2551 return part;
2552 } else {
2553 if (Array.isArray(part) && part.length == 2) {
2554 return `R${part[0]}${part[1]}`;
2555 }
2556 }
2557 }).join('o');
2558 }
2559 }
2560 }).join('');
2561 }
2562
2563 query += 'T';
2564 }
2565
2566 if (Array.isArray(swuQueryObject.signbox)) {
2567 query += swuQueryObject.signbox.map(part => {
2568 let out;
2569
2570 if (part.or) {
2571 out = part.or.map(item => {
2572 if (typeof item === 'string') {
2573 return item;
2574 } else {
2575 if (Array.isArray(item) && item.length == 2) {
2576 return `R${item[0]}${item[1]}`;
2577 }
2578 }
2579 }).join('o');
2580 } else if (part.symbol) {
2581 out = part.symbol;
2582 } else {
2583 if (part.range && Array.isArray(part.range) && part.range.length == 2) {
2584 out = `R${part.range[0]}${part.range[1]}`;
2585 }
2586 }
2587
2588 return out + (Array.isArray(part.coord) && part.coord.length == 2 ? coord2swu(part.coord) : '');
2589 }).join('');
2590 }
2591
2592 query += swuQueryObject.style ? '-' : '';
2593 query = query.match(new RegExp(`^${re.full}`))[0];
2594 return query;
2595};
2596
2597/**
2598 * Function to convert an SWU sign to a query string
2599 *
2600 * For the flags parameter, use one or more of the following.
2601 * - A: exact symbol in temporal prefix
2602 * - a: general symbol in temporal prefix
2603 * - S: exact symbol in spatial signbox
2604 * - s: general symbol in spatial signbox
2605 * - L: spatial signbox symbol at location
2606 * @function swuquery.swu2query
2607 * @param {string} swuSign - SWU sign
2608 * @param {string} flags - flags for query string creation
2609 * @returns {string} SWU query string
2610 * @example
2611 * swuquery.swu2query('𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭', 'ASL')
2612 *
2613 * return 'QA񀀒񀀚񋚥񋛩T񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭'
2614 */
2615
2616const swu2query = (swuSign, flags) => {
2617 let query = '';
2618 const parsed = parse$1.sign(swuSign);
2619
2620 if (parsed.box) {
2621 const A_flag = flags.indexOf('A') > -1;
2622 const a_flag = flags.indexOf('a') > -1;
2623 const S_flag = flags.indexOf('S') > -1;
2624 const s_flag = flags.indexOf('s') > -1;
2625 const L_flag = flags.indexOf('L') > -1;
2626
2627 if (A_flag || a_flag || S_flag || s_flag) {
2628 if ((A_flag || a_flag) && parsed.sequence) {
2629 query += 'A';
2630 query += parsed.sequence.map(sym => sym + (a_flag ? 'fr' : '')).join('');
2631 query += 'T';
2632 }
2633
2634 if ((S_flag || s_flag) && parsed.spatials) {
2635 query += parsed.spatials.map(spatial => spatial.symbol + (s_flag ? 'fr' : '') + (L_flag ? coord2swu(spatial.coord) : '')).join('');
2636 }
2637 }
2638
2639 return query ? "Q" + query : undefined;
2640 } else {
2641 return undefined;
2642 }
2643};
2644
2645/**
2646 * Function to transform a range of SWU characters to a regular expression
2647 * @function swuquery.range
2648 * @param {string} min - an SWU character
2649 * @param {string} max - an SWU character
2650 * @returns {string} a regular expression that matches a range of SWU characters
2651 * @example
2652 * swuquery.range('񀀁', '񀇡')
2653 *
2654 * return '\uD8C0[\uDC01-\uDDE1]'
2655 * @example
2656 * swuquery.range('𝣔', '𝤸')
2657 *
2658 * return '\uD836[\uDCD4-\uDD38]'
2659 */
2660
2661const range = (min, max) => {
2662 if (min > max) return '';
2663 let pattern = '';
2664 let cnt;
2665 let re = [];
2666 min = pair(min);
2667 max = pair(max);
2668 if (min.length != 2 && max.length != 2) return ''; // HEAD // min[0] with range of min[1] to (DFFF or max[1])
2669
2670 if (min[0] == max[0]) {
2671 if (min[1] == max[1]) {
2672 pattern = '\\u' + min[0] + '\\u' + min[1];
2673 re.push(pattern);
2674 } else {
2675 pattern = '\\u' + min[0] + '[\\u' + min[1] + '-\\u' + max[1] + ']';
2676 re.push(pattern);
2677 }
2678 } else {
2679 if (min[1] == "DFFF") {
2680 pattern = '\\u' + min[0] + '\\uDFFF';
2681 } else {
2682 pattern = '\\u' + min[0] + '[\\u' + min[1] + '-\\uDFFF]';
2683 }
2684
2685 re.push(pattern); // BODY // range of (min[0] +1) to (max[0] -1) with all DC00-DFFF
2686
2687 let diff = parseInt(max[0], 16) - parseInt(min[0], 16);
2688
2689 if (diff == 2) {
2690 pattern = '\\u' + (parseInt(min[0], 16) + 1).toString(16).toUpperCase();
2691 pattern += '[\\uDC00-\\uDFFF]';
2692 re.push(pattern);
2693 }
2694
2695 if (diff > 2) {
2696 pattern = '[';
2697 pattern += '\\u' + (parseInt(min[0], 16) + 1).toString(16).toUpperCase();
2698 pattern += '-\\u' + (parseInt(max[0], 16) - 1).toString(16).toUpperCase();
2699 pattern += '][\\uDC00-\\uDFFF]';
2700 re.push(pattern);
2701 } // TAIL // max[0] with range of DC00 to max[1]
2702
2703
2704 if (max[1] == "DC00") {
2705 pattern = '\\u' + max[0] + '\\uDC00';
2706 } else {
2707 pattern = '\\u' + max[0] + '[\\uDC00-\\u' + max[1] + ']';
2708 }
2709
2710 re.push(pattern);
2711 }
2712
2713 cnt = re.length;
2714
2715 if (cnt == 1) {
2716 pattern = re[0];
2717 } else {
2718 pattern = re.join(')|(');
2719 pattern = '((' + pattern + '))';
2720 }
2721
2722 return decode(pattern);
2723};
2724
2725/**
2726 * Function to transform an SWU symbol with fill and rotation flags to a regular expression
2727 * @function swuquery.symbolRanges
2728 * @param {string} symbolFR - an SWU character with optional flags of 'f' for any fill and 'r' for any rotation
2729 * @returns {string} a regular expression that matches one or more ranges of SWU symbols
2730 * @example <caption>Match an exact symbol</caption>
2731 * swuquery.symbolRanges('񀀁')
2732 *
2733 * return '\uD8C0\uDC01');
2734 * @example <caption>Match a symbol with any fill</caption>
2735 * swuquery.symbolRanges('񀀁f')
2736 *
2737 * return '(\uD8C0\uDC01|\uD8C0\uDC11|\uD8C0\uDC21|\uD8C0\uDC31|\uD8C0\uDC41|\uD8C0\uDC51)'
2738 * @example <caption>Match a symbol with any rotation</caption>
2739 * swuquery.symbolRanges('񀀁r')
2740 *
2741 * return '\uD8C0[\uDC01-\uDC10]'
2742 * @example <caption>Match a symbol with any fill or rotation</caption>
2743 * swuquery.symbolRanges('񀀁fr')
2744 *
2745 * return '\uD8C0[\uDC01-\uDC60]'
2746 */
2747
2748const symbolRanges = symbolFR => {
2749 let match = symbolFR.match(new RegExp(re.symbol));
2750
2751 if (match) {
2752 let sym = match[0].slice(0, 2);
2753 let key = swu2key(sym);
2754 let base = key.slice(0, 4);
2755 let start, end;
2756
2757 if (match[0].slice(-2) == 'fr') {
2758 start = key2swu(base + "00");
2759 end = key2swu(base + "5f");
2760 return range(start, end);
2761 } else if (match[0].slice(-1) == 'r') {
2762 start = key2swu(key.slice(0, 5) + '0');
2763 end = key2swu(key.slice(0, 5) + 'f');
2764 return range(start, end);
2765 } else if (match[0].slice(-1) == 'f') {
2766 let list = [0, 1, 2, 3, 4, 5].map(function (f) {
2767 return key2swu(base + f + key.slice(-1));
2768 });
2769 return "(" + list.join("|") + ")";
2770 } else {
2771 return sym;
2772 }
2773 } else {
2774 return '';
2775 }
2776};
2777
2778const regexRange = symRange => {
2779 from = swu2key(symRange.slice(1, 3));
2780 to = swu2key(symRange.slice(-2));
2781 from = key2swu(from.slice(0, 4) + '00');
2782 to = key2swu(to.slice(0, 4) + '5f');
2783 return range(from, to);
2784}; //needs rewritten, but it works
2785
2786/**
2787 * Function to transform an SWU query string to one or more regular expressions
2788 * @function swuquery.regex
2789 * @param {string} query - an SWU query string
2790 * @returns {string[]} an array of one or more regular expressions
2791 * @example
2792 * swuquery.regex('QA񀀒T')
2793 *
2794 * return [
2795 * '(\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})*'
2796 * ]
2797 */
2798
2799
2800const regex = query => {
2801 query = query.match(new RegExp(`^${re.full}`))[0];
2802
2803 if (!query) {
2804 return '';
2805 }
2806
2807 let matches;
2808 let matchesOr;
2809 let matched;
2810 let orList;
2811 let i;
2812 let j;
2813 let coord;
2814 let segment;
2815 let x;
2816 let y;
2817 let fuzz = 20;
2818 let re_sym = re$2.symbol;
2819 let re_coord = re$2.coord;
2820 let re_signbox = re$2.box;
2821 let re_seq = re$2.sort;
2822 let re_word = re_signbox + re_coord + '(' + re_sym + re_coord + ')*';
2823 let re_sortable = '(' + re_seq + '(' + re_sym + ')+)';
2824 let q_var = '(V[0-9]+)';
2825 let q_style = '(' + re$3.full + ')?';
2826 let q_sortable;
2827
2828 if (query == 'Q') {
2829 return [re$2.sign];
2830 }
2831
2832 if (query == 'Q-') {
2833 return [re$2.sign + "(" + re$3.full + ")?"];
2834 }
2835
2836 if (query == 'QT') {
2837 return [re$2.sortable];
2838 }
2839
2840 if (query == 'QT-') {
2841 return [re$2.sortable + "(" + re$3.full + ")?"];
2842 }
2843
2844 let segments = [];
2845 let sortable = query.indexOf('T') + 1;
2846
2847 if (sortable) {
2848 q_sortable = '(' + re$2.sort;
2849 let qat = query.slice(0, sortable);
2850 query = query.replace(qat, '');
2851
2852 if (qat == 'QT') {
2853 q_sortable += '(' + re_sym + ')+)';
2854 } else {
2855 matches = qat.match(new RegExp('(' + re.list + ')', 'g'));
2856
2857 if (matches) {
2858 for (i = 0; i < matches.length; i += 1) {
2859 orList = [];
2860 matchesOr = matches[i].match(new RegExp('(' + re.symbol + '|' + re.range + ')', 'g'));
2861
2862 if (matchesOr) {
2863 for (j = 0; j < matchesOr.length; j += 1) {
2864 matched = matchesOr[j].match(new RegExp(re.symbol));
2865
2866 if (matched) {
2867 orList.push(symbolRanges(matched[0]));
2868 } else {
2869 orList.push(regexRange(matchesOr[j]));
2870 }
2871 }
2872
2873 if (orList.length == 1) {
2874 q_sortable += orList[0];
2875 } else {
2876 q_sortable += '(' + orList.join('|') + ')';
2877 }
2878 }
2879 }
2880
2881 q_sortable += '(' + re$2.symbol + ')*)';
2882 }
2883 }
2884 } //get the variance
2885
2886
2887 matches = query.match(new RegExp(q_var, 'g'));
2888
2889 if (matches) {
2890 fuzz = matches.toString().slice(1) * 1;
2891 } //this gets all symbols and ranges with or without location
2892
2893
2894 matches = query.match(new RegExp(re.list + re.coord, 'g'));
2895
2896 if (matches) {
2897 for (i = 0; i < matches.length; i += 1) {
2898 orList = [];
2899 matchesOr = matches[i].match(new RegExp('(' + re.symbol + '|' + re.range + ')', 'g'));
2900
2901 if (matchesOr) {
2902 for (j = 0; j < matchesOr.length; j += 1) {
2903 matched = matchesOr[j].match(new RegExp(re.symbol));
2904
2905 if (matched) {
2906 orList.push(symbolRanges(matched[0]));
2907 } else {
2908 orList.push(regexRange(matchesOr[j]));
2909 }
2910 }
2911
2912 if (orList.length == 1) {
2913 segment = orList[0];
2914 } else {
2915 segment = '(' + orList.join('|') + ')';
2916 }
2917 }
2918
2919 coord = matches[i].match(new RegExp(`${re$2.coord}`));
2920
2921 if (coord) {
2922 coord = swu2coord(coord[0]);
2923 x = coord[0];
2924 y = coord[1];
2925 segment += range(num2swu(x - fuzz), num2swu(x + fuzz));
2926 segment += range(num2swu(y - fuzz), num2swu(y + fuzz));
2927 } else {
2928 segment += re$2.coord;
2929 } // add to general swu word
2930
2931
2932 segment = re_word + segment + '(' + re_sym + re_coord + ')*';
2933
2934 if (sortable) {
2935 segment = q_sortable + segment;
2936 } else {
2937 segment = re_sortable + "?" + segment;
2938 }
2939
2940 if (query.indexOf('-') > 0) {
2941 segment += q_style;
2942 }
2943
2944 segments.push(segment);
2945 }
2946 }
2947
2948 if (!segments.length) {
2949 if (query.indexOf('-') > 0) {
2950 segment += q_style;
2951 }
2952
2953 segments.push(q_sortable + re_word);
2954 }
2955
2956 return segments;
2957};
2958
2959/**
2960 * Function that uses a query string to match signs from a string of text.
2961 * @function swuquery.results
2962 * @param {string} query - an SWU query string
2963 * @param {string} text - a string of text containing multiple signs
2964 * @returns {string[]} an array of SWU signs
2965 * @example
2966 * swuquery.results('QA񀀒T','𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭 𝠀񂇢񂇈񆙡񋎥񋎵𝠃𝤛𝤬񂇈𝤀𝣺񂇢𝤄𝣻񋎥𝤄𝤗񋎵𝤃𝣟񆙡𝣱𝣸 𝠀񅨑񀀙񆉁𝠃𝤙𝤞񀀙𝣷𝤀񅨑𝣼𝤀񆉁𝣳𝣮')
2967 *
2968 * return [
2969 * '𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭'
2970 * ]
2971 */
2972
2973const results = (query, text) => {
2974 if (!text) {
2975 return [];
2976 }
2977
2978 let pattern;
2979 let matches;
2980 let parts;
2981 let words;
2982 let res = regex(query);
2983
2984 if (!res) {
2985 return [];
2986 }
2987
2988 let i;
2989
2990 for (i = 0; i < res.length; i += 1) {
2991 pattern = res[i];
2992 matches = text.match(new RegExp(pattern, 'g'));
2993
2994 if (matches) {
2995 text = matches.join(' ');
2996 } else {
2997 text = '';
2998 }
2999 }
3000
3001 if (text) {
3002 parts = text.split(' ');
3003 words = parts.filter(function (element) {
3004 return element in parts ? false : parts[element] = true;
3005 }, {});
3006 } else {
3007 words = [];
3008 }
3009
3010 return words;
3011}; //needs rewritten, but it works
3012
3013/**
3014 * Function that uses an SWU query string to match signs from multiple lines of text.
3015 * @function swuquery.lines
3016 * @param {string} query - an SWU query string
3017 * @param {string} text - multiple lines of text, each starting with an SWU sign
3018 * @returns {string[]} an array of lines of text, each starting with an SWU sign
3019 * @example
3020 * swuquery.lines('QA񀀒T',`𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭 line one
3021 * 𝠀񂇢񂇈񆙡񋎥񋎵𝠃𝤛𝤬񂇈𝤀𝣺񂇢𝤄𝣻񋎥𝤄𝤗񋎵𝤃𝣟񆙡𝣱𝣸 line two
3022 * 𝠀񅨑񀀙񆉁𝠃𝤙𝤞񀀙𝣷𝤀񅨑𝣼𝤀񆉁𝣳𝣮 line three`)
3023 *
3024 * return [
3025 * '𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭 line one'
3026 * ]
3027 */
3028
3029
3030const lines = (query, text) => {
3031 if (!text) {
3032 return [];
3033 }
3034
3035 let pattern;
3036 let matches;
3037 let parts;
3038 let words;
3039 let res = regex(query);
3040
3041 if (!res) {
3042 return [];
3043 }
3044
3045 let i;
3046
3047 for (i = 0; i < res.length; i += 1) {
3048 pattern = res[i];
3049 pattern = '^' + pattern + '.*';
3050 matches = text.match(new RegExp(pattern, 'mg'));
3051
3052 if (matches) {
3053 text = matches.join("\n");
3054 } else {
3055 text = '';
3056 }
3057 }
3058
3059 if (text) {
3060 parts = text.split("\n");
3061 words = parts.filter(function (element) {
3062 return element in parts ? false : parts[element] = true;
3063 }, {});
3064 } else {
3065 words = [];
3066 }
3067
3068 return words;
3069};
3070
3071/** The swuquery module contains functions for handling the SWU query language.
3072 * [Query Language definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-07.html#rfc.section.2.6)
3073 * @module swuquery
3074 */
3075
3076var index = /*#__PURE__*/Object.freeze({
3077 __proto__: null,
3078 re: re,
3079 parse: parse,
3080 compose: compose,
3081 swu2query: swu2query,
3082 range: range,
3083 symbolRanges: symbolRanges,
3084 regex: regex,
3085 results: results,
3086 lines: lines
3087});
3088
3089export { index$4 as convert, index$3 as fsw, index$2 as fswquery, index$5 as style, index$1 as swu, index as swuquery };
3090
3091/* support ongoing development on https://patreon.com/signwriting */