UNPKG

103 kBJavaScriptView Raw
1/**
2* Sutton SignWriting Core Module v1.4.2 (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 * @alias fsw.re
11 * @property {string} symbol - regular expressions for a symbol
12 * @property {string} coord - regular expressions for a coordinate
13 * @property {string} sort - regular expressions for the sorting marker
14 * @property {string} box - regular expression for a signbox marker
15 * @property {string} prefix - regular expression for a sorting marker followed by one or more symbols
16 * @property {string} spatial - regular expression for a symbol followed by a coordinate
17 * @property {string} signbox - regular expression for a signbox marker, max coordinate and zero or more spatial symbols
18 * @property {string} sign - regular expression for an optional prefix followed by a signbox
19 * @property {string} sortable - regular expression for a mandatory prefix followed by a signbox
20 */
21let re$4 = {
22 'symbol': 'S[123][0-9a-f]{2}[0-5][0-9a-f]',
23 'coord': '[0-9]{3}x[0-9]{3}',
24 'sort': 'A',
25 'box': '[BLMR]'
26};
27re$4.prefix = `(?:${re$4.sort}(?:${re$4.symbol})+)`;
28re$4.spatial = `${re$4.symbol}${re$4.coord}`;
29re$4.signbox = `${re$4.box}${re$4.coord}(?:${re$4.spatial})*`;
30re$4.sign = `${re$4.prefix}?${re$4.signbox}`;
31re$4.sortable = `${re$4.prefix}${re$4.signbox}`;
32
33/**
34 * Object of regular expressions for style strings
35 *
36 * @alias style.re
37 * @type {object}
38 * @property {string} colorize - regular expression for colorize section
39 * @property {string} colorhex - regular expression for color hex values with 3 or 6 characters
40 * @property {string} colorname - regular expression for css color name
41 * @property {string} padding - regular expression for padding section
42 * @property {string} zoom - regular expression for zoom section
43 * @property {string} classbase - regular expression for class name definition
44 * @property {string} id - regular expression for id definition
45 * @property {string} colorbase - regular expression for color hex or color name
46 * @property {string} color - regular expression for single color entry
47 * @property {string} colors - regular expression for double color entry
48 * @property {string} background - regular expression for background section
49 * @property {string} detail - regular expression for color details for line and optional fill
50 * @property {string} detailsym - regular expression for color details for individual symbols
51 * @property {string} classes - regular expression for one or more class names
52 * @property {string} full - full regular expression for style string
53 */
54let re$3 = {
55 'colorize': 'C',
56 'colorhex': '(?:[0-9a-fA-F]{3}){1,2}',
57 'colorname': '[a-zA-Z]+',
58 'padding': 'P[0-9]{2}',
59 'zoom': 'Z(?:[0-9]+(?:\\.[0-9]+)?|x)',
60 'classbase': '-?[_a-zA-Z][_a-zA-Z0-9-]{0,100}',
61 'id': '[a-zA-Z][_a-zA-Z0-9-]{0,100}'
62};
63re$3.colorbase = `(?:${re$3.colorhex}|${re$3.colorname})`;
64re$3.color = `_${re$3.colorbase}_`;
65re$3.colors = `_${re$3.colorbase}(?:,${re$3.colorbase})?_`;
66re$3.background = `G${re$3.color}`;
67re$3.detail = `D${re$3.colors}`;
68re$3.detailsym = `D[0-9]{2}${re$3.colors}`;
69re$3.classes = `${re$3.classbase}(?: ${re$3.classbase})*`;
70re$3.full = `-(${re$3.colorize})?(${re$3.padding})?(${re$3.background})?(${re$3.detail})?(${re$3.zoom})?(?:-((?:${re$3.detailsym})*))?(?:-(${re$3.classes})?!(?:(${re$3.id})!)?)?`;
71
72const prefixColor = color => {
73 const regex = new RegExp(`^${re$3.colorhex}$`);
74 return (regex.test(color) ? '#' : '') + color;
75};
76
77const definedProps = obj => Object.fromEntries(Object.entries(obj).filter(([k, v]) => v !== undefined));
78/**
79 * Function to parse style string to object
80 * @function style.parse
81 * @param {string} styleString - a style string
82 * @returns {StyleObject} elements of style string
83 * @example
84 * style.parse('-CP10G_blue_D_red,Cyan_')
85 *
86 * return {
87 * 'colorize': true,
88 * 'padding': 10,
89 * 'background': 'blue',
90 * 'detail': ['red', 'Cyan']
91 * }
92 */
93
94
95const parse$4 = styleString => {
96 const regex = `^${re$3.full}`;
97 const m = (typeof styleString === 'string' ? styleString.match(new RegExp(regex)) : []) || [];
98 return definedProps({
99 'colorize': !m[1] ? undefined : !!m[1],
100 'padding': !m[2] ? undefined : parseInt(m[2].slice(1)),
101 'background': !m[3] ? undefined : prefixColor(m[3].slice(2, -1)),
102 'detail': !m[4] ? undefined : m[4].slice(2, -1).split(',').map(prefixColor),
103 'zoom': !m[5] ? undefined : m[5] === 'Zx' ? 'x' : parseFloat(m[5].slice(1)),
104 'detailsym': !m[6] ? undefined : m[6].match(new RegExp(re$3.detailsym, 'g')).map(val => {
105 const parts = val.split('_');
106 const detail = parts[1].split(',').map(prefixColor);
107 return {
108 'index': parseInt(parts[0].slice(1)),
109 'detail': detail
110 };
111 }),
112 'classes': !m[7] ? undefined : m[7],
113 'id': !m[8] ? undefined : m[8]
114 });
115};
116
117/**
118 * Function to compose style string from object
119 * @function style.compose
120 * @param {StyleObject} styleObject - an object of style options
121 * @returns {string} style string
122 * @example
123 * style.compose({
124 * 'colorize': true,
125 * 'padding': 10,
126 * 'background': 'blue',
127 * 'detail': ['red', 'Cyan'],
128 * 'zoom': 1.1,
129 * 'detailsym': [
130 * {
131 * 'index': 1,
132 * 'detail': ['#ff00ff']
133 * },
134 * {
135 * 'index': 2,
136 * 'detail': ['yellow', 'green']
137 * }
138 * ],
139 * 'classes': 'primary blinking',
140 * 'id': 'cursor'
141 * })
142 *
143 * return '-CP10G_blue_D_red,Cyan_Z1.1-D01_ff00ff_D02_yellow,green_-primary blinking!cursor!'
144 */
145
146const compose$4 = styleObject => {
147 if (typeof styleObject !== 'object' || styleObject === null) return undefined; // three sections
148
149 let style1 = '-';
150 style1 += !styleObject.colorize ? '' : 'C';
151 const padding = parseInt(styleObject.padding);
152 style1 += !padding || padding <= 0 || padding > 99 ? '' : 'P' + (padding > 9 ? padding : '0' + padding);
153 const background = !styleObject.background || !(typeof styleObject.background === 'string') ? undefined : styleObject.background.match(re$3.colorbase)[0];
154 style1 += !background ? '' : 'G_' + background + '_';
155 const detail1 = !styleObject.detail || !styleObject.detail[0] || !(typeof styleObject.detail[0] === 'string') ? undefined : styleObject.detail[0].match(re$3.colorbase)[0];
156 const detail2 = !styleObject.detail || !styleObject.detail[1] || !(typeof styleObject.detail[1] === 'string') ? undefined : styleObject.detail[1].match(re$3.colorbase)[0];
157
158 if (detail1) {
159 style1 += 'D_' + detail1;
160
161 if (detail2) {
162 style1 += ',' + detail2;
163 }
164
165 style1 += '_';
166 }
167
168 const zoom = styleObject.zoom === 'x' ? 'x' : parseFloat(styleObject.zoom);
169 style1 += !zoom || zoom <= 0 ? '' : 'Z' + zoom;
170 let style2 = '';
171 const detailsym = !styleObject.detailsym || !Array.isArray(styleObject.detailsym) ? [] : styleObject.detailsym.map(styleObject => {
172 const index = parseInt(styleObject.index);
173 if (!index || index <= 0 || index > 99) return '';
174 let style = 'D' + (index > 9 ? index : '0' + index);
175 const detail1 = !styleObject.detail || !styleObject.detail[0] ? undefined : styleObject.detail[0].match(re$3.colorbase)[0];
176 const detail2 = !styleObject.detail || !styleObject.detail[1] ? undefined : styleObject.detail[1].match(re$3.colorbase)[0];
177
178 if (detail1) {
179 style += '_' + detail1;
180
181 if (detail2) {
182 style += ',' + detail2;
183 }
184
185 style += '_';
186 }
187
188 return style;
189 });
190 style2 += detailsym.join('');
191 let style3 = '';
192 const classes = !styleObject.classes || !(typeof styleObject.classes === 'string') ? undefined : styleObject.classes.match(re$3.classes)[0];
193 style3 += !classes ? '' : classes;
194 const id = !styleObject.id || !(typeof styleObject.id === 'string') ? undefined : styleObject.id.match(re$3.id)[0];
195 style3 += classes || id ? '!' : '';
196 style3 += !id ? '' : id + '!';
197 return style1 + (style2 || style3 ? '-' + style2 : '') + (style3 ? '-' + style3 : '');
198};
199
200/** The style module contains regular expressions and functions for parsing and composing style strings.
201 * [Style string definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-09.html#name-styling-string)
202 * @module style
203 */
204
205var index$5 = /*#__PURE__*/Object.freeze({
206 __proto__: null,
207 re: re$3,
208 parse: parse$4,
209 compose: compose$4
210});
211
212/**
213 * Object of regular expressions for SWU strings in UTF-16
214 *
215 * @alias swu.re
216 * @property {string} symbol - regular expressions for a symbol
217 * @property {string} coord - regular expressions for a coordinate
218 * @property {string} sort - regular expressions for the sorting marker
219 * @property {string} box - regular expression for a signbox marker
220 * @property {string} prefix - regular expression for a sorting marker followed by one or more symbols
221 * @property {string} spatial - regular expression for a symbol followed by a coordinate
222 * @property {string} signbox - regular expression for a signbox marker, max coordinate and zero or more spatial symbols
223 * @property {string} sign - regular expression for an optional prefix followed by a signbox
224 * @property {string} sortable - regular expression for a mandatory prefix followed by a signbox
225 */
226let re$2 = {
227 'symbol': '(?:(?:\uD8C0[\uDC01-\uDFFF])|(?:[\uD8C1-\uD8FC][\uDC00-\uDFFF])|(?:\uD8FD[\uDC00-\uDC80]))',
228 'coord': '(?:\uD836[\uDC0C-\uDDFF]){2}',
229 'sort': '\uD836\uDC00',
230 'box': '\uD836[\uDC01-\uDC04]'
231};
232re$2.prefix = `(?:${re$2.sort}(?:${re$2.symbol})+)`;
233re$2.spatial = `${re$2.symbol}${re$2.coord}`;
234re$2.signbox = `${re$2.box}${re$2.coord}(?:${re$2.spatial})*`;
235re$2.sign = `${re$2.prefix}?${re$2.signbox}`;
236re$2.sortable = `${re$2.prefix}${re$2.signbox}`;
237
238/** 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.
239 * [Characters set definitions](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-09.html#name-characters)
240 * @module convert
241 */
242/**
243 * Function to convert an SWU structural marker to FSW equivalent
244 * @function convert.swu2mark
245 * @param {string} swuMark - character for SWU structural marker
246 * @returns {string} FSW structural marker
247 * @example
248 * convert.swu2mark('𝠀')
249 *
250 * return 'A'
251 */
252
253const swu2mark = swuMark => {
254 return {
255 '𝠀': 'A',
256 '𝠁': 'B',
257 '𝠂': 'L',
258 '𝠃': 'M',
259 '𝠄': 'R'
260 }[swuMark];
261};
262/**
263 * Function to convert an FSW structural marker to SWU equivalent
264 * @function convert.mark2swu
265 * @param {string} fswMark - character for FSW structural marker
266 * @returns {string} SWU structural marker
267 * @example
268 * convert.mark2swu('A')
269 *
270 * return '𝠀'
271 */
272
273
274const mark2swu = fswMark => {
275 return {
276 'A': '𝠀',
277 'B': '𝠁',
278 'L': '𝠂',
279 'M': '𝠃',
280 'R': '𝠄'
281 }[fswMark];
282};
283/**
284 * Function to convert an SWU number character to an integer
285 * @function convert.swu2num
286 * @param {string} swuNum - SWU number character
287 * @returns {number} Integer value for number
288 * @example
289 * convert.swu2num('𝤆')
290 *
291 * return 500
292 */
293
294
295const swu2num = swuNum => parseInt(swuNum.codePointAt(0)) - 0x1D80C + 250;
296/**
297 * Function to convert a number to an SWU number character
298 * @function convert.num2swu
299 * @param {number} num - Integer value for number
300 * @returns {string} SWU number character
301 * @example
302 * convert.num2swu(500)
303 *
304 * return '𝤆'
305 */
306
307
308const num2swu = num => String.fromCodePoint(0x1D80C + parseInt(num) - 250);
309/**
310 * Function to convert two SWU number characters to an array of x,y integers
311 * @function convert.swu2coord
312 * @param {string} swuCoord - Two SWU number character
313 * @returns {number[]} Array of x,y integers
314 * @example
315 * convert.swu2coord('𝤆𝤆')
316 *
317 * return [500, 500]
318 */
319
320
321const swu2coord = swuCoord => [swu2num(swuCoord.slice(0, 2)), swu2num(swuCoord.slice(2, 4))];
322/**
323 * Function to convert an array of x,y integers to two SWU number characters
324 * @function convert.coord2swu
325 * @param {number[]} coord - Array of x,y integers
326 * @returns {string} Two SWU number character
327 * @example
328 * convert.coord2swu([500, 500])
329 *
330 * return '𝤆𝤆'
331 */
332
333
334const coord2swu = coord => coord.map(num => num2swu(num)).join('');
335/**
336 * Function to convert an FSW coordinate string to an array of x,y integers
337 * @function convert.fsw2coord
338 * @param {string} fswCoord - An FSW coordinate string
339 * @returns {number[]} Array of x,y integers
340 * @example
341 * convert.fsw2coord('500x500')
342 *
343 * return [500, 500]
344 */
345
346
347const fsw2coord = fswCoord => fswCoord.split('x').map(num => parseInt(num));
348/**
349 * Function to convert an array of x,y integers to an FSW coordinate string
350 * @function convert.coord2fsw
351 * @param {number[]} coord - Array of x,y integers
352 * @returns {string} An FSW coordinate string
353 * @example
354 * convert.coord2fsw([500, 500])
355 *
356 * return '500x500'
357 */
358
359
360const coord2fsw = coord => coord.join('x');
361/**
362 * Function to convert an SWU symbol character to a code point on plane 4
363 * @function convert.swu2code
364 * @param {string} swuSym - SWU symbol character
365 * @returns {number} Code point on plane 4
366 * @example
367 * convert.swu2code('񀀁')
368 *
369 * return 0x40001
370 */
371
372
373const swu2code = swuSym => parseInt(swuSym.codePointAt(0));
374/**
375 * Function to convert a code point on plane 4 to an SWU symbol character
376 * @function convert.code2swu
377 * @param {number} code - Code point on plane 4
378 * @returns {string} SWU symbol character
379 * @example
380 * convert.code2swu(0x40001)
381 *
382 * return '񀀁'
383 */
384
385
386const code2swu = code => String.fromCodePoint(code);
387/**
388 * Function to convert an SWU symbol character to a 16-bit ID
389 * @function convert.swu2id
390 * @param {string} swuSym - SWU symbol character
391 * @returns {number} 16-bit ID
392 * @example
393 * convert.swu2id('񀀁')
394 *
395 * return 1
396 */
397
398
399const swu2id = swuSym => swu2code(swuSym) - 0x40000;
400/**
401 * Function to convert a 16-bit ID to an SWU symbol character
402 * @function convert.id2swu
403 * @param {number} id - 16-bit ID
404 * @returns {string} SWU symbol character
405 * @example
406 * convert.id2swu(1)
407 *
408 * return '񀀁'
409 */
410
411
412const id2swu = id => code2swu(id + 0x40000);
413/**
414 * Function to convert an FSW symbol key to a 16-bit ID
415 * @function convert.key2id
416 * @param {string} key - FSW symbol key
417 * @returns {number} 16-bit ID
418 * @example
419 * convert.key2id('S10000')
420 *
421 * return 1
422 */
423
424
425const key2id = key => 1 + (parseInt(key.slice(1, 4), 16) - 256) * 96 + parseInt(key.slice(4, 5), 16) * 16 + parseInt(key.slice(5, 6), 16);
426/**
427 * Function to convert a 16-bit ID to an FSW symbol key
428 * @function convert.id2key
429 * @param {number} id - 16-bit ID
430 * @returns {string} FSW symbol key
431 * @example
432 * convert.id2key(1)
433 *
434 * return 'S10000'
435 */
436
437
438const id2key = id => {
439 const symcode = id - 1;
440 const base = parseInt(symcode / 96);
441 const fill = parseInt((symcode - base * 96) / 16);
442 const rotation = parseInt(symcode - base * 96 - fill * 16);
443 return 'S' + (base + 0x100).toString(16) + fill.toString(16) + rotation.toString(16);
444};
445/**
446 * Function to convert an SWU symbol character to an FSW symbol key
447 * @function convert.swu2key
448 * @param {string} swuSym - SWU symbol character
449 * @returns {string} FSW symbol key
450 * @example
451 * convert.swu2key('񀀁')
452 *
453 * return 'S10000'
454 */
455
456
457const swu2key = swuSym => {
458 const symcode = swu2code(swuSym) - 0x40001;
459 const base = parseInt(symcode / 96);
460 const fill = parseInt((symcode - base * 96) / 16);
461 const rotation = parseInt(symcode - base * 96 - fill * 16);
462 return 'S' + (base + 0x100).toString(16) + fill.toString(16) + rotation.toString(16);
463};
464/**
465 * Function to convert an FSW symbol key to an SWU symbol character
466 * @function convert.key2swu
467 * @param {string} key - FSW symbol key
468 * @returns {string} SWU symbol character
469 * @example
470 * convert.key2swu('S10000')
471 *
472 * return '񀀁'
473 */
474
475
476const 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));
477/**
478 * Function to convert SWU text to FSW text
479 * @function convert.swu2fsw
480 * @param {string} swuText - SWU text
481 * @returns {string} FSW text
482 * @example
483 * convert.swu2fsw('𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭')
484 *
485 * return 'AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475'
486 */
487
488
489const swu2fsw = swuText => {
490 if (!swuText) return '';
491 let fsw = swuText.replace(/𝠀/g, "A").replace(/𝠁/g, "B").replace(/𝠂/g, "L").replace(/𝠃/g, "M").replace(/𝠄/g, "R");
492 const syms = fsw.match(new RegExp(re$2.symbol, 'g'));
493
494 if (syms) {
495 syms.forEach(function (sym) {
496 fsw = fsw.replace(sym, swu2key(sym));
497 });
498 }
499
500 const coords = fsw.match(new RegExp(re$2.coord, 'g'));
501
502 if (coords) {
503 coords.forEach(function (coord) {
504 fsw = fsw.replace(coord, swu2coord(coord).join('x'));
505 });
506 }
507
508 return fsw;
509};
510/**
511 * Function to convert FSW text to SWU text
512 * @function convert.fsw2swu
513 * @param {string} fswText - FSW text
514 * @returns {string} SWU text
515 * @example
516 * convert.fsw2swu('AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475')
517 *
518 * return '𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭'
519 */
520
521
522const fsw2swu = fswText => {
523 if (!fswText) return '';
524 const prefixes = fswText.match(new RegExp(re$4.prefix, 'g'));
525
526 if (prefixes) {
527 prefixes.forEach(function (prefix) {
528 fswText = fswText.replace(prefix, '𝠀' + prefix.slice(1).match(/.{6}/g).map(key => key2swu(key)).join(''));
529 });
530 }
531
532 const boxes = fswText.match(new RegExp(re$4.box + re$4.coord, 'g'));
533
534 if (boxes) {
535 boxes.forEach(function (boxes) {
536 fswText = fswText.replace(boxes, mark2swu(boxes.slice(0, 1)) + coord2swu(fsw2coord(boxes.slice(1, 8))));
537 });
538 }
539
540 const spatials = fswText.match(new RegExp(re$4.spatial, 'g'));
541
542 if (spatials) {
543 spatials.forEach(function (spatial) {
544 fswText = fswText.replace(spatial, key2swu(spatial.slice(0, 6)) + coord2swu(fsw2coord(spatial.slice(6, 13))));
545 });
546 }
547
548 return fswText;
549};
550
551var index$4 = /*#__PURE__*/Object.freeze({
552 __proto__: null,
553 swu2mark: swu2mark,
554 mark2swu: mark2swu,
555 swu2num: swu2num,
556 num2swu: num2swu,
557 swu2coord: swu2coord,
558 coord2swu: coord2swu,
559 fsw2coord: fsw2coord,
560 coord2fsw: coord2fsw,
561 swu2code: swu2code,
562 code2swu: code2swu,
563 swu2id: swu2id,
564 id2swu: id2swu,
565 key2id: key2id,
566 id2key: id2key,
567 swu2key: swu2key,
568 key2swu: key2swu,
569 swu2fsw: swu2fsw,
570 fsw2swu: fsw2swu
571});
572
573const parse$3 = {
574 /**
575 * Function to parse an fsw symbol with optional coordinate and style string
576 * @function fsw.parse.symbol
577 * @param {string} fswSym - an fsw symbol
578 * @returns {object} elements of fsw symbol
579 * @example
580 * fsw.parse.symbol('S10000500x500-C')
581 *
582 * return {
583 * 'symbol': 'S10000',
584 * 'coord': [500, 500],
585 * 'style': '-C'
586 * }
587 */
588 symbol: fswSym => {
589 const regex = `^(${re$4.symbol})(${re$4.coord})?(${re$3.full})?`;
590 const symbol = typeof fswSym === 'string' ? fswSym.match(new RegExp(regex)) : undefined;
591 return {
592 'symbol': symbol ? symbol[1] : undefined,
593 'coord': symbol && symbol[2] ? fsw2coord(symbol[2]) : undefined,
594 'style': symbol ? symbol[3] : undefined
595 };
596 },
597
598 /**
599 * Function to parse an fsw sign with style string
600 * @function fsw.parse.sign
601 * @param {string} fswSign - an fsw sign
602 * @returns {object} elements of fsw sign
603 * @example
604 * fsw.parse.sign('AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475-C')
605 *
606 * return {
607 * sequence: ['S10011', 'S10019', 'S2e704', 'S2e748'],
608 * box: 'M',
609 * max: [525, 535],
610 * spatials: [
611 * {
612 * symbol: 'S2e748',
613 * coord: [483, 510]
614 * },
615 * {
616 * symbol: 'S10011',
617 * coord: [501, 466]
618 * },
619 * {
620 * symbol: 'S2e704',
621 * coord: [510, 500]
622 * },
623 * {
624 * symbol: 'S10019',
625 * coord: [476, 475]
626 * }
627 * ],
628 * style: '-C'
629 * }
630 */
631 sign: fswSign => {
632 const regex = `^(${re$4.prefix})?(${re$4.signbox})(${re$3.full})?`;
633 const sign = typeof fswSign === 'string' ? fswSign.match(new RegExp(regex)) : undefined;
634
635 if (sign) {
636 return {
637 'sequence': sign[1] ? sign[1].slice(1).match(/.{6}/g) : undefined,
638 'box': sign[2][0],
639 'max': fsw2coord(sign[2].slice(1, 8)),
640 'spatials': sign[2].length < 9 ? undefined : sign[2].slice(8).match(/(.{13})/g).map(m => {
641 return {
642 symbol: m.slice(0, 6),
643 coord: [parseInt(m.slice(6, 9)), parseInt(m.slice(10, 13))]
644 };
645 }),
646 'style': sign[3]
647 };
648 } else {
649 return {};
650 }
651 },
652
653 /**
654 * Function to parse an fsw text
655 * @function fsw.parse.text
656 * @param {string} fswText - an fsw text
657 * @returns {array} fsw signs and punctuations
658 * @example
659 * fsw.parse.text('AS14c20S27106M518x529S14c20481x471S27106503x489 AS18701S1870aS2e734S20500M518x533S1870a489x515S18701482x490S20500508x496S2e734500x468 S38800464x496')
660 *
661 * return [
662 * 'AS14c20S27106M518x529S14c20481x471S27106503x489',
663 * 'AS18701S1870aS2e734S20500M518x533S1870a489x515S18701482x490S20500508x496S2e734500x468',
664 * 'S38800464x496'
665 * ]
666 */
667 text: fswText => {
668 if (typeof fswText !== 'string') return [];
669 const regex = `(${re$4.sign}(${re$3.full})?|${re$4.spatial}(${re$3.full})?)`;
670 const matches = fswText.match(new RegExp(regex, 'g'));
671 return matches ? [...matches] : [];
672 }
673};
674
675const compose$3 = {
676 /**
677 * Function to compose an fsw symbol with optional coordinate and style string
678 * @function fsw.compose.symbol
679 * @param {object} fswSymObject - an fsw symbol object
680 * @param {string} fswSymObject.symbol - an fsw symbol key
681 * @param {number[]} fswSymObject.coord - top-left coordinate of symbol
682 * @param {string} fswSymObject.style - a style string for custom appearance
683 * @returns {string} an fsw symbol string
684 * @example
685 * fsw.compose.symbol({
686 * 'symbol': 'S10000',
687 * 'coord': [480, 480],
688 * 'style': '-C'
689 * })
690 *
691 * return 'S10000480x480-C'
692 */
693 symbol: fswSymObject => {
694 if (typeof fswSymObject.symbol === 'string') {
695 const symbol = (fswSymObject.symbol.match(re$4.symbol) || [''])[0];
696
697 if (symbol) {
698 const x = (fswSymObject.coord && fswSymObject.coord[0] || '').toString();
699 const y = (fswSymObject.coord && fswSymObject.coord[1] || '').toString();
700 const coord = ((x + 'x' + y).match(re$4.coord) || [''])[0] || '';
701 const styleStr = typeof fswSymObject.style === 'string' && (fswSymObject.style.match(re$3.full) || [''])[0] || '';
702 return symbol + coord + styleStr;
703 }
704 }
705
706 return undefined;
707 },
708
709 /**
710 * Function to compose an fsw sign with style string
711 * @function fsw.compose.sign
712 * @param {object} fswSymObject - an fsw sign object
713 * @param {string[]} fswSignObject.sequence - an ordered array of symbols
714 * @param {string} fswSignObject.box - a choice BLMR: horizontal Box, Left, Middle, and Right lane
715 * @param {number[]} fswSignObject.max - max bottom-right coordinate of the signbox space
716 * @param {{symbol:string,coord:number[]}[]} fswSignObject.spatials - array of symbols with top-left coordinate placement
717 * @param {string} fswSignObject.style - a style string for custom appearance
718 * @returns {string} an fsw sign string
719 * @example
720 * fsw.compose.sign({
721 * sequence: ['S10011', 'S10019', 'S2e704', 'S2e748'],
722 * box: 'M',
723 * max: [525, 535],
724 * spatials: [
725 * {
726 * symbol: 'S2e748',
727 * coord: [483, 510]
728 * },
729 * {
730 * symbol: 'S10011',
731 * coord: [501, 466]
732 * },
733 * {
734 * symbol: 'S2e704',
735 * coord: [510, 500]
736 * },
737 * {
738 * symbol: 'S10019',
739 * coord: [476, 475]
740 * }
741 * ],
742 * style: '-C'
743 * })
744 *
745 * return 'AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475-C'
746 */
747 sign: fswSignObject => {
748 let box = typeof fswSignObject.box !== 'string' ? 'M' : (fswSignObject.box + 'M').match(re$4.box);
749 const x = (fswSignObject.max && fswSignObject.max[0] || '').toString();
750 const y = (fswSignObject.max && fswSignObject.max[1] || '').toString();
751 const max = ((x + 'x' + y).match(re$4.coord) || [''])[0] || '';
752 if (!max) return undefined;
753 let prefix = '';
754
755 if (fswSignObject.sequence && Array.isArray(fswSignObject.sequence)) {
756 prefix = fswSignObject.sequence.map(key => (key.match(re$4.symbol) || [''])[0]).join('');
757 prefix = prefix ? 'A' + prefix : '';
758 }
759
760 let signbox = '';
761
762 if (fswSignObject.spatials && Array.isArray(fswSignObject.spatials)) {
763 signbox = fswSignObject.spatials.map(spatial => {
764 if (typeof spatial.symbol === 'string') {
765 const symbol = (spatial.symbol.match(re$4.symbol) || [''])[0];
766
767 if (symbol) {
768 const x = (spatial.coord && spatial.coord[0] || '').toString();
769 const y = (spatial.coord && spatial.coord[1] || '').toString();
770 const coord = ((x + 'x' + y).match(re$4.coord) || [''])[0] || '';
771
772 if (coord) {
773 return symbol + coord;
774 }
775 }
776 }
777
778 return '';
779 }).join('');
780 }
781
782 const styleStr = typeof fswSignObject.style === 'string' && (fswSignObject.style.match(re$3.full) || [''])[0] || '';
783 return prefix + box + max + signbox + styleStr;
784 }
785};
786
787/**
788 * Function to gather sizing information about an fsw sign or symbol
789 * @function fsw.info
790 * @param {string} fsw - an fsw sign or symbol
791 * @returns {object} information about the fsw string
792 * @example
793 * fsw.info('AS14c20S27106L518x529S14c20481x471S27106503x489-P10Z2')
794 *
795 * return {
796 * minX: 481,
797 * minY: 471,
798 * width: 37,
799 * height: 58,
800 * zoom: 2,
801 * padding: 10,
802 * segment: 'sign',
803 * lane: -1
804 * }
805 */
806
807const info$1 = fsw => {
808 let lanes = {
809 "B": 0,
810 "L": -1,
811 "M": 0,
812 "R": 1
813 };
814 let parsed = parse$3.sign(fsw);
815 let width, height, segment, x1, x2, y1, y2, lane;
816
817 if (parsed.spatials) {
818 x1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[0]));
819 x2 = parsed.max[0];
820 width = x2 - x1;
821 y1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[1]));
822 y2 = parsed.max[1];
823 height = y2 - y1;
824 segment = 'sign';
825 lane = parsed.box;
826 } else {
827 parsed = parse$3.symbol(fsw);
828 lane = "M";
829
830 if (parsed.coord) {
831 x1 = parsed.coord[0];
832 width = (500 - x1) * 2;
833 y1 = parsed.coord[1];
834 height = (500 - y1) * 2;
835 segment = 'symbol';
836 } else {
837 x1 = 490;
838 width = 20;
839 y1 = 490;
840 height = 20;
841 segment = 'none';
842 }
843 }
844
845 let style = parse$4(parsed.style);
846 let zoom = style.zoom || 1;
847 let padding = style.padding || 0;
848 return {
849 minX: x1,
850 minY: y1,
851 width: width,
852 height: height,
853 segment: segment,
854 lane: lanes[lane],
855 padding: padding,
856 zoom: zoom
857 };
858};
859
860const columnDefaults$1 = {
861 'height': 500,
862 'width': 150,
863 'offset': 50,
864 'pad': 20,
865 'margin': 5,
866 'dynamic': false,
867 'background': undefined,
868 'punctuation': {
869 'spacing': true,
870 'pad': 30,
871 'pull': true
872 },
873 'style': {
874 'detail': ['black', 'white'],
875 'zoom': 1
876 }
877};
878/**
879 * Function to an object of column options with default values
880 *
881 * @function fsw.columnDefaultsMerge
882 * @param {ColumnOptions} options - object of column options
883 * @returns {ColumnOptions} object of column options merged with column defaults
884 * @example
885 * fsw.columnDefaultsMerge({height: 500,width:150})
886 *
887 * return {
888 * "height": 500,
889 * "width": 150,
890 * "offset": 50,
891 * "pad": 20,
892 * "margin": 5,
893 * "dynamic": false,
894 * "punctuation": {
895 * "spacing": true,
896 * "pad": 30,
897 * "pull": true
898 * },
899 * "style": {
900 * "detail": [
901 * "black",
902 * "white"
903 * ],
904 * "zoom": 1
905 * }
906 * }
907 */
908
909const columnDefaultsMerge$1 = options => {
910 if (typeof options !== 'object') options = {};
911 return { ...columnDefaults$1,
912 ...options,
913 punctuation: { ...columnDefaults$1.punctuation,
914 ...options.punctuation
915 },
916 style: { ...columnDefaults$1.style,
917 ...options.style
918 }
919 };
920};
921/**
922 * Function to transform an FSW text to an array of columns
923 *
924 * @function fsw.columns
925 * @param {string} fswText - FSW text of signs and punctuation
926 * @param {ColumnOptions} options - object of column options
927 * @returns {{options:ColumnOptions,widths:number[],columns:ColumnData}} object of column options, widths array, and column data
928 * @example
929 * fsw.columns('AS14c20S27106M518x529S14c20481x471S27106503x489 AS18701S1870aS2e734S20500M518x533S1870a489x515S18701482x490S20500508x496S2e734500x468 S38800464x496', {height: 500,width:150})
930 *
931 * return {
932 * "options": {
933 * "height": 500,
934 * "width": 150,
935 * "offset": 50,
936 * "pad": 20,
937 * "margin": 5,
938 * "dynamic": false,
939 * "punctuation": {
940 * "spacing": true,
941 * "pad": 30,
942 * "pull": true
943 * },
944 * "style": {
945 * "detail": [
946 * "black",
947 * "white"
948 * ],
949 * "zoom": 1
950 * }
951 * },
952 * "widths": [
953 * 150
954 * ],
955 * "columns": [
956 * [
957 * {
958 * "x": 56,
959 * "y": 20,
960 * "minX": 481,
961 * "minY": 471,
962 * "width": 37,
963 * "height": 58,
964 * "lane": 0,
965 * "padding": 0,
966 * "segment": "sign",
967 * "text": "AS14c20S27106M518x529S14c20481x471S27106503x489",
968 * "zoom": 1
969 * },
970 * {
971 * "x": 57,
972 * "y": 118,
973 * "minX": 482,
974 * "minY": 468,
975 * "width": 36,
976 * "height": 65,
977 * "lane": 0,
978 * "padding": 0,
979 * "segment": "sign",
980 * "text": "AS18701S1870aS2e734S20500M518x533S1870a489x515S18701482x490S20500508x496S2e734500x468",
981 * "zoom": 1
982 * },
983 * {
984 * "x": 39,
985 * "y": 203,
986 * "minX": 464,
987 * "minY": 496,
988 * "width": 72,
989 * "height": 8,
990 * "lane": 0,
991 * "padding": 0,
992 * "segment": "symbol",
993 * "text": "S38800464x496",
994 * "zoom": 1
995 * }
996 * ]
997 * ]
998 * }
999 */
1000
1001
1002const columns$1 = (fswText, options) => {
1003 if (typeof fswText !== 'string') return {};
1004 const values = columnDefaultsMerge$1(options);
1005 let input = parse$3.text(fswText);
1006 let cursor = 0;
1007 let cols = [];
1008 let col = [];
1009 let plus = 0;
1010 let center = parseInt(values.width / 2);
1011 let maxHeight = values.height - values.margin;
1012 let pullable = true;
1013 let finalize = false;
1014
1015 for (let val of input) {
1016 let informed = info$1(val);
1017 cursor += plus;
1018
1019 if (values.punctuation.spacing) {
1020 cursor += informed.segment == 'sign' ? values.pad : 0;
1021 } else {
1022 cursor += values.pad;
1023 }
1024
1025 finalize = cursor + informed.height > maxHeight;
1026
1027 if (finalize && informed.segment == 'symbol' && values.punctuation.pull && pullable) {
1028 finalize = false;
1029 pullable = false;
1030 }
1031
1032 if (col.length == 0) {
1033 finalize = false;
1034 }
1035
1036 if (finalize) {
1037 cursor = values.pad;
1038 cols.push(col);
1039 col = [];
1040 pullable = true;
1041 }
1042
1043 col.push(Object.assign(informed, {
1044 x: center + values.offset * informed.lane - (500 - informed.minX) * informed.zoom * values.style.zoom,
1045 y: cursor,
1046 text: val
1047 }));
1048 cursor += informed.height * informed.zoom * values.style.zoom;
1049
1050 if (values.punctuation.spacing) {
1051 plus = informed.segment == 'sign' ? values.pad : values.punctuation.pad;
1052 } else {
1053 plus = values.pad;
1054 }
1055 }
1056
1057 if (col.length) {
1058 cols.push(col);
1059 } // over height issue when pulling punctuation
1060
1061
1062 if (values.punctuation.pull) {
1063 for (let col of cols) {
1064 let last = col[col.length - 1];
1065 let diff = last.y + last.height - (values.height - values.margin);
1066
1067 if (diff > 0) {
1068 let adj = parseInt(diff / col.length) + 1;
1069
1070 for (let i in col) {
1071 col[i].y -= adj * i + adj;
1072 }
1073 }
1074 }
1075 } // contract, expand, adjust
1076
1077
1078 let widths = [];
1079
1080 for (let col of cols) {
1081 let min = [center - values.offset - values.pad];
1082 let max = [center + values.offset + values.pad];
1083
1084 for (let item of col) {
1085 min.push(item.x - values.pad);
1086 max.push(item.x + item.width + values.pad);
1087 }
1088
1089 min = Math.min(...min);
1090 max = Math.max(...max);
1091 let width = values.width;
1092 let adj = 0;
1093
1094 if (!values.dynamic) {
1095 adj = center - parseInt((min + max) / 2);
1096 } else {
1097 width = max - min;
1098 adj = -min;
1099 }
1100
1101 for (let item of col) {
1102 item.x += adj;
1103 }
1104
1105 widths.push(width);
1106 }
1107
1108 return {
1109 'options': values,
1110 'widths': widths,
1111 'columns': cols
1112 };
1113};
1114
1115/**
1116 * Array of numbers for kinds of symbols: writing, location, and punctuation.
1117 * @alias fsw.kind
1118 * @type {array}
1119 */
1120
1121const kind$1 = [0x100, 0x37f, 0x387];
1122/**
1123 * Array of numbers for categories of symbols: hand, movement, dynamics, head, trunk & limb, location, and punctuation.
1124 * @alias fsw.category
1125 * @type {array}
1126 */
1127
1128const category$1 = [0x100, 0x205, 0x2f7, 0x2ff, 0x36d, 0x37f, 0x387];
1129/**
1130 * Array of numbers for the 30 symbol groups.
1131 * @alias fsw.group
1132 * @type {array}
1133 */
1134
1135const 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];
1136/**
1137 * Object of symbol ranges with starting and ending numbers.
1138 *
1139 * { all, writing, hand, movement, dynamic, head, hcenter, vcenter, trunk, limb, location, punctuation }
1140 * @alias fsw.ranges
1141 * @type {object}
1142 */
1143
1144const ranges$1 = {
1145 'all': [0x100, 0x38b],
1146 'writing': [0x100, 0x37e],
1147 'hand': [0x100, 0x204],
1148 'movement': [0x205, 0x2f6],
1149 'dynamic': [0x2f7, 0x2fe],
1150 'head': [0x2ff, 0x36c],
1151 'hcenter': [0x2ff, 0x36c],
1152 'vcenter': [0x2ff, 0x375],
1153 'trunk': [0x36d, 0x375],
1154 'limb': [0x376, 0x37e],
1155 'location': [0x37f, 0x386],
1156 'punctuation': [0x387, 0x38b]
1157};
1158/**
1159 * Function to test if symbol is of a certain type.
1160 * @function fsw.isType
1161 * @param {string} key - an FSW symbol key
1162 * @param {string} type - the name of a symbol range
1163 * @returns {boolean} is symbol of specified type
1164 * @example
1165 * fsw.isType('S10000', 'hand')
1166 *
1167 * return true
1168 */
1169
1170const isType$1 = (key, type) => {
1171 const parsed = parse$3.symbol(key);
1172
1173 if (parsed.symbol) {
1174 const dec = parseInt(parsed.symbol.slice(1, 4), 16);
1175 const range = ranges$1[type];
1176
1177 if (range) {
1178 return range[0] <= dec && range[1] >= dec;
1179 }
1180 }
1181
1182 return false;
1183};
1184
1185/**
1186 * Array of colors associated with the seven symbol categories.
1187 * @alias fsw.colors
1188 * @type {array}
1189 */
1190
1191const colors$1 = ['#0000CC', '#CC0000', '#FF0099', '#006600', '#000000', '#884411', '#FF9900'];
1192/**
1193 * Function that returns the standardized color for a symbol.
1194 * @function fsw.colorize
1195 * @param {string} key - an FSW symbol key
1196 * @returns {string} name of standardized color for symbol
1197 * @example
1198 * fsw.colorize('S10000')
1199 *
1200 * return '#0000CC'
1201 */
1202
1203const colorize$1 = key => {
1204 const parsed = parse$3.symbol(key);
1205 let color = '#000000';
1206
1207 if (parsed.symbol) {
1208 const dec = parseInt(parsed.symbol.slice(1, 4), 16);
1209 const index = category$1.findIndex(val => val > dec);
1210 color = colors$1[index < 0 ? 6 : index - 1];
1211 }
1212
1213 return color;
1214};
1215
1216/** The fsw module contains functions for handling Formal SignWriitng in ASCII (FSW) characters.
1217 * [FSW characters definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-09.html#name-formal-signwriting-in-ascii)
1218 * @module fsw
1219 */
1220
1221var index$3 = /*#__PURE__*/Object.freeze({
1222 __proto__: null,
1223 re: re$4,
1224 parse: parse$3,
1225 compose: compose$3,
1226 info: info$1,
1227 columnDefaults: columnDefaults$1,
1228 columnDefaultsMerge: columnDefaultsMerge$1,
1229 columns: columns$1,
1230 kind: kind$1,
1231 category: category$1,
1232 group: group$1,
1233 ranges: ranges$1,
1234 isType: isType$1,
1235 colors: colors$1,
1236 colorize: colorize$1
1237});
1238
1239/**
1240 * Object of regular expressions for FSW query strings
1241 *
1242 * { base, coord, var, symbol, range, item, list, prefix, signbox, full }
1243 * @alias fswquery.re
1244 * @type {object}
1245 */
1246let re$1 = {
1247 'base': '[123][0-9a-f]{2}',
1248 'coord': '(?:[0-9]{3}x[0-9]{3})?',
1249 'var': 'V[0-9]+'
1250};
1251re$1.symbol = `S${re$1.base}[0-5u][0-9a-fu]`;
1252re$1.range = `R${re$1.base}t${re$1.base}`;
1253re$1.item = `(?:${re$1.symbol}|${re$1.range})`;
1254re$1.list = `${re$1.item}(?:o${re$1.item})*`;
1255re$1.prefix = `(?:A(?:${re$1.list})+)?T`;
1256re$1.signbox = `(?:${re$1.list}${re$1.coord})*`;
1257re$1.full = `Q(${re$1.prefix})?(${re$1.signbox})?(${re$1.var})?(-?)`;
1258
1259const parsePrefix$1 = text => {
1260 return {
1261 required: true,
1262 parts: text == 'T' ? undefined : text.match(new RegExp(`${re$1.list}`, 'g')).map(part => {
1263 if (part.includes('o')) {
1264 return ['or'].concat(part.match(new RegExp(`(${re$1.item})`, 'g')).map(part => part[0] == 'S' ? part : part.slice(1).split('t')));
1265 } else {
1266 return part[0] == 'S' ? part : part.slice(1).split('t');
1267 }
1268 })
1269 };
1270};
1271
1272const parseSignbox$1 = text => {
1273 return text.match(new RegExp(`(${re$1.list}${re$1.coord})`, 'g')).map(part => {
1274 let coord, front;
1275
1276 if (part.includes('x')) {
1277 coord = fsw2coord(part.slice(-7));
1278 front = part.slice(0, -7);
1279 } else {
1280 front = part;
1281 }
1282
1283 if (front.includes('o')) {
1284 return {
1285 or: front.split('o').map(part => {
1286 if (part.includes('S')) {
1287 return part;
1288 } else {
1289 return part.slice(1).split('t');
1290 }
1291 }),
1292 coord,
1293 coord
1294 };
1295 } else if (front.includes('S')) {
1296 return {
1297 symbol: front,
1298 coord: coord
1299 };
1300 } else {
1301 return {
1302 range: front.slice(1).split('t'),
1303 coord: coord
1304 };
1305 }
1306 });
1307};
1308/**
1309 * Function to parse FSW query string to object
1310 * @function fswquery.parse
1311 * @param {string} fswQueryString - an FSW query string
1312 * @returns {object} elements of an FSW query string
1313 * @example
1314 * fswquery.parse('QAS10000S10500oS20500oR2fft304TS100uuR205t206oS207uu510x510V5-')
1315 *
1316 * return {
1317 * "query": true,
1318 * "prefix": {
1319 * "required": true,
1320 * "parts": [
1321 * "S10000",
1322 * [
1323 * "or",
1324 * "S10500",
1325 * "S20500",
1326 * [
1327 * "2ff",
1328 * "304"
1329 * ]
1330 * ]
1331 * ]
1332 * },
1333 * "signbox": [
1334 * {
1335 * "symbol": "S100uu"
1336 * },
1337 * {
1338 * "or": [
1339 * [
1340 * "205",
1341 * "206"
1342 * ],
1343 * "S207uu"
1344 * ],
1345 * "coord": [
1346 * 510,
1347 * 510
1348 * ]
1349 * }
1350 * ],
1351 * "variance": 5,
1352 * "style": true
1353 * }
1354 */
1355
1356
1357const parse$2 = fswQueryString => {
1358 const query = typeof fswQueryString === 'string' ? fswQueryString.match(new RegExp(`^${re$1.full}`)) : undefined;
1359 return {
1360 'query': query ? true : undefined,
1361 'prefix': query && query[1] ? parsePrefix$1(query[1]) : undefined,
1362 'signbox': query && query[2] ? parseSignbox$1(query[2]) : undefined,
1363 'variance': query && query[3] ? parseInt(query[3].slice(1)) : undefined,
1364 'style': query && query[4] ? true : undefined
1365 };
1366};
1367
1368/**
1369 * Function to compose FSW query string from object
1370 * @function fswquery.compose
1371 * @param {object} fswQueryObject - an object of style options
1372 * @param {boolean} fswQueryObject.query - required true for FSW query object
1373 * @param {object} fswQueryObject.prefix - an object for prefix elements
1374 * @param {boolean} fswQueryObject.prefix.required - true if sorting prefix is required
1375 * @param {(string|string[]|(string|string[])[])[]} fswQueryObject.prefix.parts - array of symbol strings, range arrays, and OR arrays of strings and range arrays
1376 * @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
1377 * @param {number} fswQueryObject.variance - amount that x or y coordinates can vary and find a match, defaults to 20
1378 * @param {boolean} fswQueryObject.style - boolean value for including style string in matches
1379 * @returns {string} FSW query string
1380 * @example
1381 * fswquery.compose({
1382 * query: true,
1383 * prefix: {
1384 * required: true,
1385 * parts: [
1386 * 'S10000',
1387 * ['100', '204'],
1388 * 'S20500'
1389 * ]
1390 * },
1391 * signbox: [
1392 * { symbol: 'S20000' },
1393 * {
1394 * range: ['100', '105'],
1395 * coord: [500, 500]
1396 * }
1397 * ],
1398 * variance: 5,
1399 * style: true
1400 * })
1401 *
1402 * return 'QAS10000R100t204S20500TS20000R100t105500x500V5-'
1403 */
1404
1405const compose$2 = fswQueryObject => {
1406 if (!fswQueryObject || !fswQueryObject.query) {
1407 return undefined;
1408 }
1409
1410 let query = 'Q';
1411
1412 if (fswQueryObject.prefix && fswQueryObject.prefix.required) {
1413 if (Array.isArray(fswQueryObject.prefix.parts)) {
1414 query += 'A';
1415 query += fswQueryObject.prefix.parts.map(part => {
1416 if (typeof part === 'string') {
1417 return part;
1418 } else {
1419 if (Array.isArray(part) && part.length == 2) {
1420 return `R${part[0]}t${part[1]}`;
1421 } else if (Array.isArray(part) && part.length > 2 && part[0] == 'or') {
1422 part.shift();
1423 return part.map(part => {
1424 if (typeof part === 'string') {
1425 return part;
1426 } else {
1427 if (Array.isArray(part) && part.length == 2) {
1428 return `R${part[0]}t${part[1]}`;
1429 }
1430 }
1431 }).join('o');
1432 }
1433 }
1434 }).join('');
1435 }
1436
1437 query += 'T';
1438 }
1439
1440 if (Array.isArray(fswQueryObject.signbox)) {
1441 query += fswQueryObject.signbox.map(part => {
1442 let out;
1443
1444 if (part.or) {
1445 out = part.or.map(item => {
1446 if (typeof item === 'string') {
1447 return item;
1448 } else {
1449 if (Array.isArray(item) && item.length == 2) {
1450 return `R${item[0]}t${item[1]}`;
1451 }
1452 }
1453 }).join('o');
1454 } else if (part.symbol) {
1455 out = part.symbol;
1456 } else {
1457 if (part.range && Array.isArray(part.range) && part.range.length == 2) {
1458 out = `R${part.range[0]}t${part.range[1]}`;
1459 }
1460 }
1461
1462 return out + (Array.isArray(part.coord) && part.coord.length == 2 ? part.coord.join('x') : '');
1463 }).join('');
1464 }
1465
1466 query += fswQueryObject.style ? '-' : '';
1467 query = query.match(new RegExp(`^${re$1.full}`))[0];
1468 return query;
1469};
1470
1471/**
1472 * Function to convert an FSW sign to a query string
1473 *
1474 * For the flags parameter, use one or more of the following.
1475 * - A: exact symbol in temporal prefix
1476 * - a: general symbol in temporal prefix
1477 * - S: exact symbol in spatial signbox
1478 * - s: general symbol in spatial signbox
1479 * - L: spatial signbox symbol at location
1480 * @function fswquery.fsw2query
1481 * @param {string} fswSign - FSW sign
1482 * @param {string} flags - flags for query string creation
1483 * @returns {string} FSW query string
1484 * @example
1485 * fswquery.fsw2query('AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475', 'ASL')
1486 *
1487 * return 'QAS10011S10019S2e704S2e748TS2e748483x510S10011501x466S2e704510x500S10019476x475'
1488 */
1489
1490const fsw2query = (fswSign, flags) => {
1491 let query = '';
1492 const parsed = parse$3.sign(fswSign);
1493
1494 if (parsed.box) {
1495 const A_flag = flags.indexOf('A') > -1;
1496 const a_flag = flags.indexOf('a') > -1;
1497 const S_flag = flags.indexOf('S') > -1;
1498 const s_flag = flags.indexOf('s') > -1;
1499 const L_flag = flags.indexOf('L') > -1;
1500
1501 if (A_flag || a_flag || S_flag || s_flag) {
1502 if ((A_flag || a_flag) && parsed.sequence) {
1503 query += 'A';
1504 query += parsed.sequence.map(sym => sym.slice(0, 4) + (a_flag ? 'uu' : sym.slice(4, 6))).join('');
1505 query += 'T';
1506 }
1507
1508 if ((S_flag || s_flag) && parsed.spatials) {
1509 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('');
1510 }
1511 }
1512
1513 return query ? "Q" + query : undefined;
1514 } else {
1515 return undefined;
1516 }
1517};
1518
1519//needs rewritten, but it works
1520
1521/**
1522 * Function to transform a range to a regular expression
1523 * @function fswquery.range
1524 * @param {(number|string)} min - either a decimal number or hexidecimal string
1525 * @param {(number|string)} max - either a decimal number or hexidecimal string
1526 * @param {boolean?} hex - if true, the regular expression will match a hexidecimal range
1527 * @returns {string} a regular expression that matches a range
1528 * @example
1529 * fswquery.range(500,750)
1530 *
1531 * return '(([56][0-9][0-9])|(7[0-4][0-9])|(750))'
1532 * @example
1533 * fswquery.range('100','10e',true)
1534 *
1535 * return '10[0-9a-e]'
1536 */
1537const range$1 = (min, max, hex) => {
1538 let pattern;
1539 let re;
1540 let diff;
1541 let tmax;
1542 let cnt;
1543 let minV;
1544 let maxV;
1545
1546 if (!hex) {
1547 hex = '';
1548 }
1549
1550 min = ("000" + min).slice(-3);
1551 max = '' + max;
1552 pattern = '';
1553
1554 if (min === max) {
1555 return min;
1556 } //ending pattern will be series of connected OR ranges
1557
1558
1559 re = []; //first pattern+ 10's don't match and the min 1's are not zero
1560 //odd number to 9
1561
1562 if (!(min[0] == max[0] && min[1] == max[1])) {
1563 if (min[2] != '0') {
1564 pattern = min[0] + min[1];
1565
1566 if (hex) {
1567 //switch for dex
1568 switch (min[2]) {
1569 case "f":
1570 pattern += 'f';
1571 break;
1572
1573 case "e":
1574 pattern += '[ef]';
1575 break;
1576
1577 case "d":
1578 case "c":
1579 case "b":
1580 case "a":
1581 pattern += '[' + min[2] + '-f]';
1582 break;
1583
1584 default:
1585 switch (min[2]) {
1586 case "9":
1587 pattern += '[9a-f]';
1588 break;
1589
1590 case "8":
1591 pattern += '[89a-f]';
1592 break;
1593
1594 default:
1595 pattern += '[' + min[2] + '-9a-f]';
1596 break;
1597 }
1598
1599 break;
1600 }
1601
1602 diff = 15 - parseInt(min[2], 16) + 1;
1603 min = '' + (parseInt(min, 16) + diff).toString(16);
1604 re.push(pattern);
1605 } else {
1606 //switch for dex
1607 switch (min[2]) {
1608 case "9":
1609 pattern += '9';
1610 break;
1611
1612 case "8":
1613 pattern += '[89]';
1614 break;
1615
1616 default:
1617 pattern += '[' + min[2] + '-9]';
1618 break;
1619 }
1620
1621 diff = 9 - min[2] + 1;
1622 min = '' + (min * 1 + diff);
1623 re.push(pattern);
1624 }
1625 }
1626 }
1627
1628 pattern = ''; //if hundreds are different, get odd to 99 or ff
1629
1630 if (min[0] != max[0]) {
1631 if (min[1] != '0') {
1632 if (hex) {
1633 //scrape to ff
1634 pattern = min[0];
1635
1636 switch (min[1]) {
1637 case "f":
1638 pattern += 'f';
1639 break;
1640
1641 case "e":
1642 pattern += '[ef]';
1643 break;
1644
1645 case "d":
1646 case "c":
1647 case "b":
1648 case "a":
1649 pattern += '[' + min[1] + '-f]';
1650 break;
1651
1652 case "9":
1653 pattern += '[9a-f]';
1654 break;
1655
1656 case "8":
1657 pattern += '[89a-f]';
1658 break;
1659
1660 default:
1661 pattern += '[' + min[1] + '-9a-f]';
1662 break;
1663 }
1664
1665 pattern += '[0-9a-f]';
1666 diff = 15 - parseInt(min[1], 16) + 1;
1667 min = '' + (parseInt(min, 16) + diff * 16).toString(16);
1668 re.push(pattern);
1669 } else {
1670 //scrape to 99
1671 pattern = min[0];
1672 diff = 9 - min[1] + 1;
1673
1674 switch (min[1]) {
1675 case "9":
1676 pattern += '9';
1677 break;
1678
1679 case "8":
1680 pattern += '[89]';
1681 break;
1682
1683 default:
1684 pattern += '[' + min[1] + '-9]';
1685 break;
1686 }
1687
1688 pattern += '[0-9]';
1689 diff = 9 - min[1] + 1;
1690 min = '' + (min * 1 + diff * 10);
1691 re.push(pattern);
1692 }
1693 }
1694 }
1695
1696 pattern = ''; //if hundreds are different, get to same
1697
1698 if (min[0] != max[0]) {
1699 if (hex) {
1700 diff = parseInt(max[0], 16) - parseInt(min[0], 16);
1701 tmax = (parseInt(min[0], 16) + diff - 1).toString(16);
1702
1703 switch (diff) {
1704 case 1:
1705 pattern = min[0];
1706 break;
1707
1708 case 2:
1709 pattern = '[' + min[0] + tmax + ']';
1710 break;
1711
1712 default:
1713 if (parseInt(min[0], 16) > 9) {
1714 minV = 'h';
1715 } else {
1716 minV = 'd';
1717 }
1718
1719 if (parseInt(tmax, 16) > 9) {
1720 maxV = 'h';
1721 } else {
1722 maxV = 'd';
1723 }
1724
1725 switch (minV + maxV) {
1726 case "dd":
1727 pattern += '[' + min[0] + '-' + tmax + ']';
1728 break;
1729
1730 case "dh":
1731 diff = 9 - min[0]; //firs get up to 9
1732
1733 switch (diff) {
1734 case 0:
1735 pattern += '[9';
1736 break;
1737
1738 case 1:
1739 pattern += '[89';
1740 break;
1741
1742 default:
1743 pattern += '[' + min[0] + '-9';
1744 break;
1745 }
1746
1747 switch (tmax[0]) {
1748 case 'a':
1749 pattern += 'a]';
1750 break;
1751
1752 case 'b':
1753 pattern += 'ab]';
1754 break;
1755
1756 default:
1757 pattern += 'a-' + tmax + ']';
1758 break;
1759 }
1760
1761 break;
1762
1763 case "hh":
1764 pattern += '[' + min[0] + '-' + tmax + ']';
1765 break;
1766 }
1767
1768 }
1769
1770 pattern += '[0-9a-f][0-9a-f]';
1771 diff = parseInt(max[0], 16) - parseInt(min[0], 16);
1772 min = '' + (parseInt(min, 16) + diff * 256).toString(16);
1773 re.push(pattern);
1774 } else {
1775 diff = max[0] - min[0];
1776 tmax = min[0] * 1 + diff - 1;
1777
1778 switch (diff) {
1779 case 1:
1780 pattern = min[0];
1781 break;
1782
1783 case 2:
1784 pattern = '[' + min[0] + tmax + ']';
1785 break;
1786
1787 default:
1788 pattern = '[' + min[0] + '-' + tmax + ']';
1789 break;
1790 }
1791
1792 pattern += '[0-9][0-9]';
1793 min = '' + (min * 1 + diff * 100);
1794 re.push(pattern);
1795 }
1796 }
1797
1798 pattern = ''; //if tens are different, get to same
1799
1800 if (min[1] != max[1]) {
1801 if (hex) {
1802 diff = parseInt(max[1], 16) - parseInt(min[1], 16);
1803 tmax = (parseInt(min[1], 16) + diff - 1).toString(16);
1804 pattern = min[0];
1805
1806 switch (diff) {
1807 case 1:
1808 pattern += min[1];
1809 break;
1810
1811 case 2:
1812 pattern += '[' + min[1] + tmax + ']';
1813 break;
1814
1815 default:
1816 if (parseInt(min[1], 16) > 9) {
1817 minV = 'h';
1818 } else {
1819 minV = 'd';
1820 }
1821
1822 if (parseInt(tmax, 16) > 9) {
1823 maxV = 'h';
1824 } else {
1825 maxV = 'd';
1826 }
1827
1828 switch (minV + maxV) {
1829 case "dd":
1830 pattern += '[' + min[1];
1831
1832 if (diff > 1) {
1833 pattern += '-';
1834 }
1835
1836 pattern += tmax + ']';
1837 break;
1838
1839 case "dh":
1840 diff = 9 - min[1]; //firs get up to 9
1841
1842 switch (diff) {
1843 case 0:
1844 pattern += '[9';
1845 break;
1846
1847 case 1:
1848 pattern += '[89';
1849 break;
1850
1851 default:
1852 pattern += '[' + min[1] + '-9';
1853 break;
1854 }
1855
1856 switch (max[1]) {
1857 case 'a':
1858 pattern += ']';
1859 break;
1860
1861 case 'b':
1862 pattern += 'a]';
1863 break;
1864
1865 default:
1866 pattern += 'a-' + (parseInt(max[1], 16) - 1).toString(16) + ']';
1867 break;
1868 }
1869
1870 break;
1871
1872 case "hh":
1873 pattern += '[' + min[1];
1874
1875 if (diff > 1) {
1876 pattern += '-';
1877 }
1878
1879 pattern += (parseInt(max[1], 16) - 1).toString(16) + ']';
1880 break;
1881 }
1882
1883 break;
1884 }
1885
1886 pattern += '[0-9a-f]';
1887 diff = parseInt(max[1], 16) - parseInt(min[1], 16);
1888 min = '' + (parseInt(min, 16) + diff * 16).toString(16);
1889 re.push(pattern);
1890 } else {
1891 diff = max[1] - min[1];
1892 tmax = min[1] * 1 + diff - 1;
1893 pattern = min[0];
1894
1895 switch (diff) {
1896 case 1:
1897 pattern += min[1];
1898 break;
1899
1900 case 2:
1901 pattern += '[' + min[1] + tmax + ']';
1902 break;
1903
1904 default:
1905 pattern += '[' + min[1] + '-' + tmax + ']';
1906 break;
1907 }
1908
1909 pattern += '[0-9]';
1910 min = '' + (min * 1 + diff * 10);
1911 re.push(pattern);
1912 }
1913 }
1914
1915 pattern = ''; //if digits are different, get to same
1916
1917 if (min[2] != max[2]) {
1918 if (hex) {
1919 pattern = min[0] + min[1];
1920 diff = parseInt(max[2], 16) - parseInt(min[2], 16);
1921
1922 if (parseInt(min[2], 16) > 9) {
1923 minV = 'h';
1924 } else {
1925 minV = 'd';
1926 }
1927
1928 if (parseInt(max[2], 16) > 9) {
1929 maxV = 'h';
1930 } else {
1931 maxV = 'd';
1932 }
1933
1934 switch (minV + maxV) {
1935 case "dd":
1936 pattern += '[' + min[2];
1937
1938 if (diff > 1) {
1939 pattern += '-';
1940 }
1941
1942 pattern += max[2] + ']';
1943 break;
1944
1945 case "dh":
1946 diff = 9 - min[2]; //firs get up to 9
1947
1948 switch (diff) {
1949 case 0:
1950 pattern += '[9';
1951 break;
1952
1953 case 1:
1954 pattern += '[89';
1955 break;
1956
1957 default:
1958 pattern += '[' + min[2] + '-9';
1959 break;
1960 }
1961
1962 switch (max[2]) {
1963 case 'a':
1964 pattern += 'a]';
1965 break;
1966
1967 case 'b':
1968 pattern += 'ab]';
1969 break;
1970
1971 default:
1972 pattern += 'a-' + max[2] + ']';
1973 break;
1974 }
1975
1976 break;
1977
1978 case "hh":
1979 pattern += '[' + min[2];
1980
1981 if (diff > 1) {
1982 pattern += '-';
1983 }
1984
1985 pattern += max[2] + ']';
1986 break;
1987 }
1988
1989 diff = parseInt(max[2], 16) - parseInt(min[2], 16);
1990 min = '' + (parseInt(min, 16) + diff).toString(16);
1991 re.push(pattern);
1992 } else {
1993 diff = max[2] - min[2];
1994 pattern = min[0] + min[1];
1995
1996 switch (diff) {
1997 case 0:
1998 pattern += min[2];
1999 break;
2000
2001 case 1:
2002 pattern += '[' + min[2] + max[2] + ']';
2003 break;
2004
2005 default:
2006 pattern += '[' + min[2] + '-' + max[2] + ']';
2007 break;
2008 }
2009
2010 min = '' + (min * 1 + diff);
2011 re.push(pattern);
2012 }
2013 }
2014
2015 pattern = ''; //last place is whole hundred
2016
2017 if (min[2] == '0' && max[2] == '0') {
2018 pattern = max;
2019 re.push(pattern);
2020 }
2021
2022 pattern = '';
2023 cnt = re.length;
2024
2025 if (cnt == 1) {
2026 pattern = re[0];
2027 } else {
2028 pattern = re.join(')|(');
2029 pattern = '((' + pattern + '))';
2030 }
2031
2032 return pattern;
2033};
2034
2035const regexSymbol = sym => {
2036 let segment = sym.slice(0, 4);
2037 let fill = sym.slice(4, 5);
2038
2039 if (fill == 'u') {
2040 segment += '[0-5]';
2041 } else {
2042 segment += fill;
2043 }
2044
2045 let rotate = sym.slice(5, 6);
2046
2047 if (rotate == 'u') {
2048 segment += '[0-9a-f]';
2049 } else {
2050 segment += rotate;
2051 }
2052
2053 return segment;
2054};
2055
2056const regexRange$1 = symRange => {
2057 let from = symRange.slice(1, 4);
2058 let to = symRange.slice(5, 8);
2059 return 'S' + range$1(from, to, 'hex') + '[0-5][0-9a-f]';
2060}; //needs rewritten, but it works
2061
2062/**
2063 * Function to transform an FSW query string to one or more regular expressions
2064 * @function fswquery.regex
2065 * @param {string} query - an FSW query string
2066 * @returns {string[]} an array of one or more regular expressions
2067 * @example
2068 * fswquery.regex('QS100uuS20500480x520')
2069 *
2070 * return [
2071 * '(?: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})*',
2072 * '(?: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})*'
2073 * ]
2074 */
2075
2076
2077const regex$1 = query => {
2078 query = query.match(new RegExp(`^${re$1.full}`))[0];
2079
2080 if (!query) {
2081 return '';
2082 }
2083
2084 var matches;
2085 var matchesOr;
2086 var matched;
2087 var orList;
2088 var i;
2089 var j;
2090 var segment;
2091 var coord;
2092 var x;
2093 var y;
2094 var fuzz = 20;
2095 var q_style = '(' + re$3.full + ')?';
2096 var q_sortable;
2097
2098 if (query == 'Q') {
2099 return [re$4.prefix + "?" + re$4.signbox];
2100 }
2101
2102 if (query == 'Q-') {
2103 return [re$4.prefix + "?" + re$4.signbox + q_style];
2104 }
2105
2106 if (query == 'QT') {
2107 return [re$4.prefix + re$4.signbox];
2108 }
2109
2110 if (query == 'QT-') {
2111 return [re$4.prefix + re$4.signbox + q_style];
2112 }
2113
2114 var segments = [];
2115 var sortable = query.indexOf('T') + 1;
2116
2117 if (sortable) {
2118 q_sortable = '(A';
2119 var qat = query.slice(0, sortable);
2120 query = query.replace(qat, '');
2121
2122 if (qat == 'QT') {
2123 q_sortable += '(' + re$4.symbol + ')+)';
2124 } else {
2125 matches = qat.match(new RegExp('(' + re$1.list + ')', 'g'));
2126
2127 if (matches) {
2128 for (i = 0; i < matches.length; i += 1) {
2129 orList = [];
2130 matchesOr = matches[i].match(new RegExp('(' + re$1.symbol + '|' + re$1.range + ')', 'g'));
2131
2132 if (matchesOr) {
2133 for (j = 0; j < matchesOr.length; j += 1) {
2134 matched = matchesOr[j].match(new RegExp(re$1.symbol));
2135
2136 if (matched) {
2137 orList.push(regexSymbol(matched[0]));
2138 } else {
2139 orList.push(regexRange$1(matchesOr[j]));
2140 }
2141 }
2142
2143 if (orList.length == 1) {
2144 q_sortable += orList[0];
2145 } else {
2146 q_sortable += '(' + orList.join('|') + ')';
2147 }
2148 }
2149 }
2150
2151 q_sortable += '(' + re$4.symbol + ')*)';
2152 }
2153 }
2154 } //get the variance
2155
2156
2157 matches = query.match(new RegExp(re$1.var, 'g'));
2158
2159 if (matches) {
2160 fuzz = matches.toString().slice(1) * 1;
2161 } //this gets all symbols and ranges with or without location
2162
2163
2164 matches = query.match(new RegExp(re$1.list + re$1.coord, 'g'));
2165
2166 if (matches) {
2167 for (i = 0; i < matches.length; i += 1) {
2168 orList = [];
2169 matchesOr = matches[i].match(new RegExp('(' + re$1.symbol + '|' + re$1.range + ')', 'g'));
2170
2171 if (matchesOr) {
2172 for (j = 0; j < matchesOr.length; j += 1) {
2173 matched = matchesOr[j].match(new RegExp(re$1.symbol));
2174
2175 if (matched) {
2176 orList.push(regexSymbol(matched[0]));
2177 } else {
2178 orList.push(regexRange$1(matchesOr[j]));
2179 }
2180 }
2181
2182 if (orList.length == 1) {
2183 segment = orList[0];
2184 } else {
2185 segment = '(' + orList.join('|') + ')';
2186 }
2187 }
2188
2189 if (matches[i].includes('x')) {
2190 coord = fsw2coord(matches[i].slice(-7));
2191 x = coord[0];
2192 y = coord[1];
2193 segment += range$1(x - fuzz, x + fuzz);
2194 segment += 'x';
2195 segment += range$1(y - fuzz, y + fuzz);
2196 } else {
2197 segment += re$4.coord;
2198 } // add to general fsw word
2199
2200
2201 segment = re$4.signbox + segment + '(' + re$4.symbol + re$4.coord + ')*';
2202
2203 if (sortable) {
2204 segment = q_sortable + segment;
2205 } else {
2206 segment = re$4.prefix + "?" + segment;
2207 }
2208
2209 if (query.indexOf('-') > 0) {
2210 segment += q_style;
2211 }
2212
2213 segments.push(segment);
2214 }
2215 }
2216
2217 if (!segments.length) {
2218 if (query.indexOf('-') > 0) {
2219 segment += q_style;
2220 }
2221
2222 segments.push(q_sortable + re$4.signbox);
2223 }
2224
2225 return segments;
2226};
2227
2228/**
2229 * Function that uses a query string to match signs from a string of text.
2230 * @function fswquery.results
2231 * @param {string} query - an FSW query string
2232 * @param {string} text - a string of text containing multiple signs
2233 * @returns {string[]} an array of FSW signs
2234 * @example
2235 * fswquery.results('QAS10011T','AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475 AS15a21S15a07S21100S2df04S2df14M521x538S15a07494x488S15a21498x489S2df04498x517S2df14497x461S21100479x486 AS1f010S10018S20600M519x524S10018485x494S1f010490x494S20600481x476')
2236 *
2237 * return [
2238 * 'AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475'
2239 * ]
2240 */
2241
2242const results$1 = (query, text) => {
2243 if (!text) {
2244 return [];
2245 }
2246
2247 let pattern;
2248 let matches;
2249 let parts;
2250 let words;
2251 let re = regex$1(query);
2252
2253 if (!re) {
2254 return [];
2255 }
2256
2257 let i;
2258
2259 for (i = 0; i < re.length; i += 1) {
2260 pattern = re[i];
2261 matches = text.match(new RegExp(pattern, 'g'));
2262
2263 if (matches) {
2264 text = matches.join(' ');
2265 } else {
2266 text = '';
2267 }
2268 }
2269
2270 if (text) {
2271 parts = text.split(' ');
2272 words = parts.filter(function (element) {
2273 return element in parts ? false : parts[element] = true;
2274 }, {});
2275 } else {
2276 words = [];
2277 }
2278
2279 return words;
2280}; //needs rewritten, but it works
2281
2282/**
2283 * Function that uses an FSW query string to match signs from multiple lines of text.
2284 * @function fswquery.lines
2285 * @param {string} query - an FSW query string
2286 * @param {string} text - multiple lines of text, each starting with an FSW sign
2287 * @returns {string[]} an array of lines of text, each starting with an FSW sign
2288 * @example
2289 * fswquery.lines('QAS10011T',`AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475 line one
2290 * AS15a21S15a07S21100S2df04S2df14M521x538S15a07494x488S15a21498x489S2df04498x517S2df14497x461S21100479x486 line two
2291 * AS1f010S10018S20600M519x524S10018485x494S1f010490x494S20600481x476 line three`)
2292 *
2293 * return [
2294 * 'AS10011S10019S2e704S2e748M525x535S2e748483x510S10011501x466S2e704510x500S10019476x475 line one'
2295 * ]
2296 */
2297
2298
2299const lines$1 = (query, text) => {
2300 if (!text) {
2301 return [];
2302 }
2303
2304 let pattern;
2305 let matches;
2306 let parts;
2307 let words;
2308 let re = regex$1(query);
2309
2310 if (!re) {
2311 return [];
2312 }
2313
2314 let i;
2315
2316 for (i = 0; i < re.length; i += 1) {
2317 pattern = re[i];
2318 pattern = '^' + pattern + '.*';
2319 matches = text.match(new RegExp(pattern, 'mg'));
2320
2321 if (matches) {
2322 text = matches.join("\n");
2323 } else {
2324 text = '';
2325 }
2326 }
2327
2328 if (text) {
2329 parts = text.split("\n");
2330 words = parts.filter(function (element) {
2331 return element in parts ? false : parts[element] = true;
2332 }, {});
2333 } else {
2334 words = [];
2335 }
2336
2337 return words;
2338};
2339
2340/** The fswquery module contains functions for handling the FSW query language.
2341 * [Query Language definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-09.html#name-query-language)
2342 * @module fswquery
2343 */
2344
2345var index$2 = /*#__PURE__*/Object.freeze({
2346 __proto__: null,
2347 re: re$1,
2348 parse: parse$2,
2349 compose: compose$2,
2350 fsw2query: fsw2query,
2351 range: range$1,
2352 regex: regex$1,
2353 results: results$1,
2354 lines: lines$1
2355});
2356
2357const parse$1 = {
2358 /**
2359 * Function to parse an swu symbol with optional coordinate and style string
2360 * @function swu.parse.symbol
2361 * @param {string} swuSym - an swu symbol
2362 * @returns {object} elements of swu symbol
2363 * @example
2364 * swu.parse.symbol('񀀁𝤆𝤆-C')
2365 *
2366 * return {
2367 * 'symbol': '񀀁',
2368 * 'coord': [500, 500],
2369 * 'style': '-C'
2370 * }
2371 */
2372 symbol: swuSym => {
2373 const regex = `^(${re$2.symbol})(${re$2.coord})?(${re$3.full})?`;
2374 const symbol = typeof swuSym === 'string' ? swuSym.match(new RegExp(regex)) : undefined;
2375 return {
2376 'symbol': symbol ? symbol[1] : undefined,
2377 'coord': symbol && symbol[2] ? swu2coord(symbol[2]) : undefined,
2378 'style': symbol ? symbol[3] : undefined
2379 };
2380 },
2381
2382 /**
2383 * Function to parse an swu sign with style string
2384 * @function swu.parse.sign
2385 * @param {string} swuSign - an swu sign
2386 * @returns {object} elements of swu sign
2387 * @example
2388 * swu.parse.sign('𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭-C')
2389 *
2390 * return {
2391 * sequence: ['񀀒','񀀚','񋚥','񋛩'],
2392 * box: '𝠃',
2393 * max: [525, 535],
2394 * spatials: [
2395 * {
2396 * symbol: '񋛩',
2397 * coord: [483, 510]
2398 * },
2399 * {
2400 * symbol: '񀀒',
2401 * coord: [501, 466]
2402 * },
2403 * {
2404 * symbol: '񋚥',
2405 * coord: [510, 500]
2406 * },
2407 * {
2408 * symbol: '񀀚',
2409 * coord: [476, 475]
2410 * }
2411 * ],
2412 * style: '-C'
2413 * }
2414 */
2415 sign: swuSign => {
2416 const regex = `^(${re$2.prefix})?(${re$2.signbox})(${re$3.full})?`;
2417 const sign = typeof swuSign === 'string' ? swuSign.match(new RegExp(regex)) : undefined;
2418
2419 if (sign) {
2420 return {
2421 'sequence': sign[1] ? sign[1].slice(2).match(/.{2}/g) : undefined,
2422 'box': sign[2].slice(0, 2),
2423 'max': swu2coord(sign[2].slice(2, 6)),
2424 'spatials': sign[2].length < 7 ? undefined : sign[2].slice(6).match(/(.{6})/g).map(m => {
2425 return {
2426 symbol: m.slice(0, 2),
2427 coord: swu2coord(m.slice(2))
2428 };
2429 }),
2430 'style': sign[3]
2431 };
2432 } else {
2433 return {};
2434 }
2435 },
2436
2437 /**
2438 * Function to parse an swu text
2439 * @function swu.parse.text
2440 * @param {string} swuText - an swu text
2441 * @returns {array} swu signs and punctuations
2442 * @example
2443 * swu.parse.text('𝠀񁲡񈩧𝠃𝤘𝤣񁲡𝣳𝣩񈩧𝤉𝣻 𝠀񃊢񃊫񋛕񆇡𝠃𝤘𝤧񃊫𝣻𝤕񃊢𝣴𝣼񆇡𝤎𝤂񋛕𝤆𝣦 񏌁𝣢𝤂')
2444 *
2445 * return [
2446 * '𝠀񁲡񈩧𝠃𝤘𝤣񁲡𝣳𝣩񈩧𝤉𝣻',
2447 * '𝠀񃊢񃊫񋛕񆇡𝠃𝤘𝤧񃊫𝣻𝤕񃊢𝣴𝣼񆇡𝤎𝤂񋛕𝤆𝣦',
2448 * '񏌁𝣢𝤂'
2449 * ]
2450 */
2451 text: swuText => {
2452 if (typeof swuText !== 'string') return [];
2453 const regex = `(${re$2.sign}(${re$3.full})?|${re$2.spatial}(${re$3.full})?)`;
2454 const matches = swuText.match(new RegExp(regex, 'g'));
2455 return matches ? [...matches] : [];
2456 }
2457};
2458/**
2459 * Function to encode SWU characters using the UTF-16 escape format.
2460 * @function swu.encode
2461 * @param {string} swu - SWU characters
2462 * @returns {string} UTF-16 escape format
2463 * @example
2464 * swu.encode('񀀁𝤆𝤆')
2465 *
2466 * return '\\uD8C0\\uDC01\\uD836\\uDD06\\uD836\\uDD06'
2467 */
2468
2469const encode = text => text.replace(/[\u007F-\uFFFF]/g, function (chr) {
2470 return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4).toUpperCase();
2471});
2472/**
2473 * Function to decode UTF-16 escape format to SWU characters.
2474 * @function swu.decode
2475 * @param {string} encoded - UTF-16 escape format
2476 * @returns {string} SWU characters
2477 * @example
2478 * swu.decode('\\uD8C0\\uDC01\\uD836\\uDD06\\uD836\\uDD06')
2479 *
2480 * return '񀀁𝤆𝤆'
2481 */
2482
2483
2484const decode = encoded => encoded.replace(/\\u([0-9A-F]{4})/g, function (match, chr) {
2485 return String.fromCharCode(parseInt(chr, 16));
2486});
2487/**
2488 * Function to decompose an SWU character into UTF-16 surrogate pairs.
2489 * @function swu.pair
2490 * @param {string} swuChar - an SWU character
2491 * @returns {string[]} an array of UTF-16 surrogate pairs
2492 * @example
2493 * swu.pair('񀀁')
2494 *
2495 * return ['D8C0', 'DC01']
2496 */
2497
2498
2499const pair = swuChar => [swuChar.charCodeAt(0).toString(16).toUpperCase(), swuChar.charCodeAt(1).toString(16).toUpperCase()];
2500
2501const compose$1 = {
2502 /**
2503 * Function to compose an swu symbol with optional coordinate and style string
2504 * @function swu.compose.symbol
2505 * @param {object} swuSymObject - an swu symbol object
2506 * @param {string} swuSymObject.symbol - an swu symbol key
2507 * @param {number[]} swuSymObject.coord - top-left coordinate of symbol with 500,500 center
2508 * @param {string} swuSymObject.style - a style string for custom appearance
2509 * @returns {string} an swu symbol string
2510 * @example
2511 * swu.compose.symbol({
2512 * 'symbol': '񀀁',
2513 * 'coord': [500, 500],
2514 * 'style': '-C'
2515 * })
2516 *
2517 * return '񀀁𝤆𝤆-C'
2518 */
2519 symbol: swuSymObject => {
2520 if (typeof swuSymObject !== 'object' || swuSymObject === null) return undefined;
2521
2522 if (typeof swuSymObject.symbol === 'string') {
2523 const symbol = (swuSymObject.symbol.match(re$2.symbol) || [''])[0];
2524
2525 if (symbol) {
2526 const x = swuSymObject.coord && swuSymObject.coord[0] || '';
2527 const y = swuSymObject.coord && swuSymObject.coord[1] || '';
2528 const coord = x && y ? coord2swu([x, y]) : '';
2529 const styleStr = typeof swuSymObject.style === 'string' && (swuSymObject.style.match(re$3.full) || [''])[0] || '';
2530 return symbol + coord + styleStr;
2531 }
2532 }
2533
2534 return undefined;
2535 },
2536
2537 /**
2538 * Function to compose an swu sign with style string
2539 * @function swu.compose.sign
2540 * @param {object} swuSignObject - an swu sign object
2541 * @param {string[]} swuSignObject.sequence - an ordered array of symbols
2542 * @param {string} swuSignObject.box - a choice of signbox marker: horizontal Box, Left, Middle, and Right lane
2543 * @param {number[]} swuSignObject.max - max bottom-right coordinate of the signbox space
2544 * @param {{symbol:string,coord:number[]}[]} swuSignObject.spatials - array of symbols with top-left coordinate placement
2545 * @param {string} swuSignObject.style - a style string for custom appearance
2546 * @returns {string} an swu sign string
2547 * @example
2548 * swu.compose.sign({
2549 * sequence: ['񀀒','񀀚','񋚥','񋛩'],
2550 * box: '𝠃',
2551 * max: [525, 535],
2552 * spatials: [
2553 * {
2554 * symbol: '񋛩',
2555 * coord: [483, 510]
2556 * },
2557 * {
2558 * symbol: '񀀒',
2559 * coord: [501, 466]
2560 * },
2561 * {
2562 * symbol: '񋚥',
2563 * coord: [510, 500]
2564 * },
2565 * {
2566 * symbol: '񀀚',
2567 * coord: [476, 475]
2568 * }
2569 * ],
2570 * style: '-C'
2571 * })
2572 *
2573 * return '𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭-C'
2574 */
2575 sign: swuSignObject => {
2576 if (typeof swuSignObject !== 'object' || swuSignObject === null) return undefined;
2577 let box = typeof swuSignObject.box !== 'string' ? '𝠃' : (swuSignObject.box + '𝠃').match(re$2.box);
2578 const x = swuSignObject.max && swuSignObject.max[0] || '';
2579 const y = swuSignObject.max && swuSignObject.max[1] || '';
2580 const max = x && y ? coord2swu([x, y]) : undefined;
2581 if (!max) return undefined;
2582 let prefix = '';
2583
2584 if (swuSignObject.sequence && Array.isArray(swuSignObject.sequence)) {
2585 prefix = swuSignObject.sequence.map(key => (key.match(re$2.symbol) || [''])[0]).join('');
2586 prefix = prefix ? '𝠀' + prefix : '';
2587 }
2588
2589 let signbox = '';
2590
2591 if (swuSignObject.spatials && Array.isArray(swuSignObject.spatials)) {
2592 signbox = swuSignObject.spatials.map(spatial => {
2593 if (typeof spatial.symbol === 'string') {
2594 const symbol = (spatial.symbol.match(re$2.symbol) || [''])[0];
2595
2596 if (symbol) {
2597 const x = spatial.coord && spatial.coord[0] || '';
2598 const y = spatial.coord && spatial.coord[1] || '';
2599 const coord = x && y ? coord2swu([x, y]) : '';
2600
2601 if (coord) {
2602 return symbol + coord;
2603 }
2604 }
2605 }
2606
2607 return '';
2608 }).join('');
2609 }
2610
2611 const styleStr = typeof swuSignObject.style === 'string' && (swuSignObject.style.match(re$3.full) || [''])[0] || '';
2612 return prefix + box + max + signbox + styleStr;
2613 }
2614};
2615
2616/**
2617 * Function to gather sizing information about an swu sign or symbol
2618 * @function swu.info
2619 * @param {string} swu - an swu sign or symbol
2620 * @returns {object} information about the swu string
2621 * @example
2622 * swu.info('𝠀񁲡񈩧𝠂𝤘𝤣񁲡𝣳𝣩񈩧𝤉𝣻-P10Z2')
2623 *
2624 * return {
2625 * minX: 481,
2626 * minY: 471,
2627 * width: 37,
2628 * height: 58,
2629 * segment: 'sign',
2630 * lane: -1
2631 * padding: 10,
2632 * zoom: 2
2633 * }
2634 */
2635
2636const info = swu => {
2637 let lanes = {
2638 '𝠁': 0,
2639 '𝠂': -1,
2640 '𝠃': 0,
2641 '𝠄': 1
2642 };
2643 let parsed = parse$1.sign(swu);
2644 let width, height, segment, x1, x2, y1, y2, lane;
2645
2646 if (parsed.spatials) {
2647 x1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[0]));
2648 x2 = parsed.max[0];
2649 width = x2 - x1;
2650 y1 = Math.min(...parsed.spatials.map(spatial => spatial.coord[1]));
2651 y2 = parsed.max[1];
2652 height = y2 - y1;
2653 segment = 'sign';
2654 lane = parsed.box;
2655 } else {
2656 parsed = parse$1.symbol(swu);
2657 lane = "𝠃";
2658
2659 if (parsed.coord) {
2660 x1 = parsed.coord[0];
2661 width = (500 - x1) * 2;
2662 y1 = parsed.coord[1];
2663 height = (500 - y1) * 2;
2664 segment = 'symbol';
2665 } else {
2666 x1 = 490;
2667 width = 20;
2668 y1 = 490;
2669 height = 20;
2670 segment = 'none';
2671 }
2672 }
2673
2674 let style = parse$4(parsed.style);
2675 let zoom = style.zoom || 1;
2676 let padding = style.padding || 0;
2677 return {
2678 minX: x1,
2679 minY: y1,
2680 width: width,
2681 height: height,
2682 segment: segment,
2683 lane: lanes[lane],
2684 padding: padding,
2685 zoom: zoom
2686 };
2687};
2688
2689const columnDefaults = {
2690 'height': 500,
2691 'width': 150,
2692 'offset': 50,
2693 'pad': 20,
2694 'margin': 5,
2695 'dynamic': false,
2696 'background': undefined,
2697 'punctuation': {
2698 'spacing': true,
2699 'pad': 30,
2700 'pull': true
2701 },
2702 'style': {
2703 'detail': ['black', 'white'],
2704 'zoom': 1
2705 }
2706};
2707/**
2708 * Function to an object of column options with default values
2709 *
2710 * @function swu.columnDefaultsMerge
2711 * @param {ColumnOptions} options - object of column options
2712 * @returns {ColumnOptions} object of column options merged with column defaults
2713 * @example
2714 * swu.columnDefaultsMerge({height: 500,width:150})
2715 *
2716 * return {
2717 * "height": 500,
2718 * "width": 150,
2719 * "offset": 50,
2720 * "pad": 20,
2721 * "margin": 5,
2722 * "dynamic": false,
2723 * "punctuation": {
2724 * "spacing": true,
2725 * "pad": 30,
2726 * "pull": true
2727 * },
2728 * "style": {
2729 * "detail": [
2730 * "black",
2731 * "white"
2732 * ],
2733 * "zoom": 1
2734 * }
2735 * }
2736 */
2737
2738const columnDefaultsMerge = options => {
2739 if (typeof options !== 'object') options = {};
2740 return { ...columnDefaults,
2741 ...options,
2742 punctuation: { ...columnDefaults.punctuation,
2743 ...options.punctuation
2744 },
2745 style: { ...columnDefaults.style,
2746 ...options.style
2747 }
2748 };
2749};
2750/**
2751 * Function to transform an SWU text to an array of columns
2752 *
2753 * @function swu.columns
2754 * @param {string} swuText - SWU text of signs and punctuation
2755 * @param {ColumnOptions} options - object of column options
2756 * @returns {{options:ColumnOptions,widths:number[],columns:ColumnData}} object of column options, widths array, and column data
2757 * @example
2758 * swu.columns('𝠀񁲡񈩧𝠃𝤘𝤣񁲡𝣳𝣩񈩧𝤉𝣻 𝠀񃊢񃊫񋛕񆇡𝠃𝤘𝤧񃊫𝣻𝤕񃊢𝣴𝣼񆇡𝤎𝤂񋛕𝤆𝣦 񏌁𝣢𝤂', {height: 500,width:150})
2759 *
2760 * return {
2761 * "options": {
2762 * "height": 500,
2763 * "width": 150,
2764 * "offset": 50,
2765 * "pad": 20,
2766 * "margin": 5,
2767 * "dynamic": false,
2768 * "punctuation": {
2769 * "spacing": true,
2770 * "pad": 30,
2771 * "pull": true
2772 * },
2773 * "style": {
2774 * "detail": [
2775 * "black",
2776 * "white"
2777 * ],
2778 * "zoom": 1
2779 * }
2780 * },
2781 * "widths": [
2782 * 150
2783 * ],
2784 * "columns": [
2785 * [
2786 * {
2787 * "x": 56,
2788 * "y": 20,
2789 * "minX": 481,
2790 * "minY": 471,
2791 * "width": 37,
2792 * "height": 58,
2793 * "lane": 0,
2794 * "padding": 0,
2795 * "segment": "sign",
2796 * "text": "𝠀񁲡񈩧𝠃𝤘𝤣񁲡𝣳𝣩񈩧𝤉𝣻",
2797 * "zoom": 1
2798 * },
2799 * {
2800 * "x": 57,
2801 * "y": 118,
2802 * "minX": 482,
2803 * "minY": 468,
2804 * "width": 36,
2805 * "height": 65,
2806 * "lane": 0,
2807 * "padding": 0,
2808 * "segment": "sign",
2809 * "text": "𝠀񃊢񃊫񋛕񆇡𝠃𝤘𝤧񃊫𝣻𝤕񃊢𝣴𝣼񆇡𝤎𝤂񋛕𝤆𝣦",
2810 * "zoom": 1
2811 * },
2812 * {
2813 * "x": 39,
2814 * "y": 203,
2815 * "minX": 464,
2816 * "minY": 496,
2817 * "width": 72,
2818 * "height": 8,
2819 * "lane": 0,
2820 * "padding": 0,
2821 * "segment": "symbol",
2822 * "text": "񏌁𝣢𝤂",
2823 * "zoom": 1
2824 * }
2825 * ]
2826 * ]
2827 * }
2828 */
2829
2830
2831const columns = (swuText, options) => {
2832 if (typeof swuText !== 'string') return {};
2833 const values = columnDefaultsMerge(options);
2834 let input = parse$1.text(swuText);
2835 let cursor = 0;
2836 let cols = [];
2837 let col = [];
2838 let plus = 0;
2839 let center = parseInt(values.width / 2);
2840 let maxHeight = values.height - values.margin;
2841 let pullable = true;
2842 let finalize = false;
2843
2844 for (let val of input) {
2845 let informed = info(val);
2846 cursor += plus;
2847
2848 if (values.punctuation.spacing) {
2849 cursor += informed.segment == 'sign' ? values.pad : 0;
2850 } else {
2851 cursor += values.pad;
2852 }
2853
2854 finalize = cursor + informed.height > maxHeight;
2855
2856 if (finalize && informed.segment == 'symbol' && values.punctuation.pull && pullable) {
2857 finalize = false;
2858 pullable = false;
2859 }
2860
2861 if (col.length == 0) {
2862 finalize = false;
2863 }
2864
2865 if (finalize) {
2866 cursor = values.pad;
2867 cols.push(col);
2868 col = [];
2869 pullable = true;
2870 }
2871
2872 col.push(Object.assign(informed, {
2873 x: center + values.offset * informed.lane - (500 - informed.minX) * informed.zoom * values.style.zoom,
2874 y: cursor,
2875 text: val
2876 }));
2877 cursor += informed.height * informed.zoom * values.style.zoom;
2878
2879 if (values.punctuation.spacing) {
2880 plus = informed.segment == 'sign' ? values.pad : values.punctuation.pad;
2881 } else {
2882 plus = values.pad;
2883 }
2884 }
2885
2886 if (col.length) {
2887 cols.push(col);
2888 } // over height issue when pulling punctuation
2889
2890
2891 if (values.punctuation.pull) {
2892 for (let col of cols) {
2893 let last = col[col.length - 1];
2894 let diff = last.y + last.height - (values.height - values.margin);
2895
2896 if (diff > 0) {
2897 let adj = parseInt(diff / col.length) + 1;
2898
2899 for (let i in col) {
2900 col[i].y -= adj * i + adj;
2901 }
2902 }
2903 }
2904 } // contract, expand, adjust
2905
2906
2907 let widths = [];
2908
2909 for (let col of cols) {
2910 let min = [center - values.offset - values.pad];
2911 let max = [center + values.offset + values.pad];
2912
2913 for (let item of col) {
2914 min.push(item.x - values.pad);
2915 max.push(item.x + item.width + values.pad);
2916 }
2917
2918 min = Math.min(...min);
2919 max = Math.max(...max);
2920 let width = values.width;
2921 let adj = 0;
2922
2923 if (!values.dynamic) {
2924 adj = center - parseInt((min + max) / 2);
2925 } else {
2926 width = max - min;
2927 adj = -min;
2928 }
2929
2930 for (let item of col) {
2931 item.x += adj;
2932 }
2933
2934 widths.push(width);
2935 }
2936
2937 return {
2938 'options': values,
2939 'widths': widths,
2940 'columns': cols
2941 };
2942};
2943
2944/**
2945 * Array of plane 4 code points for kinds of symbols: writing, location, and punctuation.
2946 * @alias swu.kind
2947 * @type {array}
2948 */
2949
2950const kind = [0x40001, 0x4efa1, 0x4f2a1];
2951/**
2952 * Array of plane 4 code points for categories of symbols: hand, movement, dynamics, head, trunk & limb, location, and punctuation.
2953 * @alias swu.category
2954 * @type {array}
2955 */
2956
2957const category = [0x40001, 0x461e1, 0x4bca1, 0x4bfa1, 0x4e8e1, 0x4efa1, 0x4f2a1];
2958/**
2959 * Array of plane 4 code points for the 30 symbol groups.
2960 * @alias swu.group
2961 * @type {array}
2962 */
2963
2964const 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];
2965/**
2966 * Object of symbol ranges with starting and ending code points on plane 4.
2967 *
2968 * { all, writing, hand, movement, dynamic, head, hcenter, vcenter, trunk, limb, location, punctuation }
2969 * @alias swu.ranges
2970 * @type {object}
2971 */
2972
2973const ranges = {
2974 'all': [0x40001, 0x4f480],
2975 'writing': [0x40001, 0x4efa0],
2976 'hand': [0x40001, 0x461e0],
2977 'movement': [0x461e1, 0x4bca0],
2978 'dynamic': [0x4bca1, 0x4bfa0],
2979 'head': [0x4bfa1, 0x4e8e0],
2980 'hcenter': [0x4bfa1, 0x4e8e0],
2981 'vcenter': [0x4bfa1, 0x4ec40],
2982 'trunk': [0x4e8e1, 0x4ec40],
2983 'limb': [0x4ec41, 0x4efa0],
2984 'location': [0x4efa1, 0x4f2a0],
2985 'punctuation': [0x4f2a1, 0x4f480]
2986};
2987/**
2988 * Function to test if symbol is of a certain type.
2989 * @function swu.isType
2990 * @param {string} swuSym - an SWU symbol character
2991 * @param {string} type - the name of a symbol range
2992 * @returns {boolean} is symbol of specified type
2993 * @example
2994 * swu.isType('񀀁', 'hand')
2995 *
2996 * return true
2997 */
2998
2999const isType = (swuSym, type) => {
3000 const parsed = parse$1.symbol(swuSym);
3001
3002 if (parsed.symbol) {
3003 const code = swu2code(parsed.symbol);
3004 const range = ranges[type];
3005
3006 if (range) {
3007 return range[0] <= code && range[1] >= code;
3008 }
3009 }
3010
3011 return false;
3012};
3013
3014/**
3015 * Array of colors associated with the seven symbol categories.
3016 * @alias swu.colors
3017 * @type {array}
3018 */
3019
3020const colors = ['#0000CC', '#CC0000', '#FF0099', '#006600', '#000000', '#884411', '#FF9900'];
3021/**
3022 * Function that returns the standardized color for a symbol.
3023 * @function swu.colorize
3024 * @param {string} swuSym - an SWU symbol character
3025 * @returns {string} name of standardized color for symbol
3026 * @example
3027 * swu.colorize('񀀁')
3028 *
3029 * return '#0000CC'
3030 */
3031
3032const colorize = swuSym => {
3033 const parsed = parse$1.symbol(swuSym);
3034 let color = '#000000';
3035
3036 if (parsed.symbol) {
3037 const code = swu2code(parsed.symbol);
3038 const index = category.findIndex(val => val > code);
3039 color = colors[index < 0 ? 6 : index - 1];
3040 }
3041
3042 return color;
3043};
3044
3045/** The swu module contains functions for handling SignWriitng in Unicode (SWU) characters.
3046 * [SWU characters definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-09.html#name-signwriting-in-unicode-swu)
3047 * @module swu
3048 */
3049
3050var index$1 = /*#__PURE__*/Object.freeze({
3051 __proto__: null,
3052 re: re$2,
3053 parse: parse$1,
3054 encode: encode,
3055 decode: decode,
3056 pair: pair,
3057 compose: compose$1,
3058 info: info,
3059 columnDefaults: columnDefaults,
3060 columnDefaultsMerge: columnDefaultsMerge,
3061 columns: columns,
3062 kind: kind,
3063 category: category,
3064 group: group,
3065 ranges: ranges,
3066 isType: isType,
3067 colors: colors,
3068 colorize: colorize
3069});
3070
3071/**
3072 * Object of regular expressions for SWU query strings
3073 *
3074 * { base, coord, var, symbol, range, item, list, prefix, signbox, full }
3075 * @alias swuquery.re
3076 * @type {object}
3077 */
3078let re = {
3079 'base': '(?:(?:\uD8C0[\uDC01-\uDFFF])|(?:[\uD8C1-\uD8FC][\uDC00-\uDFFF])|(?:\uD8FD[\uDC00-\uDC80]))',
3080 'coord': '(?:(?:\uD836[\uDC0C-\uDDFF]){2})?',
3081 'var': 'V[0-9]+'
3082};
3083re.symbol = `${re.base}f?r?`;
3084re.range = `R${re.base}${re.base}`;
3085re.item = `(?:${re.symbol}|${re.range})`;
3086re.list = `${re.item}(?:o${re.item})*`;
3087re.prefix = `(?:A(?:${re.list})+)?T`;
3088re.signbox = `(?:${re.list}${re.coord})*`;
3089re.full = `Q(${re.prefix})?(${re.signbox})?(${re.var})?(-?)`;
3090
3091const parsePrefix = text => {
3092 return {
3093 required: true,
3094 parts: text == 'T' ? undefined : text.match(new RegExp(`(${re.list})`, 'g')).map(part => {
3095 if (part.includes('o')) {
3096 return ['or'].concat(part.match(new RegExp(`(${re.item})`, 'g')).map(part => part[0] != 'R' ? part : [part.slice(1, 3), part.slice(3, 5)]));
3097 } else {
3098 return part[0] != 'R' ? part : [part.slice(1, 3), part.slice(3, 5)];
3099 }
3100 })
3101 };
3102};
3103
3104const parseSignbox = text => {
3105 return text.match(new RegExp(`(${re.list}${re.coord})`, 'g')).map(part => {
3106 let coord, front;
3107 coord = part.match(new RegExp(`${re$2.coord}`));
3108
3109 if (coord) {
3110 coord = swu2coord(coord[0]);
3111 front = part.slice(0, -4);
3112 } else {
3113 coord = undefined;
3114 front = part;
3115 }
3116
3117 if (front.includes('o')) {
3118 return {
3119 or: front.split('o').map(part => {
3120 if (!part.includes('R')) {
3121 return part;
3122 } else {
3123 return [part.slice(1, 3), part.slice(3, 5)];
3124 }
3125 }),
3126 coord,
3127 coord
3128 };
3129 } else if (!front.includes('R')) {
3130 return {
3131 symbol: front,
3132 coord: coord
3133 };
3134 } else {
3135 return {
3136 range: [front.slice(1, 3), front.slice(3, 5)],
3137 coord: coord
3138 };
3139 }
3140 });
3141};
3142/**
3143 * Function to parse SWU query string to object
3144 * @function swuquery.parse
3145 * @param {string} swuQueryString - an SWU query string
3146 * @returns {object} elements of an SWU query string
3147 * @example
3148 * swuquery.parse('QA񀀁R񀀁񆆑񆇡T񆀁R񀀁񀇱𝤆𝤆V5-')
3149 *
3150 * return {
3151 * query: true,
3152 * prefix: {
3153 * required: true,
3154 * parts: [
3155 * '񀀁',
3156 * ['񀀁', '񆆑'],
3157 * '񆇡'
3158 * ]
3159 * },
3160 * signbox: [
3161 * { symbol: '񆀁' },
3162 * {
3163 * range: ['񀀁', '񀇱'],
3164 * coord: [500, 500]
3165 * }
3166 * ],
3167 * variance: 5,
3168 * style: true
3169 * }
3170 */
3171
3172
3173const parse = swuQueryString => {
3174 const query = typeof swuQueryString === 'string' ? swuQueryString.match(new RegExp(`^${re.full}`)) : undefined;
3175 return {
3176 'query': query ? true : undefined,
3177 'prefix': query && query[1] ? parsePrefix(query[1]) : undefined,
3178 'signbox': query && query[2] ? parseSignbox(query[2]) : undefined,
3179 'variance': query && query[3] ? parseInt(query[3].slice(1)) : undefined,
3180 'style': query && query[4] ? true : undefined
3181 };
3182};
3183
3184/**
3185 * Function to compose SWU query string from object
3186 * @function swuquery.compose
3187 * @param {object} swuQueryObject - an object of style options
3188 * @param {boolean} swuQueryObject.query - required true for SWU query object
3189 * @param {object} swuQueryObject.prefix - an object for prefix elements
3190 * @param {boolean} swuQueryObject.prefix.required - true if sorting prefix is required
3191 * @param {(string|string[]|(string|string[])[])[]} swuQueryObject.prefix.parts - array of symbol strings, range arrays, and OR arrays of strings and range arrays
3192 * @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
3193 * @param {number} swuQueryObject.variance - amount that x or y coordinates can vary and find a match, defaults to 20
3194 * @param {boolean} swuQueryObject.style - boolean value for including style string in matches
3195 * @returns {string} SWU query string
3196 * @example
3197 * swuquery.compose({
3198 * query: true,
3199 * prefix: {
3200 * required: true,
3201 * parts: [
3202 * '񀀁',
3203 * ['񀀁', '񆆑'],
3204 * '񆇡'
3205 * ]
3206 * },
3207 * signbox: [
3208 * { symbol: '񆀁' },
3209 * {
3210 * range: ['񀀁', '񀇱'],
3211 * coord: [500, 500]
3212 * }
3213 * ],
3214 * variance: 5,
3215 * style: true
3216 * })
3217 *
3218 * return 'QA񀀁R񀀁񆆑񆇡T񆀁R񀀁񀇱𝤆𝤆V5-'
3219 */
3220
3221const compose = swuQueryObject => {
3222 if (!swuQueryObject || !swuQueryObject.query) {
3223 return undefined;
3224 }
3225
3226 let query = 'Q';
3227
3228 if (swuQueryObject.prefix && swuQueryObject.prefix.required) {
3229 if (Array.isArray(swuQueryObject.prefix.parts)) {
3230 query += 'A';
3231 query += swuQueryObject.prefix.parts.map(part => {
3232 if (typeof part === 'string') {
3233 return part;
3234 } else {
3235 if (Array.isArray(part) && part.length == 2) {
3236 return `R${part[0]}${part[1]}`;
3237 } else if (Array.isArray(part) && part.length > 2 && part[0] == 'or') {
3238 part.shift();
3239 return part.map(part => {
3240 if (typeof part === 'string') {
3241 return part;
3242 } else {
3243 if (Array.isArray(part) && part.length == 2) {
3244 return `R${part[0]}${part[1]}`;
3245 }
3246 }
3247 }).join('o');
3248 }
3249 }
3250 }).join('');
3251 }
3252
3253 query += 'T';
3254 }
3255
3256 if (Array.isArray(swuQueryObject.signbox)) {
3257 query += swuQueryObject.signbox.map(part => {
3258 let out;
3259
3260 if (part.or) {
3261 out = part.or.map(item => {
3262 if (typeof item === 'string') {
3263 return item;
3264 } else {
3265 if (Array.isArray(item) && item.length == 2) {
3266 return `R${item[0]}${item[1]}`;
3267 }
3268 }
3269 }).join('o');
3270 } else if (part.symbol) {
3271 out = part.symbol;
3272 } else {
3273 if (part.range && Array.isArray(part.range) && part.range.length == 2) {
3274 out = `R${part.range[0]}${part.range[1]}`;
3275 }
3276 }
3277
3278 return out + (Array.isArray(part.coord) && part.coord.length == 2 ? coord2swu(part.coord) : '');
3279 }).join('');
3280 }
3281
3282 query += swuQueryObject.style ? '-' : '';
3283 query = query.match(new RegExp(`^${re.full}`))[0];
3284 return query;
3285};
3286
3287/**
3288 * Function to convert an SWU sign to a query string
3289 *
3290 * For the flags parameter, use one or more of the following.
3291 * - A: exact symbol in temporal prefix
3292 * - a: general symbol in temporal prefix
3293 * - S: exact symbol in spatial signbox
3294 * - s: general symbol in spatial signbox
3295 * - L: spatial signbox symbol at location
3296 * @function swuquery.swu2query
3297 * @param {string} swuSign - SWU sign
3298 * @param {string} flags - flags for query string creation
3299 * @returns {string} SWU query string
3300 * @example
3301 * swuquery.swu2query('𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭', 'ASL')
3302 *
3303 * return 'QA񀀒񀀚񋚥񋛩T񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭'
3304 */
3305
3306const swu2query = (swuSign, flags) => {
3307 let query = '';
3308 const parsed = parse$1.sign(swuSign);
3309
3310 if (parsed.box) {
3311 const A_flag = flags.indexOf('A') > -1;
3312 const a_flag = flags.indexOf('a') > -1;
3313 const S_flag = flags.indexOf('S') > -1;
3314 const s_flag = flags.indexOf('s') > -1;
3315 const L_flag = flags.indexOf('L') > -1;
3316
3317 if (A_flag || a_flag || S_flag || s_flag) {
3318 if ((A_flag || a_flag) && parsed.sequence) {
3319 query += 'A';
3320 query += parsed.sequence.map(sym => sym + (a_flag ? 'fr' : '')).join('');
3321 query += 'T';
3322 }
3323
3324 if ((S_flag || s_flag) && parsed.spatials) {
3325 query += parsed.spatials.map(spatial => spatial.symbol + (s_flag ? 'fr' : '') + (L_flag ? coord2swu(spatial.coord) : '')).join('');
3326 }
3327 }
3328
3329 return query ? "Q" + query : undefined;
3330 } else {
3331 return undefined;
3332 }
3333};
3334
3335/**
3336 * Function to transform a range of SWU characters to a regular expression
3337 * @function swuquery.range
3338 * @param {string} min - an SWU character
3339 * @param {string} max - an SWU character
3340 * @returns {string} a regular expression that matches a range of SWU characters
3341 * @example
3342 * swuquery.range('񀀁', '񀇡')
3343 *
3344 * return '\uD8C0[\uDC01-\uDDE1]'
3345 * @example
3346 * swuquery.range('𝣔', '𝤸')
3347 *
3348 * return '\uD836[\uDCD4-\uDD38]'
3349 */
3350
3351const range = (min, max) => {
3352 if (min > max) return '';
3353 let pattern = '';
3354 let cnt;
3355 let re = [];
3356 min = pair(min);
3357 max = pair(max);
3358 if (min.length != 2 && max.length != 2) return ''; // HEAD // min[0] with range of min[1] to (DFFF or max[1])
3359
3360 if (min[0] == max[0]) {
3361 if (min[1] == max[1]) {
3362 pattern = '\\u' + min[0] + '\\u' + min[1];
3363 re.push(pattern);
3364 } else {
3365 pattern = '\\u' + min[0] + '[\\u' + min[1] + '-\\u' + max[1] + ']';
3366 re.push(pattern);
3367 }
3368 } else {
3369 if (min[1] == "DFFF") {
3370 pattern = '\\u' + min[0] + '\\uDFFF';
3371 } else {
3372 pattern = '\\u' + min[0] + '[\\u' + min[1] + '-\\uDFFF]';
3373 }
3374
3375 re.push(pattern); // BODY // range of (min[0] +1) to (max[0] -1) with all DC00-DFFF
3376
3377 let diff = parseInt(max[0], 16) - parseInt(min[0], 16);
3378
3379 if (diff == 2) {
3380 pattern = '\\u' + (parseInt(min[0], 16) + 1).toString(16).toUpperCase();
3381 pattern += '[\\uDC00-\\uDFFF]';
3382 re.push(pattern);
3383 }
3384
3385 if (diff > 2) {
3386 pattern = '[';
3387 pattern += '\\u' + (parseInt(min[0], 16) + 1).toString(16).toUpperCase();
3388 pattern += '-\\u' + (parseInt(max[0], 16) - 1).toString(16).toUpperCase();
3389 pattern += '][\\uDC00-\\uDFFF]';
3390 re.push(pattern);
3391 } // TAIL // max[0] with range of DC00 to max[1]
3392
3393
3394 if (max[1] == "DC00") {
3395 pattern = '\\u' + max[0] + '\\uDC00';
3396 } else {
3397 pattern = '\\u' + max[0] + '[\\uDC00-\\u' + max[1] + ']';
3398 }
3399
3400 re.push(pattern);
3401 }
3402
3403 cnt = re.length;
3404
3405 if (cnt == 1) {
3406 pattern = re[0];
3407 } else {
3408 pattern = re.join(')|(');
3409 pattern = '((' + pattern + '))';
3410 }
3411
3412 return decode(pattern);
3413};
3414
3415/**
3416 * Function to transform an SWU symbol with fill and rotation flags to a regular expression
3417 * @function swuquery.symbolRanges
3418 * @param {string} symbolFR - an SWU character with optional flags of 'f' for any fill and 'r' for any rotation
3419 * @returns {string} a regular expression that matches one or more ranges of SWU symbols
3420 * @example <caption>Match an exact symbol</caption>
3421 * swuquery.symbolRanges('񀀁')
3422 *
3423 * return '\uD8C0\uDC01');
3424 * @example <caption>Match a symbol with any fill</caption>
3425 * swuquery.symbolRanges('񀀁f')
3426 *
3427 * return '(\uD8C0\uDC01|\uD8C0\uDC11|\uD8C0\uDC21|\uD8C0\uDC31|\uD8C0\uDC41|\uD8C0\uDC51)'
3428 * @example <caption>Match a symbol with any rotation</caption>
3429 * swuquery.symbolRanges('񀀁r')
3430 *
3431 * return '\uD8C0[\uDC01-\uDC10]'
3432 * @example <caption>Match a symbol with any fill or rotation</caption>
3433 * swuquery.symbolRanges('񀀁fr')
3434 *
3435 * return '\uD8C0[\uDC01-\uDC60]'
3436 */
3437
3438const symbolRanges = symbolFR => {
3439 let match = symbolFR.match(new RegExp(re.symbol));
3440
3441 if (match) {
3442 let sym = match[0].slice(0, 2);
3443 let key = swu2key(sym);
3444 let base = key.slice(0, 4);
3445 let start, end;
3446
3447 if (match[0].slice(-2) == 'fr') {
3448 start = key2swu(base + "00");
3449 end = key2swu(base + "5f");
3450 return range(start, end);
3451 } else if (match[0].slice(-1) == 'r') {
3452 start = key2swu(key.slice(0, 5) + '0');
3453 end = key2swu(key.slice(0, 5) + 'f');
3454 return range(start, end);
3455 } else if (match[0].slice(-1) == 'f') {
3456 let list = [0, 1, 2, 3, 4, 5].map(function (f) {
3457 return key2swu(base + f + key.slice(-1));
3458 });
3459 return "(" + list.join("|") + ")";
3460 } else {
3461 return sym;
3462 }
3463 } else {
3464 return '';
3465 }
3466};
3467
3468const regexRange = symRange => {
3469 from = swu2key(symRange.slice(1, 3));
3470 to = swu2key(symRange.slice(-2));
3471 from = key2swu(from.slice(0, 4) + '00');
3472 to = key2swu(to.slice(0, 4) + '5f');
3473 return range(from, to);
3474}; //needs rewritten, but it works
3475
3476/**
3477 * Function to transform an SWU query string to one or more regular expressions
3478 * @function swuquery.regex
3479 * @param {string} query - an SWU query string
3480 * @returns {string[]} an array of one or more regular expressions
3481 * @example
3482 * swuquery.regex('QA񀀒T')
3483 *
3484 * return [
3485 * '(\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})*'
3486 * ]
3487 */
3488
3489
3490const regex = query => {
3491 query = query.match(new RegExp(`^${re.full}`))[0];
3492
3493 if (!query) {
3494 return '';
3495 }
3496
3497 let matches;
3498 let matchesOr;
3499 let matched;
3500 let orList;
3501 let i;
3502 let j;
3503 let coord;
3504 let segment;
3505 let x;
3506 let y;
3507 let fuzz = 20;
3508 let re_sym = re$2.symbol;
3509 let re_coord = re$2.coord;
3510 let re_signbox = re$2.box;
3511 let re_seq = re$2.sort;
3512 let re_word = re_signbox + re_coord + '(' + re_sym + re_coord + ')*';
3513 let re_sortable = '(' + re_seq + '(' + re_sym + ')+)';
3514 let q_var = '(V[0-9]+)';
3515 let q_style = '(' + re$3.full + ')?';
3516 let q_sortable;
3517
3518 if (query == 'Q') {
3519 return [re$2.sign];
3520 }
3521
3522 if (query == 'Q-') {
3523 return [re$2.sign + "(" + re$3.full + ")?"];
3524 }
3525
3526 if (query == 'QT') {
3527 return [re$2.sortable];
3528 }
3529
3530 if (query == 'QT-') {
3531 return [re$2.sortable + "(" + re$3.full + ")?"];
3532 }
3533
3534 let segments = [];
3535 let sortable = query.indexOf('T') + 1;
3536
3537 if (sortable) {
3538 q_sortable = '(' + re$2.sort;
3539 let qat = query.slice(0, sortable);
3540 query = query.replace(qat, '');
3541
3542 if (qat == 'QT') {
3543 q_sortable += '(' + re_sym + ')+)';
3544 } else {
3545 matches = qat.match(new RegExp('(' + re.list + ')', 'g'));
3546
3547 if (matches) {
3548 for (i = 0; i < matches.length; i += 1) {
3549 orList = [];
3550 matchesOr = matches[i].match(new RegExp('(' + re.symbol + '|' + re.range + ')', 'g'));
3551
3552 if (matchesOr) {
3553 for (j = 0; j < matchesOr.length; j += 1) {
3554 matched = matchesOr[j].match(new RegExp(re.symbol));
3555
3556 if (matched) {
3557 orList.push(symbolRanges(matched[0]));
3558 } else {
3559 orList.push(regexRange(matchesOr[j]));
3560 }
3561 }
3562
3563 if (orList.length == 1) {
3564 q_sortable += orList[0];
3565 } else {
3566 q_sortable += '(' + orList.join('|') + ')';
3567 }
3568 }
3569 }
3570
3571 q_sortable += '(' + re$2.symbol + ')*)';
3572 }
3573 }
3574 } //get the variance
3575
3576
3577 matches = query.match(new RegExp(q_var, 'g'));
3578
3579 if (matches) {
3580 fuzz = matches.toString().slice(1) * 1;
3581 } //this gets all symbols and ranges with or without location
3582
3583
3584 matches = query.match(new RegExp(re.list + re.coord, 'g'));
3585
3586 if (matches) {
3587 for (i = 0; i < matches.length; i += 1) {
3588 orList = [];
3589 matchesOr = matches[i].match(new RegExp('(' + re.symbol + '|' + re.range + ')', 'g'));
3590
3591 if (matchesOr) {
3592 for (j = 0; j < matchesOr.length; j += 1) {
3593 matched = matchesOr[j].match(new RegExp(re.symbol));
3594
3595 if (matched) {
3596 orList.push(symbolRanges(matched[0]));
3597 } else {
3598 orList.push(regexRange(matchesOr[j]));
3599 }
3600 }
3601
3602 if (orList.length == 1) {
3603 segment = orList[0];
3604 } else {
3605 segment = '(' + orList.join('|') + ')';
3606 }
3607 }
3608
3609 coord = matches[i].match(new RegExp(`${re$2.coord}`));
3610
3611 if (coord) {
3612 coord = swu2coord(coord[0]);
3613 x = coord[0];
3614 y = coord[1];
3615 segment += range(num2swu(x - fuzz), num2swu(x + fuzz));
3616 segment += range(num2swu(y - fuzz), num2swu(y + fuzz));
3617 } else {
3618 segment += re$2.coord;
3619 } // add to general swu word
3620
3621
3622 segment = re_word + segment + '(' + re_sym + re_coord + ')*';
3623
3624 if (sortable) {
3625 segment = q_sortable + segment;
3626 } else {
3627 segment = re_sortable + "?" + segment;
3628 }
3629
3630 if (query.indexOf('-') > 0) {
3631 segment += q_style;
3632 }
3633
3634 segments.push(segment);
3635 }
3636 }
3637
3638 if (!segments.length) {
3639 if (query.indexOf('-') > 0) {
3640 segment += q_style;
3641 }
3642
3643 segments.push(q_sortable + re_word);
3644 }
3645
3646 return segments;
3647};
3648
3649/**
3650 * Function that uses a query string to match signs from a string of text.
3651 * @function swuquery.results
3652 * @param {string} query - an SWU query string
3653 * @param {string} text - a string of text containing multiple signs
3654 * @returns {string[]} an array of SWU signs
3655 * @example
3656 * swuquery.results('QA񀀒T','𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭 𝠀񂇢񂇈񆙡񋎥񋎵𝠃𝤛𝤬񂇈𝤀𝣺񂇢𝤄𝣻񋎥𝤄𝤗񋎵𝤃𝣟񆙡𝣱𝣸 𝠀񅨑񀀙񆉁𝠃𝤙𝤞񀀙𝣷𝤀񅨑𝣼𝤀񆉁𝣳𝣮')
3657 *
3658 * return [
3659 * '𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭'
3660 * ]
3661 */
3662
3663const results = (query, text) => {
3664 if (!text) {
3665 return [];
3666 }
3667
3668 let pattern;
3669 let matches;
3670 let parts;
3671 let words;
3672 let res = regex(query);
3673
3674 if (!res) {
3675 return [];
3676 }
3677
3678 let i;
3679
3680 for (i = 0; i < res.length; i += 1) {
3681 pattern = res[i];
3682 matches = text.match(new RegExp(pattern, 'g'));
3683
3684 if (matches) {
3685 text = matches.join(' ');
3686 } else {
3687 text = '';
3688 }
3689 }
3690
3691 if (text) {
3692 parts = text.split(' ');
3693 words = parts.filter(function (element) {
3694 return element in parts ? false : parts[element] = true;
3695 }, {});
3696 } else {
3697 words = [];
3698 }
3699
3700 return words;
3701}; //needs rewritten, but it works
3702
3703/**
3704 * Function that uses an SWU query string to match signs from multiple lines of text.
3705 * @function swuquery.lines
3706 * @param {string} query - an SWU query string
3707 * @param {string} text - multiple lines of text, each starting with an SWU sign
3708 * @returns {string[]} an array of lines of text, each starting with an SWU sign
3709 * @example
3710 * swuquery.lines('QA񀀒T',`𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭 line one
3711 * 𝠀񂇢񂇈񆙡񋎥񋎵𝠃𝤛𝤬񂇈𝤀𝣺񂇢𝤄𝣻񋎥𝤄𝤗񋎵𝤃𝣟񆙡𝣱𝣸 line two
3712 * 𝠀񅨑񀀙񆉁𝠃𝤙𝤞񀀙𝣷𝤀񅨑𝣼𝤀񆉁𝣳𝣮 line three`)
3713 *
3714 * return [
3715 * '𝠀񀀒񀀚񋚥񋛩𝠃𝤟𝤩񋛩𝣵𝤐񀀒𝤇𝣤񋚥𝤐𝤆񀀚𝣮𝣭 line one'
3716 * ]
3717 */
3718
3719
3720const lines = (query, text) => {
3721 if (!text) {
3722 return [];
3723 }
3724
3725 let pattern;
3726 let matches;
3727 let parts;
3728 let words;
3729 let res = regex(query);
3730
3731 if (!res) {
3732 return [];
3733 }
3734
3735 let i;
3736
3737 for (i = 0; i < res.length; i += 1) {
3738 pattern = res[i];
3739 pattern = '^' + pattern + '.*';
3740 matches = text.match(new RegExp(pattern, 'mg'));
3741
3742 if (matches) {
3743 text = matches.join("\n");
3744 } else {
3745 text = '';
3746 }
3747 }
3748
3749 if (text) {
3750 parts = text.split("\n");
3751 words = parts.filter(function (element) {
3752 return element in parts ? false : parts[element] = true;
3753 }, {});
3754 } else {
3755 words = [];
3756 }
3757
3758 return words;
3759};
3760
3761/** The swuquery module contains functions for handling the SWU query language.
3762 * [Query Language definition](https://tools.ietf.org/id/draft-slevinski-formal-signwriting-09.html#name-query-language)
3763 * @module swuquery
3764 */
3765
3766var index = /*#__PURE__*/Object.freeze({
3767 __proto__: null,
3768 re: re,
3769 parse: parse,
3770 compose: compose,
3771 swu2query: swu2query,
3772 range: range,
3773 symbolRanges: symbolRanges,
3774 regex: regex,
3775 results: results,
3776 lines: lines
3777});
3778
3779export { index$4 as convert, index$3 as fsw, index$2 as fswquery, index$5 as style, index$1 as swu, index as swuquery };
3780
3781/* support ongoing development on https://patreon.com/signwriting */