de-compromise 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -53,6 +53,8 @@
53
53
  };
54
54
  var compute$9 = fns$4;
55
55
 
56
+ // wrappers for loops in javascript arrays
57
+
56
58
  const forEach = function (cb) {
57
59
  let ptrs = this.fullPointer;
58
60
  ptrs.forEach((ptr, i) => {
@@ -64,11 +66,14 @@
64
66
 
65
67
  const map = function (cb, empty) {
66
68
  let ptrs = this.fullPointer;
67
- // let cache = this._cache || []
68
69
  let res = ptrs.map((ptr, i) => {
69
70
  let view = this.update([ptr]);
70
- // view._cache = cache[i]
71
- return cb(view, i)
71
+ let out = cb(view, i);
72
+ // if we returned nothing, return a view
73
+ if (out === undefined) {
74
+ return this.none()
75
+ }
76
+ return out
72
77
  });
73
78
  if (res.length === 0) {
74
79
  return empty || this.update([])
@@ -95,23 +100,18 @@
95
100
 
96
101
  const filter = function (cb) {
97
102
  let ptrs = this.fullPointer;
98
- // let cache = this._cache || []
99
103
  ptrs = ptrs.filter((ptr, i) => {
100
104
  let view = this.update([ptr]);
101
- // view._cache = cache[i]
102
105
  return cb(view, i)
103
106
  });
104
- let res = this.update(ptrs); //TODO: keep caches automatically
105
- // res._cache = ptrs.map(ptr => cache[ptr[0]])
107
+ let res = this.update(ptrs);
106
108
  return res
107
109
  };
108
110
 
109
111
  const find = function (cb) {
110
112
  let ptrs = this.fullPointer;
111
- // let cache = this._cache || []
112
113
  let found = ptrs.find((ptr, i) => {
113
114
  let view = this.update([ptr]);
114
- // view._cache = cache[i]
115
115
  return cb(view, i)
116
116
  });
117
117
  return this.update([found])
@@ -119,10 +119,8 @@
119
119
 
120
120
  const some = function (cb) {
121
121
  let ptrs = this.fullPointer;
122
- // let cache = this._cache || []
123
122
  return ptrs.some((ptr, i) => {
124
123
  let view = this.update([ptr]);
125
- // view._cache = cache[i]
126
124
  return cb(view, i)
127
125
  })
128
126
  };
@@ -176,14 +174,11 @@
176
174
  /** */
177
175
  eq: function (n) {
178
176
  let ptr = this.pointer;
179
- let cache = this._cache || [];
180
177
  if (!ptr) {
181
178
  ptr = this.docs.map((_doc, i) => [i]);
182
179
  }
183
180
  if (ptr[n]) {
184
- let view = this.update([ptr[n]]);
185
- view._cache = cache[n];
186
- return view
181
+ return this.update([ptr[n]])
187
182
  }
188
183
  return this.none()
189
184
  },
@@ -342,31 +337,27 @@
342
337
  update(pointer) {
343
338
  let m = new View(this.document, pointer);
344
339
  // send the cache down, too?
345
- if (m._cache && pointer && pointer.length > 1) {
346
- // only if it's full
340
+ if (this._cache && pointer && pointer.length > 0) {
341
+ // only keep cache if it's a full-sentence
347
342
  let cache = [];
348
- pointer.forEach(ptr => {
343
+ pointer.forEach((ptr, i) => {
344
+ let [n, start, end] = ptr;
349
345
  if (ptr.length === 1) {
350
- cache.push(m._cache[ptr[0]]);
346
+ cache[i] = this._cache[n];
347
+ } else if (start === 0 && this.document[n].length === end) {
348
+ cache[i] = this._cache[n];
351
349
  }
352
- // let [n, start, end] = ptr
353
- // if (start === 0 && this.document[n][end - 1] && !this.document[n][end]) {
354
- // console.log('=-=-=-= here -=-=-=-')
355
- // }
356
350
  });
357
- m._cache = cache;
351
+ if (cache.length > 0) {
352
+ m._cache = cache;
353
+ }
358
354
  }
359
355
  m.world = this.world;
360
356
  return m
361
357
  }
362
358
  // create a new View, from this one
363
359
  toView(pointer) {
364
- if (pointer === undefined) {
365
- pointer = this.pointer;
366
- }
367
- let m = new View(this.document, pointer);
368
- // m._cache = this._cache // share this full thing
369
- return m
360
+ return new View(this.document, pointer || this.pointer)
370
361
  }
371
362
  fromText(input) {
372
363
  const { methods } = this;
@@ -400,7 +391,7 @@
400
391
  Object.assign(View.prototype, api$d);
401
392
  var View$1 = View;
402
393
 
403
- var version$1 = '14.3.1';
394
+ var version$1 = '14.4.0';
404
395
 
405
396
  const isObject$6 = function (item) {
406
397
  return item && typeof item === 'object' && !Array.isArray(item)
@@ -583,7 +574,6 @@
583
574
  return doc
584
575
  };
585
576
 
586
-
587
577
  /** extend compromise functionality */
588
578
  nlp.plugin = function (plugin) {
589
579
  extend$1(plugin, this._world, View$1, this);
@@ -859,7 +849,7 @@
859
849
  after 46-thousand sentences
860
850
 
861
851
  */
862
- let start$1 = 0;
852
+ let index$2 = 0;
863
853
 
864
854
  const pad3 = (str) => {
865
855
  str = str.length < 3 ? '0' + str : str;
@@ -868,19 +858,17 @@
868
858
 
869
859
  const toId = function (term) {
870
860
  let [n, i] = term.index || [0, 0];
871
- start$1 += 1;
872
- var now = start$1;
873
- now = parseInt(now, 10);
861
+ index$2 += 1;
874
862
 
875
- //don't overflow time
876
- now = now > 46655 ? 46655 : now;
863
+ //don't overflow index
864
+ index$2 = index$2 > 46655 ? 0 : index$2;
877
865
  //don't overflow sentences
878
- n = n > 46655 ? 46655 : n;
866
+ n = n > 46655 ? 0 : n;
879
867
  // //don't overflow terms
880
- i = i > 1294 ? 1294 : i;
868
+ i = i > 1294 ? 0 : i;
881
869
 
882
870
  // 3 digits for time
883
- let id = pad3(now.toString(36));
871
+ let id = pad3(index$2.toString(36));
884
872
  // 3 digit for sentence index (46k)
885
873
  id += pad3(n.toString(36));
886
874
 
@@ -939,6 +927,7 @@
939
927
 
940
928
  const insert = function (input, view, prepend) {
941
929
  const { document, world } = view;
930
+ view.uncache();
942
931
  // insert words at end of each doc
943
932
  let ptrs = view.fullPointer;
944
933
  let selfPtrs = view.fullPointer;
@@ -1027,6 +1016,7 @@
1027
1016
  fns$2.replaceWith = function (input, keep = {}) {
1028
1017
  let ptrs = this.fullPointer;
1029
1018
  let main = this;
1019
+ this.uncache();
1030
1020
  if (typeof input === 'function') {
1031
1021
  return replaceByFn(main, input)
1032
1022
  }
@@ -1172,6 +1162,7 @@
1172
1162
  /** */
1173
1163
  remove: function (reg) {
1174
1164
  const { indexN } = this.methods.one.pointer;
1165
+ this.uncache();
1175
1166
  // two modes:
1176
1167
  // - a. remove self, from full parent
1177
1168
  let self = this.all();
@@ -1203,7 +1194,6 @@
1203
1194
  this.ptrs = [];
1204
1195
  return self.none()
1205
1196
  }
1206
- // self._cache = null
1207
1197
  let res = self.toView(ptrs); //return new document
1208
1198
  return res
1209
1199
  },
@@ -1318,7 +1308,7 @@
1318
1308
  methods$h.deHyphenate = methods$h.dehyphenate;
1319
1309
  methods$h.toQuotation = methods$h.toQuotations;
1320
1310
 
1321
- var whitespace$1 = methods$h;
1311
+ var whitespace = methods$h;
1322
1312
 
1323
1313
  /** alphabetical order */
1324
1314
  const alpha = (a, b) => {
@@ -1410,6 +1400,7 @@
1410
1400
  /** re-arrange the order of the matches (in place) */
1411
1401
  const sort = function (input) {
1412
1402
  let { docs, pointer } = this;
1403
+ this.uncache();
1413
1404
  if (typeof input === 'function') {
1414
1405
  return customSort(this, input)
1415
1406
  }
@@ -1449,6 +1440,9 @@
1449
1440
  let ptrs = this.pointer || this.docs.map((_d, n) => [n]);
1450
1441
  ptrs = [].concat(ptrs);
1451
1442
  ptrs = ptrs.reverse();
1443
+ if (this._cache) {
1444
+ this._cache = this._cache.reverse();
1445
+ }
1452
1446
  return this.update(ptrs)
1453
1447
  };
1454
1448
 
@@ -1541,7 +1535,7 @@
1541
1535
  };
1542
1536
  var harden$1 = { harden, soften };
1543
1537
 
1544
- const methods$f = Object.assign({}, caseFns, insert$1, replace, remove, whitespace$1, sort$1, concat, harden$1);
1538
+ const methods$f = Object.assign({}, caseFns, insert$1, replace, remove, whitespace, sort$1, concat, harden$1);
1545
1539
 
1546
1540
  const addAPI$2 = function (View) {
1547
1541
  Object.assign(View.prototype, methods$f);
@@ -1793,6 +1787,34 @@
1793
1787
  };
1794
1788
  var numberRange$1 = numberRange;
1795
1789
 
1790
+ const numUnit = /^([0-9.,+-]+)([a-z°²³µ/]+)$/i;
1791
+
1792
+ const notUnit = new Set([
1793
+ 'st',
1794
+ 'nd',
1795
+ 'rd',
1796
+ 'th',
1797
+ 'am',
1798
+ 'pm',
1799
+ 'max'
1800
+ ]);
1801
+
1802
+ const numberUnit = function (terms, i) {
1803
+ let term = terms[i];
1804
+ let parts = term.text.match(numUnit);
1805
+ if (parts !== null) {
1806
+ // is it a recognized unit, like 'km'?
1807
+ let unit = parts[2].toLowerCase().trim();
1808
+ // don't split '3rd'
1809
+ if (notUnit.has(unit)) {
1810
+ return null
1811
+ }
1812
+ return [parts[1], unit] //split it
1813
+ }
1814
+ return null
1815
+ };
1816
+ var numberUnit$1 = numberUnit;
1817
+
1796
1818
  const byApostrophe = /'/;
1797
1819
  const numDash = /^[0-9][^-–—]*[-–—].*?[0-9]/;
1798
1820
 
@@ -1809,10 +1831,6 @@
1809
1831
  end += 1;
1810
1832
  }
1811
1833
  tmp.ptrs = [[0, start, end]];
1812
- tmp.compute('lexicon');
1813
- if (tmp.world.compute.preTagger) {
1814
- tmp.compute('preTagger');
1815
- }
1816
1834
  };
1817
1835
 
1818
1836
  const byEnd = {
@@ -1854,7 +1872,7 @@
1854
1872
 
1855
1873
  const toDocs = function (words, view) {
1856
1874
  let doc = view.fromText(words.join(' '));
1857
- doc.compute('id');
1875
+ doc.compute(['id', 'alias']);
1858
1876
  return doc.docs[0]
1859
1877
  };
1860
1878
 
@@ -1863,6 +1881,7 @@
1863
1881
  let { world, document } = view;
1864
1882
  const { model, methods } = world;
1865
1883
  let list = model.one.contractions || [];
1884
+ new Set(model.one.units || []);
1866
1885
  // each sentence
1867
1886
  document.forEach((terms, n) => {
1868
1887
  // loop through terms backwards
@@ -1898,10 +1917,18 @@
1898
1917
  methods.one.setTag(words, 'NumberRange', world);//add custom tag
1899
1918
  // is it a time-range, like '5-9pm'
1900
1919
  if (words[2] && words[2].tags.has('Time')) {
1901
- methods.one.setTag([words[0]], 'Time', world);
1920
+ methods.one.setTag([words[0]], 'Time', world, null, 'time-range');
1902
1921
  }
1903
1922
  reTag(document[n], view, i, words.length);
1904
1923
  }
1924
+ continue
1925
+ }
1926
+ // split-apart '4km'
1927
+ words = numberUnit$1(terms, i);
1928
+ if (words) {
1929
+ words = toDocs(words, view);
1930
+ splice(document, [n, i], words);
1931
+ methods.one.setTag([words[1]], 'Unit', world, null, 'contraction-unit');
1905
1932
  }
1906
1933
  }
1907
1934
  });
@@ -2002,7 +2029,7 @@
2002
2029
 
2003
2030
  // tag any words in our lexicon - even if it hasn't been filled-up yet
2004
2031
  // rest of pre-tagger is in ./two/preTagger
2005
- const firstPass$1 = function (view) {
2032
+ const lexicon$5 = function (view) {
2006
2033
  const world = view.world;
2007
2034
  view.docs.forEach(terms => {
2008
2035
  for (let i = 0; i < terms.length; i += 1) {
@@ -2017,7 +2044,7 @@
2017
2044
  };
2018
2045
 
2019
2046
  var compute$4 = {
2020
- lexicon: firstPass$1
2047
+ lexicon: lexicon$5
2021
2048
  };
2022
2049
 
2023
2050
  // derive clever things from our lexicon key-value pairs
@@ -2026,12 +2053,12 @@
2026
2053
  let lex = {};
2027
2054
  // console.log('start:', Object.keys(lex).length)
2028
2055
  let _multi = {};
2029
-
2030
2056
  // go through each word in this key-value obj:
2031
2057
  Object.keys(words).forEach(word => {
2032
2058
  let tag = words[word];
2033
2059
  // normalize lexicon a little bit
2034
2060
  word = word.toLowerCase().trim();
2061
+ word = word.replace(/'s\b/, '');
2035
2062
  // cache multi-word terms
2036
2063
  let split = word.split(/ /);
2037
2064
  if (split.length > 1) {
@@ -2290,11 +2317,13 @@
2290
2317
  /** pre-compile a list of matches to lookup */
2291
2318
  const lib$4 = {
2292
2319
  /** turn an array or object into a compressed trie*/
2293
- compile: function (input) {
2320
+ buildTrie: function (input) {
2294
2321
  const trie = build(input, this.world());
2295
2322
  return compress$1(trie)
2296
2323
  }
2297
2324
  };
2325
+ // add alias
2326
+ lib$4.compile = lib$4.buildTrie;
2298
2327
 
2299
2328
  var lookup = {
2300
2329
  api: api$a,
@@ -2348,6 +2377,19 @@
2348
2377
  // return false
2349
2378
  // }
2350
2379
 
2380
+ const parseRegs = function (regs, opts, world) {
2381
+ const one = world.methods.one;
2382
+ if (typeof regs === 'number') {
2383
+ regs = String(regs);
2384
+ }
2385
+ // support param as string
2386
+ if (typeof regs === 'string') {
2387
+ regs = one.killUnicode(regs, world);
2388
+ regs = one.parseMatch(regs, opts, world);
2389
+ }
2390
+ return regs
2391
+ };
2392
+
2351
2393
  const match$2 = function (regs, group, opts) {
2352
2394
  const one = this.methods.one;
2353
2395
  // support param as view object
@@ -2358,25 +2400,12 @@
2358
2400
  if (isNet(regs)) {
2359
2401
  return this.sweep(regs, { tagger: false }).view.settle()
2360
2402
  }
2361
- // support param as string
2362
- if (typeof regs === 'string') {
2363
- regs = one.killUnicode(regs, this.world);
2364
- regs = one.parseMatch(regs, opts, this.world);
2365
- }
2403
+ regs = parseRegs(regs, opts, this.world);
2366
2404
  let todo = { regs, group };
2367
2405
  let res = one.match(this.docs, todo, this._cache);
2368
2406
  let { ptrs, byGroup } = fixPointers(res, this.fullPointer);
2369
2407
  let view = this.toView(ptrs);
2370
2408
  view._groups = byGroup;
2371
- // try to keep some of the cache
2372
- // if (this._cache) {
2373
- // view._cache = view.ptrs.map(ptr => {
2374
- // if (isFull(ptr, this.document)) {
2375
- // return this._cache[ptr[0]]
2376
- // }
2377
- // return null
2378
- // })
2379
- // }
2380
2409
  return view
2381
2410
  };
2382
2411
 
@@ -2390,10 +2419,7 @@
2390
2419
  if (isNet(regs)) {
2391
2420
  return this.sweep(regs, { tagger: false, matchOne: true }).view
2392
2421
  }
2393
- if (typeof regs === 'string') {
2394
- regs = one.killUnicode(regs, this.world);
2395
- regs = one.parseMatch(regs, opts, this.world);
2396
- }
2422
+ regs = parseRegs(regs, opts, this.world);
2397
2423
  let todo = { regs, group, justOne: true };
2398
2424
  let res = one.match(this.docs, todo, this._cache);
2399
2425
  let { ptrs, byGroup } = fixPointers(res, this.fullPointer);
@@ -2413,10 +2439,7 @@
2413
2439
  if (isNet(regs)) {
2414
2440
  return this.sweep(regs, { tagger: false }).view.found
2415
2441
  }
2416
- if (typeof regs === 'string') {
2417
- regs = one.killUnicode(regs, this.world);
2418
- regs = one.parseMatch(regs, opts, this.world);
2419
- }
2442
+ regs = parseRegs(regs, opts, this.world);
2420
2443
  let todo = { regs, group, justOne: true };
2421
2444
  let ptrs = one.match(this.docs, todo, this._cache).ptrs;
2422
2445
  return ptrs.length > 0
@@ -2434,10 +2457,7 @@
2434
2457
  let m = this.sweep(regs, { tagger: false }).view.settle();
2435
2458
  return this.if(m)//recurse with result
2436
2459
  }
2437
- if (typeof regs === 'string') {
2438
- regs = one.killUnicode(regs, this.world);
2439
- regs = one.parseMatch(regs, opts, this.world);
2440
- }
2460
+ regs = parseRegs(regs, opts, this.world);
2441
2461
  let todo = { regs, group, justOne: true };
2442
2462
  let ptrs = this.fullPointer;
2443
2463
  let cache = this._cache || [];
@@ -2467,10 +2487,7 @@
2467
2487
  return this.ifNo(m)
2468
2488
  }
2469
2489
  // otherwise parse the match string
2470
- if (typeof regs === 'string') {
2471
- regs = one.killUnicode(regs, this.world);
2472
- regs = one.parseMatch(regs, opts, this.world);
2473
- }
2490
+ regs = parseRegs(regs, opts, this.world);
2474
2491
  let cache = this._cache || [];
2475
2492
  let view = this.filter((m, i) => {
2476
2493
  let todo = { regs, group, justOne: true };
@@ -2849,14 +2866,24 @@
2849
2866
  return obj
2850
2867
  }
2851
2868
 
2852
- //machine/sense overloaded
2869
+ //root/sense overloaded
2853
2870
  if (start(w) === '{' && end(w) === '}') {
2854
2871
  w = stripBoth(w);
2872
+ obj.id = w;
2873
+ obj.root = w;
2855
2874
  if (/\//.test(w)) {
2856
- obj.sense = w;
2857
- obj.greedy = true;
2858
- } else {
2859
- obj.machine = w;
2875
+ let split = obj.root.split(/\//);
2876
+ obj.root = split[0];
2877
+ obj.pos = split[1];
2878
+ if (obj.pos === 'adj') {
2879
+ obj.pos = 'Adjective';
2880
+ }
2881
+ // titlecase
2882
+ obj.pos = obj.pos.charAt(0).toUpperCase() + obj.pos.substr(1).toLowerCase();
2883
+ // add sense-number too
2884
+ if (split[2] !== undefined) {
2885
+ obj.num = split[2];
2886
+ }
2860
2887
  }
2861
2888
  return obj
2862
2889
  }
@@ -2965,6 +2992,60 @@
2965
2992
  };
2966
2993
  var splitHyphens$2 = splitHyphens$1;
2967
2994
 
2995
+ const addVerbs = function (token, world) {
2996
+ let { verbConjugate } = world.methods.two.transform;
2997
+ let res = verbConjugate(token.root, world.model);
2998
+ delete res.FutureTense;
2999
+ return Object.values(res).filter(str => str)
3000
+ };
3001
+
3002
+ const addNoun = function (token, world) {
3003
+ let { nounToPlural } = world.methods.two.transform;
3004
+ let res = [token.root];
3005
+ res.push(nounToPlural(token.root, world.model));
3006
+ return res
3007
+ };
3008
+
3009
+ const addAdjective = function (token, world) {
3010
+ let { adjToSuperlative, adjToComparative, adjToAdverb } = world.methods.two.transform;
3011
+ let res = [token.root];
3012
+ res.push(adjToSuperlative(token.root, world.model));
3013
+ res.push(adjToComparative(token.root, world.model));
3014
+ res.push(adjToAdverb(token.root, world.model));
3015
+ return res
3016
+ };
3017
+
3018
+ // turn '{walk}' into 'walking', 'walked', etc
3019
+ const inflectRoot = function (regs, world) {
3020
+ // do we have compromise/two?
3021
+ if (world.methods.two && world.methods.two.transform) {
3022
+ regs = regs.map(token => {
3023
+ // a reg to convert '{foo}'
3024
+ if (token.root) {
3025
+ let choices = [];
3026
+ if (!token.pos || token.pos === 'Verb') {
3027
+ choices = choices.concat(addVerbs(token, world));
3028
+ }
3029
+ if (!token.pos || token.pos === 'Noun') {
3030
+ choices = choices.concat(addNoun(token, world));
3031
+ }
3032
+ // don't run these by default
3033
+ if (!token.pos || token.pos === 'Adjective') {
3034
+ choices = choices.concat(addAdjective(token, world));
3035
+ }
3036
+ choices = choices.filter(str => str);
3037
+ if (choices.length > 0) {
3038
+ token.operator = 'or';
3039
+ token.fastOr = new Set(choices);
3040
+ }
3041
+ }
3042
+ return token
3043
+ });
3044
+ }
3045
+ return regs
3046
+ };
3047
+ var inflectRoot$1 = inflectRoot;
3048
+
2968
3049
  // name any [unnamed] capture-groups with a number
2969
3050
  const nameGroups = function (regs) {
2970
3051
  let index = 0;
@@ -3073,6 +3154,8 @@
3073
3154
  tokens = tokens.map(str => parseToken$1(str, opts));
3074
3155
  // '~re-do~'
3075
3156
  tokens = splitHyphens$2(tokens, world);
3157
+ // '{walk}'
3158
+ tokens = inflectRoot$1(tokens, world);
3076
3159
  //clean up anything weird
3077
3160
  tokens = postProcess$1(tokens);
3078
3161
  // console.log(tokens)
@@ -3328,6 +3411,10 @@
3328
3411
  }
3329
3412
  // support optimized (one|two)
3330
3413
  if (reg.fastOr !== undefined) {
3414
+ // {work/verb} must be a verb
3415
+ if (reg.pos && !term.tags.has(reg.pos)) {
3416
+ return null
3417
+ }
3331
3418
  return reg.fastOr.has(term.implicit) || reg.fastOr.has(term.normal) || reg.fastOr.has(term.text) || reg.fastOr.has(term.machine)
3332
3419
  }
3333
3420
  //support slower (one|two)
@@ -4601,6 +4688,9 @@
4601
4688
  if (method === 'normal') {
4602
4689
  return this.text('normal')
4603
4690
  }
4691
+ if (method === 'root') {
4692
+ return this.text('root')
4693
+ }
4604
4694
  if (method === 'machine' || method === 'reduced') {
4605
4695
  return this.text('machine')
4606
4696
  }
@@ -5240,7 +5330,7 @@
5240
5330
  return { wants, count }
5241
5331
  };
5242
5332
 
5243
- const parse$1 = function (matches, world) {
5333
+ const parse$2 = function (matches, world) {
5244
5334
  const parseMatch = world.methods.one.parseMatch;
5245
5335
  matches.forEach(obj => {
5246
5336
  obj.regs = parseMatch(obj.match, {}, world);
@@ -5259,12 +5349,12 @@
5259
5349
  return matches
5260
5350
  };
5261
5351
 
5262
- var parse$2 = parse$1;
5352
+ var parse$3 = parse$2;
5263
5353
 
5264
5354
  // do some indexing on the list of matches
5265
- const compile = function (matches, world) {
5355
+ const buildNet = function (matches, world) {
5266
5356
  // turn match-syntax into json
5267
- matches = parse$2(matches, world);
5357
+ matches = parse$3(matches, world);
5268
5358
 
5269
5359
  // collect by wants and needs
5270
5360
  let hooks = {};
@@ -5300,7 +5390,7 @@
5300
5390
  }
5301
5391
  };
5302
5392
 
5303
- var buildNet = compile;
5393
+ var buildNet$1 = buildNet;
5304
5394
 
5305
5395
  // for each cached-sentence, find a list of possible matches
5306
5396
  const getHooks = function (docCaches, hooks) {
@@ -5456,7 +5546,7 @@
5456
5546
  console.log(`\n\n \x1b[32m→ ${list.length} post-tagger:\x1b[0m`); //eslint-disable-line
5457
5547
  }
5458
5548
  return list.map(todo => {
5459
- if (!todo.tag && !todo.chunk) {
5549
+ if (!todo.tag && !todo.chunk && !todo.unTag) {
5460
5550
  return
5461
5551
  }
5462
5552
  let reason = todo.reason || todo.match;
@@ -5493,7 +5583,7 @@
5493
5583
  var bulkTagger = tagger$3;
5494
5584
 
5495
5585
  var methods$3 = {
5496
- buildNet,
5586
+ buildNet: buildNet$1,
5497
5587
  bulkMatch,
5498
5588
  bulkTagger
5499
5589
  };
@@ -5549,7 +5639,7 @@
5549
5639
  }
5550
5640
  // finally, add our tag
5551
5641
  term.tags.add(tag);
5552
- // now it's dirty
5642
+ // now it's dirty?
5553
5643
  term.dirty = true;
5554
5644
  // add a chunk too, if it's easy
5555
5645
  addChunk(term, tag);
@@ -5964,71 +6054,20 @@
5964
6054
  }
5965
6055
  return all
5966
6056
  };
5967
- var basicSplit$1 = basicSplit;
5968
-
5969
- const isAcronym$2 = /[ .][A-Z]\.? *$/i;
5970
- const hasEllipse = /(?:\u2026|\.{2,}) *$/;
5971
- const hasLetter$1 = /\p{L}/u;
5972
-
5973
- /** does this look like a sentence? */
5974
- const isSentence = function (str, abbrevs) {
5975
- // must have a letter
5976
- if (hasLetter$1.test(str) === false) {
5977
- return false
5978
- }
5979
- // check for 'F.B.I.'
5980
- if (isAcronym$2.test(str) === true) {
5981
- return false
5982
- }
5983
- //check for '...'
5984
- if (hasEllipse.test(str) === true) {
5985
- return false
5986
- }
5987
- let txt = str.replace(/[.!?\u203D\u2E18\u203C\u2047-\u2049] *$/, '');
5988
- let words = txt.split(' ');
5989
- let lastWord = words[words.length - 1].toLowerCase();
5990
- // check for 'Mr.'
5991
- if (abbrevs.hasOwnProperty(lastWord) === true) {
5992
- return false
5993
- }
5994
- // //check for jeopardy!
5995
- // if (blacklist.hasOwnProperty(lastWord)) {
5996
- // return false
5997
- // }
5998
- return true
5999
- };
6000
- var isSentence$1 = isSentence;
6057
+ var simpleSplit = basicSplit;
6001
6058
 
6002
- //(Rule-based sentence boundary segmentation) - chop given text into its proper sentences.
6003
- // Ignore periods/questions/exclamations used in acronyms/abbreviations/numbers, etc.
6004
- //regs-
6005
- const hasSomething = /\S/;
6006
- const startWhitespace = /^\s+/;
6007
- const hasLetter = /[a-z0-9\u00C0-\u00FF\u00a9\u00ae\u2000-\u3300\ud000-\udfff]/i;
6059
+ const hasLetter$2 = /[a-z0-9\u00C0-\u00FF\u00a9\u00ae\u2000-\u3300\ud000-\udfff]/i;
6060
+ const hasSomething$1 = /\S/;
6008
6061
 
6009
- const splitSentences = function (text, model) {
6010
- let abbrevs = model.one.abbreviations || new Set();
6011
- text = text || '';
6012
- text = String(text);
6013
- let sentences = [];
6014
- // First do a greedy-split..
6062
+ const notEmpty = function (splits) {
6015
6063
  let chunks = [];
6016
- // Ensure it 'smells like' a sentence
6017
- if (!text || typeof text !== 'string' || hasSomething.test(text) === false) {
6018
- return sentences
6019
- }
6020
- // cleanup unicode-spaces
6021
- text = text.replace('\xa0', ' ');
6022
- // Start somewhere:
6023
- let splits = basicSplit$1(text);
6024
- // Filter-out the crap ones
6025
6064
  for (let i = 0; i < splits.length; i++) {
6026
6065
  let s = splits[i];
6027
6066
  if (s === undefined || s === '') {
6028
6067
  continue
6029
6068
  }
6030
6069
  //this is meaningful whitespace
6031
- if (hasSomething.test(s) === false || hasLetter.test(s) === false) {
6070
+ if (hasSomething$1.test(s) === false || hasLetter$2.test(s) === false) {
6032
6071
  //add it to the last one
6033
6072
  if (chunks[chunks.length - 1]) {
6034
6073
  chunks[chunks.length - 1] += s;
@@ -6042,12 +6081,20 @@
6042
6081
  //else, only whitespace, no terms, no sentence
6043
6082
  chunks.push(s);
6044
6083
  }
6045
- //detection of non-sentence chunks:
6046
- //loop through these chunks, and join the non-sentence chunks back together..
6084
+ return chunks
6085
+ };
6086
+ var simpleMerge = notEmpty;
6087
+
6088
+ //loop through these chunks, and join the non-sentence chunks back together..
6089
+ const smartMerge = function (chunks, world) {
6090
+ const isSentence = world.methods.one.tokenize.isSentence;
6091
+ const abbrevs = world.model.one.abbreviations || new Set();
6092
+
6093
+ let sentences = [];
6047
6094
  for (let i = 0; i < chunks.length; i++) {
6048
6095
  let c = chunks[i];
6049
6096
  //should this chunk be combined with the next one?
6050
- if (chunks[i + 1] && isSentence$1(c, abbrevs) === false) {
6097
+ if (chunks[i + 1] && isSentence(c, abbrevs) === false) {
6051
6098
  chunks[i + 1] = c + (chunks[i + 1] || '');
6052
6099
  } else if (c && c.length > 0) {
6053
6100
  //this chunk is a proper sentence..
@@ -6055,6 +6102,31 @@
6055
6102
  chunks[i] = '';
6056
6103
  }
6057
6104
  }
6105
+ return sentences
6106
+ };
6107
+ var smartMerge$1 = smartMerge;
6108
+
6109
+ //(Rule-based sentence boundary segmentation) - chop given text into its proper sentences.
6110
+ // Ignore periods/questions/exclamations used in acronyms/abbreviations/numbers, etc.
6111
+ //regs-
6112
+ const hasSomething = /\S/;
6113
+ const startWhitespace = /^\s+/;
6114
+
6115
+ const splitSentences = function (text, world) {
6116
+ text = text || '';
6117
+ text = String(text);
6118
+ // Ensure it 'smells like' a sentence
6119
+ if (!text || typeof text !== 'string' || hasSomething.test(text) === false) {
6120
+ return []
6121
+ }
6122
+ // cleanup unicode-spaces
6123
+ text = text.replace('\xa0', ' ');
6124
+ // First do a greedy-split..
6125
+ let splits = simpleSplit(text);
6126
+ // Filter-out the crap ones
6127
+ let chunks = simpleMerge(splits);
6128
+ //detection of non-sentence chunks:
6129
+ let sentences = smartMerge$1(chunks, world);
6058
6130
  //if we never got a sentence, return the given text
6059
6131
  if (sentences.length === 0) {
6060
6132
  return [text]
@@ -6070,7 +6142,7 @@
6070
6142
  }
6071
6143
  return sentences
6072
6144
  };
6073
- var sentence = splitSentences;
6145
+ var splitSentences$1 = splitSentences;
6074
6146
 
6075
6147
  const hasHyphen = function (str, model) {
6076
6148
  let parts = str.split(/[-–—]/);
@@ -6218,12 +6290,12 @@
6218
6290
  result = result.filter(s => s);
6219
6291
  return result
6220
6292
  };
6221
- var term = splitWords;
6293
+ var splitTerms = splitWords;
6222
6294
 
6223
6295
  //all punctuation marks, from https://en.wikipedia.org/wiki/Punctuation
6224
6296
  //we have slightly different rules for start/end - like #hashtags.
6225
6297
  const startings =
6226
- /^[ \n\t.[\](){}⟨⟩:,،、‒–—―…!‹›«»‐\-?‘’;/⁄·&*•^†‡°¡¿※№÷׺ª%‰+−=‱¶′″‴§~|‖¦©℗®℠™¤₳฿\u0022\uFF02\u0027\u201C\u201F\u201B\u201E\u2E42\u201A\u2035\u2036\u2037\u301D\u0060\u301F]+/;
6298
+ /^[ \n\t.[\](){}⟨⟩:,،、‒–—―…!‹›«»‐\-?‘’;/⁄·&*•^†‡¡¿※№÷׺ª%‰+−=‱¶′″‴§~|‖¦©℗®℠™¤₳฿\u0022\uFF02\u0027\u201C\u201F\u201B\u201E\u2E42\u201A\u2035\u2036\u2037\u301D\u0060\u301F]+/;
6227
6299
  const endings =
6228
6300
  /[ \n\t.'[\](){}⟨⟩:,،、‒–—―…!‹›«»‐\-?‘’;/⁄·&*@•^†‡°¡¿※#№÷׺ª‰+−=‱¶′″‴§~|‖¦©℗®℠™¤₳฿\u0022\uFF02\u201D\u00B4\u301E]+$/;
6229
6301
  const hasApostrophe$1 = /['’]/;
@@ -6289,7 +6361,21 @@
6289
6361
  };
6290
6362
  return parsed
6291
6363
  };
6292
- var whitespace = parseTerm;
6364
+ var splitWhitespace = parseTerm;
6365
+
6366
+ // 'Björk' to 'Bjork'.
6367
+ const killUnicode = function (str, world) {
6368
+ const unicode = world.model.one.unicode || {};
6369
+ str = str || '';
6370
+ let chars = str.split('');
6371
+ chars.forEach((s, i) => {
6372
+ if (unicode[s]) {
6373
+ chars[i] = unicode[s];
6374
+ }
6375
+ });
6376
+ return chars.join('')
6377
+ };
6378
+ var killUnicode$1 = killUnicode;
6293
6379
 
6294
6380
  /** some basic operations on a string to reduce noise */
6295
6381
  const clean = function (str) {
@@ -6329,7 +6415,7 @@
6329
6415
  const noPeriodAcronym$1 = /[A-Z]{2,}('s|,)?$/;
6330
6416
  const lowerCaseAcronym$1 = /([a-z]\.)+[a-z]\.?$/;
6331
6417
 
6332
- const isAcronym$1 = function (str) {
6418
+ const isAcronym$3 = function (str) {
6333
6419
  //like N.D.A
6334
6420
  if (periodAcronym$1.test(str) === true) {
6335
6421
  return true
@@ -6350,7 +6436,7 @@
6350
6436
  };
6351
6437
 
6352
6438
  const doAcronym = function (str) {
6353
- if (isAcronym$1(str)) {
6439
+ if (isAcronym$3(str)) {
6354
6440
  str = str.replace(/\./g, '');
6355
6441
  }
6356
6442
  return str
@@ -6369,27 +6455,13 @@
6369
6455
  };
6370
6456
  var normal = normalize;
6371
6457
 
6372
- // 'Björk' to 'Bjork'.
6373
- const killUnicode = function (str, world) {
6374
- const unicode = world.model.one.unicode || {};
6375
- str = str || '';
6376
- let chars = str.split('');
6377
- chars.forEach((s, i) => {
6378
- if (unicode[s]) {
6379
- chars[i] = unicode[s];
6380
- }
6381
- });
6382
- return chars.join('')
6383
- };
6384
- var killUnicode$1 = killUnicode;
6385
-
6386
6458
  // turn a string input into a 'document' json format
6387
- const fromString = function (input, world) {
6459
+ const parse$1 = function (input, world) {
6388
6460
  const { methods, model } = world;
6389
6461
  const { splitSentences, splitTerms, splitWhitespace } = methods.one.tokenize;
6390
6462
  input = input || '';
6391
6463
  // split into sentences
6392
- let sentences = splitSentences(input, model);
6464
+ let sentences = splitSentences(input, world);
6393
6465
  // split into word objects
6394
6466
  input = sentences.map((txt) => {
6395
6467
  let terms = splitTerms(txt, model);
@@ -6403,14 +6475,49 @@
6403
6475
  });
6404
6476
  return input
6405
6477
  };
6478
+ var fromString = parse$1;
6479
+
6480
+ const isAcronym$2 = /[ .][A-Z]\.? *$/i;
6481
+ const hasEllipse$1 = /(?:\u2026|\.{2,}) *$/;
6482
+ const hasLetter$1 = /\p{L}/u;
6483
+
6484
+ /** does this look like a sentence? */
6485
+ const isSentence$2 = function (str, abbrevs) {
6486
+ // must have a letter
6487
+ if (hasLetter$1.test(str) === false) {
6488
+ return false
6489
+ }
6490
+ // check for 'F.B.I.'
6491
+ if (isAcronym$2.test(str) === true) {
6492
+ return false
6493
+ }
6494
+ //check for '...'
6495
+ if (hasEllipse$1.test(str) === true) {
6496
+ return false
6497
+ }
6498
+ let txt = str.replace(/[.!?\u203D\u2E18\u203C\u2047-\u2049] *$/, '');
6499
+ let words = txt.split(' ');
6500
+ let lastWord = words[words.length - 1].toLowerCase();
6501
+ // check for 'Mr.'
6502
+ if (abbrevs.hasOwnProperty(lastWord) === true) {
6503
+ return false
6504
+ }
6505
+ // //check for jeopardy!
6506
+ // if (blacklist.hasOwnProperty(lastWord)) {
6507
+ // return false
6508
+ // }
6509
+ return true
6510
+ };
6511
+ var isSentence$3 = isSentence$2;
6406
6512
 
6407
6513
  var methods$1 = {
6408
6514
  one: {
6409
6515
  killUnicode: killUnicode$1,
6410
6516
  tokenize: {
6411
- splitSentences: sentence,
6412
- splitTerms: term,
6413
- splitWhitespace: whitespace,
6517
+ splitSentences: splitSentences$1,
6518
+ isSentence: isSentence$3,
6519
+ splitTerms,
6520
+ splitWhitespace,
6414
6521
  fromString,
6415
6522
  },
6416
6523
  },
@@ -6606,7 +6713,7 @@
6606
6713
  'dl',
6607
6714
  'ml',
6608
6715
  'gal',
6609
- 'ft', //ambiguous
6716
+ // 'ft', //ambiguous
6610
6717
  'qt',
6611
6718
  'pt',
6612
6719
  'tbl',
@@ -6635,13 +6742,12 @@
6635
6742
  'kmph', //kilometers per hour
6636
6743
  'kb', //kilobyte
6637
6744
  'mb', //megabyte
6638
- 'gb', //ambig
6745
+ // 'gb', //ambig
6639
6746
  'tb', //terabyte
6640
6747
  'lx', //lux
6641
6748
  'lm', //lumen
6642
- 'pa', //ambig
6749
+ // 'pa', //ambig
6643
6750
  'fl oz', //
6644
-
6645
6751
  'yb',
6646
6752
  ];
6647
6753
 
@@ -6761,7 +6867,7 @@
6761
6867
  r: 'ŔŕŖŗŘřƦȐȑȒȓɌɍЃГЯгяѓҐґ',
6762
6868
  s: 'ŚśŜŝŞşŠšƧƨȘșȿЅѕ',
6763
6869
  t: 'ŢţŤťŦŧƫƬƭƮȚțȶȾΓΤτϮТт',
6764
- u: 'µÙÚÛÜùúûüŨũŪūŬŭŮůŰűŲųƯưƱƲǓǔǕǖǗǘǙǚǛǜȔȕȖȗɄΰμυϋύ',
6870
+ u: 'ÙÚÛÜùúûüŨũŪūŬŭŮůŰűŲųƯưƱƲǓǔǕǖǗǘǙǚǛǜȔȕȖȗɄΰυϋύ',
6765
6871
  v: 'νѴѵѶѷ',
6766
6872
  w: 'ŴŵƜωώϖϢϣШЩшщѡѿ',
6767
6873
  x: '×ΧχϗϰХхҲҳӼӽӾӿ',
@@ -6795,7 +6901,7 @@
6795
6901
  // const hasApostrophe = /['’]s$/
6796
6902
 
6797
6903
  const addAliases = function (term, world) {
6798
- let str = term.normal || term.text;
6904
+ let str = term.normal || term.text || term.machine;
6799
6905
  const aliases = world.model.one.aliases;
6800
6906
  // lookup known aliases like '&'
6801
6907
  if (aliases.hasOwnProperty(str)) {
@@ -7940,10 +8046,49 @@
7940
8046
  { word: 'zur', out: ['zu', 'der'] }, //(to the / to)
7941
8047
  ];
7942
8048
 
8049
+ const isAcronym$1 = /[ .][A-Z]\.? *$/i;
8050
+ const hasEllipse = /(?:\u2026|\.{2,}) *$/;
8051
+ const hasLetter = /\p{L}/u;
8052
+ const isOrdinal = /[0-9]\. *$/;
8053
+
8054
+ /** does this look like a sentence? */
8055
+ const isSentence = function (str, abbrevs) {
8056
+ // must have a letter
8057
+ if (hasLetter.test(str) === false) {
8058
+ return false
8059
+ }
8060
+ // check for 'F.B.I.'
8061
+ if (isAcronym$1.test(str) === true) {
8062
+ return false
8063
+ }
8064
+ // german ordinals like '4.'
8065
+ if (isOrdinal.test(str) === true) {
8066
+ return false
8067
+ }
8068
+ //check for '...'
8069
+ if (hasEllipse.test(str) === true) {
8070
+ return false
8071
+ }
8072
+ let txt = str.replace(/[.!?\u203D\u2E18\u203C\u2047-\u2049] *$/, '');
8073
+ let words = txt.split(' ');
8074
+ let lastWord = words[words.length - 1].toLowerCase();
8075
+ // check for 'Mr.'
8076
+ if (abbrevs.hasOwnProperty(lastWord) === true) {
8077
+ return false
8078
+ }
8079
+ // //check for jeopardy!
8080
+ // if (blacklist.hasOwnProperty(lastWord)) {
8081
+ // return false
8082
+ // }
8083
+ return true
8084
+ };
8085
+ var isSentence$1 = isSentence;
8086
+
7943
8087
  var tokenizer = {
7944
8088
  mutate: (world) => {
7945
8089
  world.model.one.unicode = unicode$1;
7946
8090
  world.model.one.contractions = contractions;
8091
+ world.methods.one.tokenize.isSentence = isSentence$1;
7947
8092
  },
7948
8093
  };
7949
8094
 
@@ -8079,6 +8224,8 @@
8079
8224
  };
8080
8225
 
8081
8226
  const hasApostrophe = /['‘’‛‵′`´]/;
8227
+ const hasPeriod = /\./;
8228
+ const isNum = /^[0-9+-,]+$/;
8082
8229
 
8083
8230
  // normal regexes
8084
8231
  const doRegs = function (str, regs) {
@@ -8100,6 +8247,12 @@
8100
8247
  if (hasApostrophe.test(term.post) && !hasApostrophe.test(term.pre)) {
8101
8248
  text += term.post.trim();
8102
8249
  }
8250
+ // keep period in number ordinals?
8251
+ if (hasPeriod.test(term.post) && isNum.test(text)) {
8252
+ setTag([term], ['Ordinal', 'NumericValue'], world, false, `1-regex-ordinal`);
8253
+ term.confidence = 0.6;
8254
+ return true
8255
+ }
8103
8256
  let arr = doRegs(text, regexText) || doRegs(normal, regexNormal);
8104
8257
  // hide a bunch of number regexes behind this one
8105
8258
  if (!arr && /[0-9]/.test(normal)) {
@@ -8512,6 +8665,9 @@
8512
8665
  // ending-apostrophes
8513
8666
  [/.{3}[lkmnp]in['‘’‛‵′`´]$/, 'Gerund', "chillin'"],
8514
8667
  [/.{4}s['‘’‛‵′`´]$/, 'Possessive', "flanders'"],
8668
+
8669
+ // german ordinals '4.'
8670
+ // [/^[0-9]+\.$/, 'Ordinal'],
8515
8671
  ];
8516
8672
 
8517
8673
  const rb = 'Adverb';
@@ -9333,7 +9489,7 @@
9333
9489
  api: api$1
9334
9490
  };
9335
9491
 
9336
- var version = '0.0.4';
9492
+ var version = '0.0.5';
9337
9493
 
9338
9494
  nlp$1.plugin(tokenizer);
9339
9495
  nlp$1.plugin(tagset);