compromise
Advanced tools
Comparing version 13.11.4 to 14.0.0
@@ -15,2 +15,46 @@ compromise uses semver, and pushes to npm frequently | ||
### 14.0.0 :postal_horn: [March 2022] | ||
Major release - see [Release Notes](https://github.com/spencermountain/compromise/releases/tag/14.0.0) for full details | ||
- **[breaking]** - remove `.parent()` and `.parents()` chain - (use `.all()` instead) | ||
- **[breaking]** - remove `@titleCase` alias (use @isTitleCase) | ||
- **[breaking]** - remove '.get()' alias - use '.eq()' | ||
- **[breaking]** - remove `.json(0)` shorthand - use `.json()[0]` | ||
- **[breaking]** - remove `.tagger()` - use .compute('tagger') | ||
- **[breaking]** - remove `.export()` -> .load() - use .json() -> nlp(json) | ||
- **[breaking]** - remove `nlp.clone()` | ||
- **[breaking]** - remove `.join()` *deprecated* | ||
- **[breaking]** - remove `.lists()` *deprecated* | ||
- **[breaking]** - remove `.segment()` *deprecated* | ||
- **[breaking]** - remove `.sententences().toParticiple()` & `.verbs().toParticiple()` | ||
- **[breaking]** - remove `.nouns().toPossessive()` & `.nouns().hasPlural()` | ||
- **[breaking]** - remove array support in match methods - (use `.match().match()` instead) | ||
- **[breaking]** - refactor `.out('freq')` output format - (uses `.compute('freq').terms().unique().json()` instead) | ||
- **[breaking]** - change `.json()` result format for subsets | ||
- **[change]** merge re-used capture-group names in one match | ||
- **[change]** drop support for undocumented empty '.split()' methods - which used to split the parent | ||
- **[change]** subtle changes to `.text('fmt')` formats | ||
- **[change]** @hasContraction is no-longer secretly-greedy. use `@hasContraction{2}` | ||
- **[change]** `.and()` now does a set 'union' operation of results (no overlaps) | ||
- **[change]** bestTag is now `.compute('tagRank')` | ||
- **[change]** `.sort()` is no longer in-place (its now immutable) | ||
- **[change]** drop undocumented options param to `.replaceWith()` method | ||
- **[change]** add match-group as 2nd param to split methods | ||
- **[change]** remove #FutureTense tag - which is not really a thing in english | ||
- **[change]** `.unique()` no-longer mutates parent | ||
- **[change]** `.normalize()` inputs cleanup | ||
- **[change]** drop agreement parameters in .numbers() methods | ||
- **[change]** - less-magical money parsing - `nlp('50 cents').money().get()` is no-longer `0.5` | ||
- **[change]** - .find() does not return undefined on an empty result anymore | ||
- **[change]** - fuzzy matches must now be wrapped in tildes, like `~this~` | ||
- **[new]** `.union()`, .intersection(), .difference() and .complement() methods | ||
- **[new]** `.confidence()` method - approximate tagging confidence score for arbitrary selections | ||
- **[new]** `.settle()` - remove overlaps in matches | ||
- **[new]** `.isDoc()` - helper-method for comparing two views | ||
- **[new]** `.none()` - helper-method for returning an empty view of the document | ||
- **[new]** `.toView()` method - drop back to a normal Class instance | ||
- **[new]** `.grow()` `.growLeft()` and `.growRight()` methods | ||
- **[new]** add punctuation match support via pre/post params | ||
- **[new]** add ambiguous empty .map() state as 2nd param | ||
#### 13.11.3 [June 2021] | ||
@@ -17,0 +61,0 @@ |
123
package.json
@@ -5,19 +5,43 @@ { | ||
"description": "modest natural language processing", | ||
"version": "13.11.4", | ||
"main": "./builds/compromise.js", | ||
"unpkg": "./builds/compromise.min.js", | ||
"module": "./builds/compromise.mjs", | ||
"type": "commonjs", | ||
"types": "types/index.d.ts", | ||
"version": "14.0.0", | ||
"main": "./src/index.js", | ||
"unpkg": "./builds/compromise.js", | ||
"type": "module", | ||
"types": "types/three.d.ts", | ||
"sideEffects": false, | ||
"exports": { | ||
".": { | ||
"require": "./builds/compromise.js", | ||
"import": "./builds/compromise.mjs", | ||
"default": "./builds/compromise.js" | ||
"import": "./src/three.js", | ||
"require": "./builds/three/compromise-three.cjs" | ||
}, | ||
"./tokenize": { | ||
"default": "./builds/compromise-tokenize.js" | ||
"import": "./src/one.js", | ||
"require": "./builds/one/compromise-one.cjs" | ||
}, | ||
"./one": { | ||
"import": "./src/one.js", | ||
"require": "./builds/one/compromise-one.cjs" | ||
}, | ||
"./two": { | ||
"import": "./src/two.js", | ||
"require": "./builds/two/compromise-two.cjs" | ||
}, | ||
"./three": { | ||
"import": "./src/three.js", | ||
"require": "./builds/three/compromise-three.cjs" | ||
} | ||
}, | ||
"typesVersions": { | ||
"*": { | ||
"one": [ | ||
"types/one.d.ts" | ||
], | ||
"two": [ | ||
"types/two.d.ts" | ||
], | ||
"three": [ | ||
"types/three.d.ts" | ||
] | ||
} | ||
}, | ||
"repository": { | ||
@@ -28,39 +52,31 @@ "type": "git", | ||
"homepage": "https://github.com/spencermountain/compromise", | ||
"browserslist": [ | ||
"defaults", | ||
"not IE 11", | ||
"maintained node versions" | ||
], | ||
"engines": { | ||
"node": ">=8.0.0" | ||
"node": ">=12.0.0" | ||
}, | ||
"scripts": { | ||
"build": "node ./scripts/build && rollup -c --silent && npm run test:smoke --silent", | ||
"pack": "node ./scripts/build/pack.js", | ||
"test": "node ./scripts/test/index.js ", | ||
"testb": "npm run test:smoke && TESTENV=prod node ./scripts/test/index.js", | ||
"test:smoke": "node \"./scripts/test/smoke-test/\" | tap-dancer", | ||
"test:spec": "tape \"./tests/**/*.test.js\" | tap-spec", | ||
"test:types": "ts-node ./scripts/test/types.ts | tap-dancer", | ||
"test:stress": "node ./scripts/test/stress.js", | ||
"test:coverage": "nyc -r text-summary -n 'src/**/*' -n 'plugins/**/*' npm run test", | ||
"coverage:html": "nyc --reporter=html tape \"./tests/**/*.test.js\" | tap-dancer --color always", | ||
"coverage": "nyc -r lcov -n 'src/**/*' -n 'plugins/**/*' npm run test", | ||
"build": "npm run version && rollup -c --silent", | ||
"watch": "amble ./scratch.js", | ||
"pack": "node ./scripts/pack.js", | ||
"version": "node ./scripts/version.js", | ||
"test": "tape \"./tests/**/*.test.js\" | tap-dancer", | ||
"testb": "npm run test:smoke && TESTENV=prod npm run test", | ||
"test:one": "tape \"./tests/one/**/*.test.js\" | tap-dancer", | ||
"test:two": "tape \"./tests/two/**/*.test.js\" | tap-dancer", | ||
"test:three": "tape \"./tests/three/**/*.test.js\" | tap-dancer", | ||
"test:smoke": "tape \"./scripts/test/smoke.test.js\" | tap-dancer", | ||
"test:plugins": "tape \"./plugins/**/tests/**/*.test.js\" | tap-dancer", | ||
"debug": "node ./scripts/debug.js", | ||
"match": "node ./scripts/match.js", | ||
"coverage": "c8 -r lcov -n 'src/**/*' -n 'plugins/**/*' npm run test", | ||
"codecov": "npm run coverage && codecov -t 15039ad1-b495-48cd-b4a0-bcf124c9b318", | ||
"perf": "node ./scripts/perf/index.js", | ||
"perf:build": "TESTENV=prod node ./scripts/perf/index.js", | ||
"perf:versions": "node ./scripts/perf/versions.js", | ||
"flame": "clinic flame -- node ./scripts/perf/flame", | ||
"lint": "eslint ./src/ && eslint ./plugins/**/src/", | ||
"watch": "amble ./scratch.js", | ||
"build:all": "node ./scripts/build/build-all.js && npm run build --silent", | ||
"plugins": "node ./scripts/plugin-check.js --silent", | ||
"plugins:install": "node ./scripts/plugins.js npm install", | ||
"lint": "eslint ./src/**/* && eslint ./plugins/**/src/*", | ||
"plugins:ci": "node ./scripts/plugins.js npm ci", | ||
"plugins:build": "node ./scripts/plugins.js npm run build", | ||
"demo": "python -m SimpleHTTPServer 8888" | ||
"plugins:build": "node ./scripts/plugins.js npm run build" | ||
}, | ||
"files": [ | ||
"builds/", | ||
"types/index.d.ts" | ||
"types/", | ||
"src/" | ||
], | ||
@@ -79,22 +95,20 @@ "keywords": [ | ||
"dependencies": { | ||
"efrt-unpack": "2.2.0" | ||
"efrt": "2.5.0", | ||
"grad-school": "0.0.4", | ||
"suffix-thumb": "4.0.2" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "7.14.6", | ||
"@babel/preset-env": "7.14.5", | ||
"@rollup/plugin-alias": "3.1.2", | ||
"@rollup/plugin-commonjs": "19.0.0", | ||
"@rollup/plugin-json": "4.1.0", | ||
"@rollup/plugin-node-resolve": "13.0.0", | ||
"@rollup/plugin-alias": "3.1.9", | ||
"@rollup/plugin-node-resolve": "13.1.3", | ||
"amble": "1.3.0", | ||
"codecov": "3.8.2", | ||
"efrt": "2.2.2", | ||
"nyc": "^15.1.0", | ||
"rollup": "2.52.2", | ||
"rollup-plugin-babel": "4.4.0", | ||
"codecov": "3.8.3", | ||
"eslint": "8.11.0", | ||
"eslint-plugin-regexp": "1.6.0", | ||
"nlp-corpus": "^4.2.0", | ||
"rollup": "2.70.1", | ||
"rollup-plugin-filesize-check": "0.0.1", | ||
"rollup-plugin-terser": "7.0.2", | ||
"shelljs": "0.8.4", | ||
"tap-dancer": "0.3.2", | ||
"tape": "5.2.2" | ||
"shelljs": "0.8.5", | ||
"tap-dancer": "0.3.4", | ||
"tape": "5.5.2" | ||
}, | ||
@@ -104,5 +118,6 @@ "eslintIgnore": [ | ||
"*.ts", | ||
"plugins/**/types/*.ts" | ||
"_old/**", | ||
"_tests/**" | ||
], | ||
"license": "MIT" | ||
} | ||
} |
1007
README.md
<div align="center"> | ||
<img height="15px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<div><b>compromise</b></div> | ||
@@ -33,21 +34,27 @@ <img src="https://user-images.githubusercontent.com/399657/68222691-6597f180-ffb9-11e9-8a32-a7f38aa8bded.png"/> | ||
<!-- spacer --> | ||
<img height="85px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<img height="25px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<div align="left"> | ||
isn't it weird how we can <i>write text</i>, but not parse it? | ||
<div align="left"> | ||
do you find it strange, how we struggle to parse text? | ||
<br/> | ||
<ul> | ||
<i>↬<sub>ᔐᖜ</sub>↬-</i> and how we can't get the information <i>back out</i>?⇬ | ||
<i>↬<sub>ᔐᖜ</sub>↬-</i> | ||
<br/> | ||
how <b>error-prone</b> and <b><i>tricky</i></b> the simplest things are? | ||
<div> | ||
<img height="45px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
</div> | ||
<sub>how easy text is to make, then how difficult it is <i>to use</i>?</sub> | ||
</ul> | ||
</div> | ||
<img height="55px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<img height="45px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<div align="center"> | ||
it's like we've agreed that | ||
<div align="right"> | ||
<sub >how it becomes</sub> | ||
<div> | ||
text is a dead-end. | ||
<sub>basically a dead-end</sub> | ||
<br/> | ||
<sub>for our information?</sub> | ||
</div> | ||
<sub>and the knowledge in it</sub> | ||
<br/> | ||
<sub>should not really be used.</sub> | ||
</div> | ||
@@ -59,7 +66,14 @@ | ||
<div align="left"> | ||
<img height="30px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/>compromise <a href="https://observablehq.com/@spencermountain/compromise-justification">tries its best</a> to parse text. | ||
</div> | ||
<img height="30px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/>compromise <a href="https://observablehq.com/@spencermountain/compromise-justification">tries its best</a> to turn text into data. | ||
<br/> | ||
<img height="30px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/>it makes limited and sensible decisions. | ||
<br/> | ||
<sub > | ||
<img height="15px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> it is not as smart as you'd think. | ||
</sub> | ||
<div align="left"> | ||
<img height="30px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<img height="45px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<!-- | ||
it is | ||
@@ -69,19 +83,39 @@ <a href="https://docs.compromise.cool/compromise-filesize">small, | ||
and often <i><a href="https://docs.compromise.cool/compromise-accuracy">good-enough</a></i>. | ||
<br/> | ||
<img height="30px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> it is not as smart as you'd think. | ||
<br/> | ||
<!-- spacer --> | ||
<!-- <img height="45px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
it is though - very open-ended, hackable, and open to engineering. --> | ||
</div> | ||
<br/> --> | ||
</div> | ||
<img height="30px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
```js | ||
import nlp from 'compromise' | ||
let doc = nlp('she sells seashells by the seashore.') | ||
doc.verbs().toPastTense() | ||
doc.text() | ||
// 'she sold seashells by the seashore.' | ||
``` | ||
<!-- spacer --> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<div align="center"> | ||
the idea is to be not fancy at all: | ||
</div> | ||
```js | ||
if (doc.has('simon says #Verb')) { | ||
return true | ||
} | ||
``` | ||
<!-- spacer --> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<img height="30px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<div align="center"> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221814-05ed1680-ffb8-11e9-8b6b-c7528d163871.png"/> | ||
</div> | ||
### .match(): | ||
interpret and match text: | ||
<div align="left"> | ||
select parts of the text: | ||
</div> | ||
@@ -93,9 +127,2 @@ ```js | ||
``` | ||
```js | ||
if (doc.has('simon says #Verb') === false) { | ||
return null | ||
} | ||
``` | ||
<div align="right"> | ||
@@ -107,54 +134,67 @@ <a href="https://docs.compromise.cool/compromise-match">match docs</a> | ||
</div> | ||
<!-- spacer --> | ||
<img height="30px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
### .verbs(): | ||
and get data: | ||
```js | ||
import plg from 'compromise-speech' | ||
nlp.extend(plg) | ||
conjugate and negate verbs in any tense: | ||
```js | ||
let doc = nlp('she sells seashells by the seashore.') | ||
doc.verbs().toPastTense() | ||
doc.text() | ||
// 'she sold seashells by the seashore.' | ||
let doc = nlp('Milwaukee has certainly had its share of visitors..') | ||
doc.compute('syllables') | ||
doc.places().json() | ||
/* | ||
[{ | ||
"text": "Milwaukee", | ||
"terms": [{ | ||
"normal": "milwaukee", | ||
"syllables": ["mil", "wau", "kee"] | ||
}] | ||
}] | ||
*/ | ||
``` | ||
<div align="right"> | ||
<a href="https://docs.compromise.cool/verbs">verb docs</a> | ||
<a href="https://docs.compromise.cool/compromise-json">json docs</a> | ||
</div> | ||
<div align="center"> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221824-09809d80-ffb8-11e9-9ef0-6ed3574b0ce8.png"/> | ||
</div> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221814-05ed1680-ffb8-11e9-8b6b-c7528d163871.png"/> | ||
</div> | ||
<!-- spacer --> | ||
<img height="30px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
### .nouns(): | ||
quickly flip between *parsed* and *unparsed* forms: | ||
play between plural, singular and possessive forms: | ||
```js | ||
let doc = nlp('the purple dinosaur') | ||
doc.nouns().toPlural() | ||
doc.text() | ||
// 'the purple dinosaurs' | ||
let doc = nlp('soft and yielding like a nerf ball') | ||
doc.out({ | ||
'#Adjective': (m) => `<i>${m.text()}</i>` | ||
}) | ||
// '<i>soft</i> and <i>yielding</i> like a nerf ball' | ||
``` | ||
<div align="right"> | ||
<a href="https://docs.compromise.cool/nouns">noun docs</a> | ||
<a href="https://docs.compromise.cool/compromise-output">output docs</a> | ||
</div> | ||
<div align="center"> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221731-e8b84800-ffb7-11e9-8453-6395e0e903fa.png"/> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221837-0d142480-ffb8-11e9-9d30-90669f1b897c.png"/> | ||
</div> | ||
<!-- spacer --> | ||
<img height="30px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
### .numbers(): | ||
avoid the problems of brittle parsers: | ||
interpret plain-text numbers | ||
```js | ||
nlp.extend(require('compromise-numbers')) | ||
let doc = nlp("we're not gonna take it..") | ||
let doc = nlp('ninety five thousand and fifty two') | ||
doc.numbers().add(2) | ||
doc.text() | ||
// 'ninety five thousand and fifty four' | ||
doc.has('gonna') // true | ||
doc.has('going to') // true (implicit) | ||
// transform | ||
doc.contractions().expand() | ||
dox.text() | ||
// 'we are not going to take it..' | ||
``` | ||
<div align="right"> | ||
<a href="https://docs.compromise.cool/compromise-values">number docs</a> | ||
<a href="https://docs.compromise.cool/compromise-contractions">contraction docs</a> | ||
</div> | ||
@@ -164,57 +204,44 @@ <div align="center"> | ||
</div> | ||
<!-- spacer --> | ||
<img height="30" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
### .topics(): | ||
names/places/orgs, tldr: | ||
and whip stuff around like it's data: | ||
```js | ||
let doc = nlp(buddyHolly) | ||
doc.people().if('mary').json() | ||
// [{text:'Mary Tyler Moore'}] | ||
let doc = nlp(freshPrince) | ||
doc.places().first().text() | ||
// 'West Phillidelphia' | ||
doc = nlp('the opera about richard nixon visiting china') | ||
doc.topics().json() | ||
// [ | ||
// { text: 'richard nixon' }, | ||
// { text: 'china' } | ||
// ] | ||
let doc = nlp('ninety five thousand and fifty two') | ||
doc.numbers().add(20) | ||
doc.text() | ||
// 'ninety five thousand and seventy two' | ||
``` | ||
<div align="right"> | ||
<a href="https://docs.compromise.cool/topics-named-entity-recognition">topics docs</a> | ||
<a href="https://docs.compromise.cool/compromise-values">number docs</a> | ||
</div> | ||
<div align="center"> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221632-b9094000-ffb7-11e9-99e0-b48edd6cdf8a.png"/> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221837-0d142480-ffb8-11e9-9d30-90669f1b897c.png"/> | ||
</div> | ||
<!-- spacer --> | ||
<img height="30" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
### .contractions(): | ||
handle implicit terms: | ||
<sub>-because it actually is-</sub> | ||
```js | ||
let doc = nlp("we're not gonna take it, no we ain't gonna take it.") | ||
// match an implicit term | ||
doc.has('going') // true | ||
// transform | ||
doc.contractions().expand() | ||
dox.text() | ||
// 'we are not going to take it, no we are not going to take it.' | ||
let doc = nlp('the purple dinosaur') | ||
doc.nouns().toPlural() | ||
doc.text() | ||
// 'the purple dinosaurs' | ||
``` | ||
<div align="right"> | ||
<a href="https://docs.compromise.cool/compromise-contractions">contraction docs</a> | ||
<a href="https://docs.compromise.cool/nouns">noun docs</a> | ||
</div> | ||
<div align="center"> | ||
<img src="https://user-images.githubusercontent.com/399657/68221731-e8b84800-ffb7-11e9-8453-6395e0e903fa.png"/> | ||
<!-- spacer --> | ||
<img height="30" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221731-e8b84800-ffb7-11e9-8453-6395e0e903fa.png"/> | ||
</div> | ||
<!-- spacer --> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
Use it on the client-side: | ||
@@ -224,6 +251,3 @@ | ||
<script src="https://unpkg.com/compromise"></script> | ||
<script src="https://unpkg.com/compromise-numbers"></script> | ||
<script> | ||
nlp.extend(compromiseNumbers) | ||
var doc = nlp('two bottles of beer') | ||
@@ -236,3 +260,3 @@ doc.numbers().minus(1) | ||
as an es-module: | ||
or likewise: | ||
@@ -246,7 +270,12 @@ ```typescript | ||
``` | ||
<img height="75px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<!-- | ||
bragging graphs | ||
--> | ||
<!-- spacer --> | ||
<img height="30" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
compromise is **180kb** (minified): | ||
compromise is **~200kb** (minified): | ||
@@ -279,162 +308,181 @@ <div align="center"> | ||
<!-- spacer --> | ||
<!-- <img height="25px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> --> | ||
<div align="center"> | ||
<img src="https://user-images.githubusercontent.com/399657/68221814-05ed1680-ffb8-11e9-8b6b-c7528d163871.png"/> | ||
</div> | ||
<img height="75px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
### .extend(): | ||
decide how words get interpreted: | ||
<!-- | ||
one/two/three parts | ||
--> | ||
<p align="left"> | ||
<sub>okay -</sub> | ||
<h1> | ||
<code>compromise/one</code> | ||
</h1> | ||
<p align="center">A <code>tokenizer</code> of words, sentences, and punctuation.</p> | ||
<img height="15px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<p> | ||
```js | ||
let myWords = { | ||
kermit: 'FirstName', | ||
fozzie: 'FirstName', | ||
} | ||
let doc = nlp(muppetText, myWords) | ||
import nlp from 'compromise/one' | ||
let doc = nlp("Wayne's World, party time") | ||
let data = doc.json() | ||
/* [{ | ||
normal:"wayne's world party time", | ||
terms:[{ text: "Wayne's", normal: "wayne" }, | ||
... | ||
] | ||
}] | ||
*/ | ||
``` | ||
or make heavier changes with a [compromise-plugin](https://observablehq.com/@spencermountain/compromise-plugins). | ||
<div align="right"> | ||
<a href="https://docs.compromise.cool/compromise-tokenization">tokenizer docs</a> | ||
</div> | ||
```js | ||
const nlp = require('compromise') | ||
<b>compromise/one</b> splits your text up, wraps it in a handy API, | ||
<ul> | ||
<sub>and does nothing else -</sub> | ||
</ul> | ||
nlp.extend((Doc, world) => { | ||
// add new tags | ||
world.addTags({ | ||
Character: { | ||
isA: 'Person', | ||
notA: 'Adjective', | ||
}, | ||
}) | ||
<img height="25px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
// add or change words in the lexicon | ||
world.addWords({ | ||
kermit: 'Character', | ||
gonzo: 'Character', | ||
}) | ||
<b>/one</b> is quick - most sentences take a 10th of a millisecond. | ||
// add methods to run after the tagger | ||
world.postProcess(doc => { | ||
doc.match('light the lights').tag('#Verb . #Plural') | ||
}) | ||
It can do <b>~1mb</b> of text a second - or 10 wikipedia pages. | ||
// add a whole new method | ||
Doc.prototype.kermitVoice = function () { | ||
this.sentences().prepend('well,') | ||
this.match('i [(am|was)]').prepend('um,') | ||
return this | ||
} | ||
}) | ||
``` | ||
<i>Infinite jest</i> is takes 3s. | ||
<div align="right"> | ||
<a href="https://docs.compromise.cool/compromise-plugins">.extend() docs</a> | ||
You can also paralellize, or stream text to it with <a href="https://github.com/spencermountain/compromise/tree/master/plugins/speed">compromise-speed</a>. | ||
</div> | ||
<div align="center"> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221848-11404200-ffb8-11e9-90cd-3adee8d8564f.png"/> | ||
</div> | ||
<!-- spacer --> | ||
<div > | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
</div> | ||
<img height="60px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
### Docs: | ||
<!-- two --> | ||
<p align="center"> | ||
<h1 align="left"> | ||
<code>compromise/two</code> | ||
</h1> | ||
<p align="center">A <code>part-of-speech</code> tagger, and grammar-interpreter.</p> | ||
<img height="15px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<p> | ||
##### gentle introduction: | ||
```js | ||
import nlp from 'compromise/two' | ||
- **[#1) Input → output](https://docs.compromise.cool/tutorial-1)** | ||
- **[#2) Match & transform](https://docs.compromise.cool/compromise-tutorial-2)** | ||
- **[#3) Making a chat-bot](https://docs.compromise.cool/compromise-making-a-bot)** | ||
<!-- * **[Tutorial #4]()** - Making a plugin --> | ||
let doc = nlp("Wayne's World, party time") | ||
let str = doc.match('#Possessive #Noun').text() | ||
// "Wayne's World" | ||
``` | ||
<div > | ||
<img height="25px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<div align="right"> | ||
<a href="https://docs.compromise.cool/compromise-tagger">tagger docs</a> | ||
</div> | ||
##### Documentation: | ||
<p> | ||
<img height="25px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
</p> | ||
<b>compromise/two</b> automatically calculates the very basic grammar of each word. | ||
| Concepts | API | Plugins | | ||
| ------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------: | -------------------------------------------------------------------------------------: | | ||
| [Accuracy](https://observablehq.com/@spencermountain/compromise-accuracy) | [Accessors](https://observablehq.com/@spencermountain/compromise-accessors) | [Adjectives](https://observablehq.com/@spencermountain/compromise-adjectives) | | ||
| [Caching](https://observablehq.com/@spencermountain/compromise-cache) | [Constructor-methods](https://observablehq.com/@spencermountain/compromise-constructor-methods) | [Dates](https://observablehq.com/@spencermountain/compromise-dates) | | ||
| [Case](https://observablehq.com/@spencermountain/compromise-case) | [Contractions](https://observablehq.com/@spencermountain/compromise-contractions) | [Export](https://observablehq.com/@spencermountain/compromise-export) | | ||
| [Filesize](https://observablehq.com/@spencermountain/compromise-filesize) | [Insert](https://observablehq.com/@spencermountain/compromise-insert) | [Hash](https://observablehq.com/@spencermountain/compromise-hash) | | ||
| [Internals](https://observablehq.com/@spencermountain/compromise-internals) | [Json](https://observablehq.com/@spencermountain/compromise-json) | [Html](https://observablehq.com/@spencermountain/compromise-html) | | ||
| [Justification](https://observablehq.com/@spencermountain/compromise-justification) | [Lists](https://observablehq.com/@spencermountain/compromise-lists) | [Keypress](https://observablehq.com/@spencermountain/compromise-keypress) | | ||
| [Lexicon](https://observablehq.com/@spencermountain/compromise-lexicon) | [Loops](https://observablehq.com/@spencermountain/compromise-loops) | [Ngrams](https://observablehq.com/@spencermountain/compromise-ngram) | | ||
| [Match-syntax](https://observablehq.com/@spencermountain/compromise-match-syntax) | [Match](https://observablehq.com/@spencermountain/compromise-match) | [Numbers](https://observablehq.com/@spencermountain/compromise-values) | | ||
| [Performance](https://observablehq.com/@spencermountain/compromise-performance) | [Nouns](https://observablehq.com/@spencermountain/nouns) | [Paragraphs](https://observablehq.com/@spencermountain/compromise-paragraphs) | | ||
| [Plugins](https://observablehq.com/@spencermountain/compromise-plugins) | [Output](https://observablehq.com/@spencermountain/compromise-output) | [Scan](https://observablehq.com/@spencermountain/compromise-scan) | | ||
| [Projects](https://observablehq.com/@spencermountain/compromise-projects) | [Selections](https://observablehq.com/@spencermountain/compromise-selections) | [Sentences](https://observablehq.com/@spencermountain/compromise-sentences) | | ||
| [Tagger](https://observablehq.com/@spencermountain/compromise-tagger) | [Sorting](https://observablehq.com/@spencermountain/compromise-sorting) | [Syllables](https://observablehq.com/@spencermountain/compromise-syllables) | | ||
| [Tags](https://observablehq.com/@spencermountain/compromise-tags) | [Split](https://observablehq.com/@spencermountain/compromise-split) | [Pronounce](https://observablehq.com/@spencermountain/compromise-pronounce) | | | ||
| [Tokenization](https://observablehq.com/@spencermountain/compromise-tokenization) | [Text](https://observablehq.com/@spencermountain/compromise-text) | [Strict](https://observablehq.com/@spencermountain/compromise-strict) | | ||
| [Named-Entities](https://observablehq.com/@spencermountain/compromise-topics) | [Utils](https://observablehq.com/@spencermountain/compromise-utils) | [Penn-tags](https://observablehq.com/@spencermountain/compromise-penn-tags) | | ||
| [Whitespace](https://observablehq.com/@spencermountain/compromise-whitespace) | [Verbs](https://observablehq.com/@spencermountain/verbs) | [Typeahead](https://observablehq.com/@spencermountain/compromise/compromise-typeahead) | | ||
| [World data](https://observablehq.com/@spencermountain/compromise-world) | [Normalization](https://observablehq.com/@spencermountain/compromise/Normalization) | | | ||
| [Fuzzy-matching](https://observablehq.com/@spencermountain/compromise-fuzzy-matching) | [Typescript](https://observablehq.com/@spencermountain/compromise-typescript) | | | ||
<sub>this is more useful than people sometimes realize.</sub> | ||
##### Talks: | ||
Light grammar helps you write cleaner templates, and get closer to the information. | ||
- **[Language as an Interface](https://www.youtube.com/watch?v=WuPVS2tCg8s)** - by Spencer Kelly | ||
- **[Coding Chat Bots](https://www.youtube.com/watch?v=c_hmwFwvO0U)** - by KahWee Teng | ||
- **[On Typing and data](https://vimeo.com/496095722)** - by Spencer Kelly | ||
<!-- Part-of-speech tagging is profoundly-difficult task to get 100% on. It is also a profoundly easy task to get 85% on. --> | ||
##### Articles: | ||
- **[Geocoding Social Conversations with NLP and JavaScript](http://compromise.cool)** - by Microsoft | ||
- **[Microservice Recipe](https://eventn.com/recipes/text-parsing-with-nlp-compromise)** - by Eventn | ||
- **[Adventure Game Sentence Parsing with Compromise](https://killalldefects.com/2020/02/20/adventure-game-sentence-parsing-with-compromise/)** | ||
- **[Building Text-Based Games](https://killalldefects.com/2019/09/24/building-text-based-games-with-compromise-nlp/)** - by Matt Eland | ||
- **[Fun with javascript in BigQuery](https://medium.com/@hoffa/new-in-bigquery-persistent-udfs-c9ea4100fd83#6e09)** - by Felipe Hoffa | ||
- **[Natural Language Processing... in the Browser?](https://dev.to/charlesdlandau/natural-language-processing-in-the-browser-52hj)** - by Charles Landau | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
##### Some fun Applications: | ||
- **[Chat dialogue framework](http://superscriptjs.com/)** - by Rob Ellis | ||
- **[Automated Bechdel Test](https://github.com/guardian/bechdel-test)** - by The Guardian | ||
- **[Story generation framework](https://perchance.org/welcome)** - by Jose Phrocca | ||
- **[Tumbler blog of lists](https://leanstooneside.tumblr.com/)** - horse-ebooks-like lists - by Michael Paulukonis | ||
- **[Video Editing from Transcription](https://newtheory.io/)** - by New Theory | ||
- **[Browser extension Fact-checking](https://github.com/AlexanderKidd/FactoidL)** - by Alexander Kidd | ||
- **[Siri shortcut](https://routinehub.co/shortcut/3260)** - by Michael Byrns | ||
- **[Amazon skill](https://github.com/tajddin/voiceplay)** - by Tajddin Maghni | ||
- **[Tasking Slack-bot](https://github.com/kevinsuh/toki)** - by Kevin Suh | ||
[[see more]](https://observablehq.com/@spencermountain/compromise-projects) | ||
compromise has <b>83 tags</b>, arranged in <a href="https://observablehq.com/@spencermountain/compromise-tags">a handsome graph</a>. | ||
<!-- spacer --> | ||
<div align="center"> | ||
<img height="25px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<hr/> | ||
<b>#FirstName</b> → <b>#Person</b> → <b>#ProperNoun</b> → <b>#Noun</b> | ||
you can see the grammar of each word by running `doc.debug()` | ||
you can see the reasoning for each tag with `nlp.verbose('tagger')`. | ||
if you prefer <a href="https://www.ling.upenn.edu/courses/Fall_2003/ling001/penn_treebank_pos.html"><i>Penn tags</i></a>, you can derive them with: | ||
```js | ||
let doc = nlp('welcome thrillho') | ||
doc.compute('penn') | ||
doc.json() | ||
``` | ||
<img height="60px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<!-- three --> | ||
<p align="center"> | ||
<h1 align="left"> | ||
<code>compromise/three</code> | ||
</h1> | ||
<p align="center"><code>Phrase</code> and sentence tooling.</p> | ||
<img height="15px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<p> | ||
```js | ||
import nlp from 'compromise/three' | ||
let doc = nlp("Wayne's World, party time") | ||
let str = doc.people().normalize().text() | ||
// "wayne" | ||
``` | ||
<div align="right"> | ||
<a href="https://docs.compromise.cool/compromise-selections">selection docs</a> | ||
</div> | ||
<div align="center"> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221632-b9094000-ffb7-11e9-99e0-b48edd6cdf8a.png"/> | ||
</div> | ||
### API: | ||
##### Constructor | ||
<b>compromise/three</b> is a set of tooling to <i>zoom into</i> and operate on parts of a text. | ||
_(these methods are on the `nlp` object)_ | ||
`.numbers()` grabs all the numbers in a document, for example - and extends it with new methods, like `.subtract()`. | ||
- **[.tokenize()](https://observablehq.com/@spencermountain/compromise-tokenization)** - parse text without running POS-tagging | ||
- **[.extend()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - mix in a compromise-plugin | ||
- **[.fromJSON()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - load a compromise object from `.json()` result | ||
- **[.verbose()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - log our decision-making for debugging | ||
- **[.version()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - current semver version of the library | ||
- **[.world()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - grab all current linguistic data | ||
- **[.parseMatch()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - pre-parse any match statements for faster lookups | ||
When you have a phrase, or group of words, you can see additional metadata about it with `.json()` | ||
```js | ||
let doc = nlp("four out of five dentists") | ||
console.log(doc.fractions().json()) | ||
/*[{ | ||
text: 'four out of five', | ||
terms: [ [Object], [Object], [Object], [Object] ], | ||
fraction: { numerator: 4, denominator: 5, decimal: 0.8 } | ||
} | ||
]*/ | ||
``` | ||
```js | ||
let doc = nlp("$4.09CAD") | ||
doc.money().json() | ||
/*[{ | ||
text: '$4.09CAD', | ||
terms: [ [Object] ], | ||
number: { prefix: '$', num: 4.09, suffix: 'cad'} | ||
} | ||
]*/ | ||
``` | ||
<img height="80px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
## API | ||
### Compromise/one | ||
##### Output | ||
- **[.text()](https://observablehq.com/@spencermountain/compromise-text)** - return the document as text | ||
- **[.json()](https://observablehq.com/@spencermountain/compromise-json)** - return the document as data | ||
- **[.debug()](https://observablehq.com/@spencermountain/compromise-output)** - pretty-print the interpreted document | ||
- **[.out()](https://observablehq.com/@spencermountain/compromise-output)** - a named or custom output | ||
- **[.html({})](https://observablehq.com/@spencermountain/compromise-html)** - output custom html tags for matches | ||
- **[.wrap({})](https://observablehq.com/@spencermountain/compromise-output)** - produce custom output for document matches | ||
##### Utils | ||
- **[.all()](https://observablehq.com/@spencermountain/compromise-utils)** - return the whole original document ('zoom out') | ||
- **[.found](https://observablehq.com/@spencermountain/compromise-utils)** _[getter]_ - is this document empty? | ||
- **[.parent()](https://observablehq.com/@spencermountain/compromise-utils)** - return the previous result | ||
- **[.parents()](https://observablehq.com/@spencermountain/compromise-utils)** - return all of the previous results | ||
- **[.tagger()](https://observablehq.com/@spencermountain/compromise-tagger)** - (re-)run the part-of-speech tagger on this document | ||
- **[.wordCount()](https://observablehq.com/@spencermountain/compromise-utils)** - count the # of terms in the document | ||
- **[.docs](https://observablehq.com/@spencermountain/compromise-utils)** _[getter]_ get term objects as json | ||
- **[.length](https://observablehq.com/@spencermountain/compromise-utils)** _[getter]_ - count the # of characters in the document (string length) | ||
- **[.isView](https://observablehq.com/@spencermountain/compromise-utils)** _[getter]_ - identify a compromise object | ||
- **[.compute()](https://observablehq.com/@spencermountain/compromise-compute)** - run a named analysis on the document | ||
- **[.clone()](https://observablehq.com/@spencermountain/compromise-utils)** - deep-copy the document, so that no references remain | ||
- **[.termList()](https://observablehq.com/@spencermountain/compromise-accessors)** - return a flat list of all Term objects in match | ||
- **[.cache({})](https://observablehq.com/@spencermountain/compromise-cache)** - freeze the current state of the document, for speed-purposes | ||
@@ -445,2 +493,4 @@ - **[.uncache()](https://observablehq.com/@spencermountain/compromise-cache)** - un-freezes the current state of the document, so it may be transformed | ||
- **[.all()](https://observablehq.com/@spencermountain/compromise-utils)** - return the whole original document ('zoom out') | ||
- **[.terms()](https://observablehq.com/@spencermountain/compromise-selections)** - split-up results by each individual term | ||
- **[.first(n)](https://observablehq.com/@spencermountain/compromise-accessors)** - use only the first result(s) | ||
@@ -450,12 +500,12 @@ - **[.last(n)](https://observablehq.com/@spencermountain/compromise-accessors)** - use only the last result(s) | ||
- **[.eq(n)](https://observablehq.com/@spencermountain/compromise-accessors)** - use only the nth result | ||
- **[.terms()](https://observablehq.com/@spencermountain/compromise-selections)** - split-up results by each individual term | ||
- **[.firstTerms()](https://observablehq.com/@spencermountain/compromise-accessors)** - get the first word in each match | ||
- **[.lastTerms()](https://observablehq.com/@spencermountain/compromise-accessors)** - get the end word in each match | ||
- **[.sentences()](https://observablehq.com/@spencermountain/compromise-accessors)** - get the whole sentence for each match | ||
- **[.termList()](https://observablehq.com/@spencermountain/compromise-accessors)** - return a flat list of all Term objects in match | ||
- **[.groups('')](https://observablehq.com/@spencermountain/compromise-accessors)** - grab any named capture-groups from a match | ||
- **[.fullSentences()](https://observablehq.com/@spencermountain/compromise-accessors)** - get the whole sentence for each match | ||
- **[.groups()](https://observablehq.com/@spencermountain/compromise-accessors)** - grab any named capture-groups from a match | ||
- **[.wordCount()](https://observablehq.com/@spencermountain/compromise-utils)** - count the # of terms in the document | ||
- **[.confidence()](https://observablehq.com/@spencermountain/compromise-utils)** - an average score for pos tag interpretations | ||
##### Match | ||
_(all match methods use the [match-syntax](https://docs.compromise.cool/compromise-match-syntax).)_ | ||
_(match methods use the [match-syntax](https://docs.compromise.cool/compromise-match-syntax).)_ | ||
@@ -468,8 +518,24 @@ - **[.match('')](https://observablehq.com/@spencermountain/compromise-match)** - return a new Doc, with this one as a parent | ||
- **[.has('')](https://observablehq.com/@spencermountain/compromise-match)** - Return a boolean if this match exists | ||
- **[.lookBehind('')](https://observablehq.com/@spencermountain/compromise-match)** - search through earlier terms, in the sentence | ||
- **[.lookAhead('')](https://observablehq.com/@spencermountain/compromise-match)** - search through following terms, in the sentence | ||
- **[.before('')](https://observablehq.com/@spencermountain/compromise-match)** - return all terms before a match, in each phrase | ||
- **[.after('')](https://observablehq.com/@spencermountain/compromise-match)** - return all terms after a match, in each phrase | ||
- **[.union()](https://observablehq.com/@spencermountain/compromise-pointers)** - return combined matches without duplicates | ||
- **[.intersection()](https://observablehq.com/@spencermountain/compromise-pointers)** - return only duplicate matches | ||
- **[.complement()](https://observablehq.com/@spencermountain/compromise-pointers)** - get everything not in another match | ||
- **[.settle()](https://observablehq.com/@spencermountain/compromise-pointers)** - remove overlaps from matches | ||
- **[.growRight('')](https://observablehq.com/@spencermountain/compromise-match)** - add any matching terms immediately after each match | ||
- **[.growLeft('')](https://observablehq.com/@spencermountain/compromise-match)** - add any matching terms immediately before each match | ||
- **[.grow('')](https://observablehq.com/@spencermountain/compromise-match)** - add any matching terms before or after each match | ||
- **[.splitOn('')](https://observablehq.com/@spencermountain/compromise-split)** - return a Document with three parts for every match ('splitOn') | ||
- **[.splitBefore('')](https://observablehq.com/@spencermountain/compromise-split)** - partition a phrase before each matching segment | ||
- **[.splitAfter('')](https://observablehq.com/@spencermountain/compromise-split)** - partition a phrase after each matching segment | ||
- **[.lookup([])](https://observablehq.com/@spencermountain/compromise-match)** - quick find for an array of string matches | ||
- **[.autofill()](https://observablehq.com/@spencermountain/compromise-typeahead)** - create type-ahead assumptions on the document | ||
##### Tag | ||
- **[.tag('')](https://observablehq.com/@spencermountain/compromise-tagger)** - Give all terms the given tag | ||
- **[.tagSafe('')](https://observablehq.com/@spencermountain/compromise-tagger)** - Only apply tag to terms if it is consistent with current tags | ||
- **[.unTag('')](https://observablehq.com/@spencermountain/compromise-tagger)** - Remove this term from the given terms | ||
- **[.canBe('')](https://observablehq.com/@spencermountain/compromise-tagger)** - return only the terms that can be this tag | ||
##### Case | ||
@@ -492,9 +558,2 @@ | ||
##### Tag | ||
- **[.tag('')](https://observablehq.com/@spencermountain/compromise-tagger)** - Give all terms the given tag | ||
- **[.tagSafe('')](https://observablehq.com/@spencermountain/compromise-tagger)** - Only apply tag to terms if it is consistent with current tags | ||
- **[.unTag('')](https://observablehq.com/@spencermountain/compromise-tagger)** - Remove this term from the given terms | ||
- **[.canBe('')](https://observablehq.com/@spencermountain/compromise-tagger)** - return only the terms that can be this tag | ||
##### Loops | ||
@@ -513,6 +572,7 @@ | ||
- **[.replaceWith(replace)](https://observablehq.com/@spencermountain/compromise-insert)** - substitute-in new text | ||
- **[.delete()](https://observablehq.com/@spencermountain/compromise-insert)** - fully remove these terms from the document | ||
- **[.append(str)](https://observablehq.com/@spencermountain/compromise-insert)** - add these new terms to the end (insertAfter) | ||
- **[.prepend(str)](https://observablehq.com/@spencermountain/compromise-insert)** - add these new terms to the front (insertBefore) | ||
- **[.remove()](https://observablehq.com/@spencermountain/compromise-insert)** - fully remove these terms from the document | ||
- **[.insertBefore(str)](https://observablehq.com/@spencermountain/compromise-insert)** - add these new terms to the front of each match (prepend) | ||
- **[.insertAfter(str)](https://observablehq.com/@spencermountain/compromise-insert)** - add these new terms to the end of each match (append) | ||
- **[.concat()](https://observablehq.com/@spencermountain/compromise-insert)** - add these new things to the end | ||
- **[.swap(fromLemma, toLemma)](https://observablehq.com/@spencermountain/compromise-insert)** - smart replace of root-words,using proper conjugation | ||
@@ -525,60 +585,55 @@ ##### Transform | ||
- **[.unique()](https://observablehq.com/@spencermountain/compromise-sorting)** - remove any duplicate matches | ||
- **[.split('')](https://observablehq.com/@spencermountain/compromise-split)** - return a Document with three parts for every match ('splitOn') | ||
- **[.splitBefore('')](https://observablehq.com/@spencermountain/compromise-split)** - partition a phrase before each matching segment | ||
- **[.splitAfter('')](https://observablehq.com/@spencermountain/compromise-split)** - partition a phrase after each matching segment | ||
- **[.segment({})](https://observablehq.com/@spencermountain/compromise-split)** - split a document into labeled sections | ||
- **[.join('')](https://observablehq.com/@spencermountain/compromise-split)** - make all phrases into one phrase | ||
##### Output | ||
- **[.text('method')](https://observablehq.com/@spencermountain/compromise-text)** - return the document as text | ||
- **[.json({})](https://observablehq.com/@spencermountain/compromise-json)** - pull out desired metadata from the document | ||
- **[.out('array|offset|terms')](https://observablehq.com/@spencermountain/compromise-output)** - some named output formats (deprecated) | ||
- **[.debug()](https://observablehq.com/@spencermountain/compromise-output)** - pretty-print the current document and its tags | ||
##### Lib | ||
##### Selections | ||
_(these methods are on the main `nlp` object)_ | ||
- **[.clauses()](https://observablehq.com/@spencermountain/compromise-selections)** - split-up sentences into multi-term phrases | ||
- **[.hyphenated()](https://observablehq.com/@spencermountain/compromise-selections)** - all terms connected with a hyphen or dash like `'wash-out'` | ||
- **[.phoneNumbers()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'(939) 555-0113'` | ||
- **[.hashTags()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'#nlp'` | ||
- **[.emails()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'hi@compromise.cool'` | ||
- **[.emoticons()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `:)` | ||
- **[.emojis()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `💋` | ||
- **[.atMentions()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'@nlp_compromise'` | ||
- **[.urls()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'compromise.cool'` | ||
- **[.adverbs()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'quickly'` | ||
- **[.pronouns()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'he'` | ||
- **[.conjunctions()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'but'` | ||
- **[.prepositions()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'of'` | ||
- **[.abbreviations()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'Mrs.'` | ||
- **[.people()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - names like 'John F. Kennedy' | ||
- **[.places()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - like 'Paris, France' | ||
- **[.organizations()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - like 'Google, Inc' | ||
- **[.topics()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - `people()` + `places()` + `organizations()` | ||
- **[nlp.tokenize()](https://observablehq.com/@spencermountain/compromise-tokenization)** - parse text without running POS-tagging | ||
- **[nlp.plugin()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - mix in a compromise-plugin | ||
- **[nlp.parseMatch()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - pre-parse any match statements for faster lookups | ||
- **[nlp.world()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - grab or change library internals | ||
- **[nlp.model()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - grab all current linguistic data | ||
- **[nlp.methods()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - grab or change internal methods | ||
- **[nlp.hooks()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - see which compute methods run automatically | ||
- **[nlp.verbose()](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - log our decision-making for debugging | ||
- **[nlp.version](https://observablehq.com/@spencermountain/compromise-constructor-methods)** - current semver version of the library | ||
##### Subsets | ||
<!-- spacer --> | ||
<img height="30px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
### compromise/two: | ||
##### Contractions | ||
- **[.contractions()](https://observablehq.com/@spencermountain/compromise-contractions)** - things like "didn't" | ||
- **[.contractions().expand()](https://observablehq.com/@spencermountain/compromise-contractions)** - things like "didn't" | ||
- **[.contract()](https://observablehq.com/@spencermountain/compromise-contractions)** - `"she would"` -> `"she'd"` | ||
- **[.parentheses()](https://observablehq.com/@spencermountain/compromise-selections)** - return anything inside (parentheses) | ||
- **[.possessives()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `"Spencer's"` | ||
- **[.quotations()](https://observablehq.com/@spencermountain/compromise-selections)** - return any terms inside quotation marks | ||
- **[.acronyms()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'FBI'` | ||
- **[.lists()](https://observablehq.com/@spencermountain/compromise-lists)** - things like `'eats, shoots, and leaves'` | ||
- **[.lists().items()](https://observablehq.com/@spencermountain/compromise-lists)** - return the partitioned things in the list | ||
- **[.lists().add()](https://observablehq.com/@spencermountain/compromise-lists)** - put a new item in the list | ||
- **[.contract()](https://observablehq.com/@spencermountain/compromise-contractions)** - things like "didn't" | ||
<!-- spacer --> | ||
<img height="30px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
### compromise/three: | ||
##### Nouns | ||
- **[.nouns()](https://observablehq.com/@spencermountain/nouns)** - return any subsequent terms tagged as a Noun | ||
- **[.nouns().json()](https://observablehq.com/@spencermountain/nouns)** - overloaded output with noun metadata | ||
- **[.nouns().adjectives()](https://observablehq.com/@spencermountain/nouns)** - get any adjectives describing this noun | ||
- **[.nouns().parse()](https://observablehq.com/@spencermountain/nouns)** - get tokenized noun-phrase | ||
- **[.nouns().isPlural()](https://observablehq.com/@spencermountain/nouns)** - return only plural nouns | ||
- **[.nouns().isSingular()](https://observablehq.com/@spencermountain/nouns)** - return only singular nouns | ||
- **[.nouns().toPlural()](https://observablehq.com/@spencermountain/nouns)** - `'football captain' → 'football captains'` | ||
- **[.nouns().toSingular()](https://observablehq.com/@spencermountain/nouns)** - `'turnovers' → 'turnover'` | ||
- **[.nouns().isPlural()](https://observablehq.com/@spencermountain/nouns)** - return only plural nouns | ||
- **[.nouns().isSingular()](https://observablehq.com/@spencermountain/nouns)** - return only singular nouns | ||
- **[.nouns().hasPlural()](https://observablehq.com/@spencermountain/nouns)** - return only nouns that _can be_ inflected as plural | ||
- **[.nouns().toPossessive()](https://observablehq.com/@spencermountain/nouns)** - add a `'s` to the end, in a safe manner. | ||
- **[.nouns().adjectives()](https://observablehq.com/@spencermountain/nouns)** - get any adjectives describing this noun | ||
##### Verbs | ||
- **[.verbs()](https://observablehq.com/@spencermountain/verbs)** - return any subsequent terms tagged as a Verb | ||
- **[.verbs().json()](https://observablehq.com/@spencermountain/verbs)** - overloaded output with verb metadata | ||
- **[.verbs().conjugate()](https://observablehq.com/@spencermountain/verbs)** - return all forms of these verbs | ||
- **[.verbs().parse()](https://observablehq.com/@spencermountain/verbs)** - get tokenized verb-phrase | ||
- **[.verbs().subjects()](https://observablehq.com/@spencermountain/verbs)** - what is doing the verb action | ||
- **[.verbs().adverbs()](https://observablehq.com/@spencermountain/verbs)** - return the adverbs describing this verb. | ||
- **[.verbs().isSingular()](https://observablehq.com/@spencermountain/verbs)** - return singular verbs like 'spencer walks' | ||
- **[.verbs().isPlural()](https://observablehq.com/@spencermountain/verbs)** - return plural verbs like 'we walk' | ||
- **[.verbs().isImperative()](https://observablehq.com/@spencermountain/verbs)** - only instruction verbs like 'eat it!' | ||
- **[.verbs().toPastTense()](https://observablehq.com/@spencermountain/verbs)** - `'will go' → 'went'` | ||
@@ -589,63 +644,24 @@ - **[.verbs().toPresentTense()](https://observablehq.com/@spencermountain/verbs)** - `'walked' → 'walks'` | ||
- **[.verbs().toGerund()](https://observablehq.com/@spencermountain/verbs)** - `'walks' → 'walking'` | ||
- **[.verbs().toParticiple()](https://observablehq.com/@spencermountain/verbs)** - `'drive' → 'driven'` - otherwise simple-past ('walked') | ||
- **[.verbs().conjugate()](https://observablehq.com/@spencermountain/verbs)** - return all forms of these verbs | ||
- **[.verbs().isNegative()](https://observablehq.com/@spencermountain/verbs)** - return verbs with 'not', 'never' or 'no' | ||
- **[.verbs().isPositive()](https://observablehq.com/@spencermountain/verbs)** - only verbs without 'not', 'never' or 'no' | ||
- **[.verbs().toNegative()](https://observablehq.com/@spencermountain/verbs)** - `'went' → 'did not go'` | ||
- **[.verbs().toPositive()](https://observablehq.com/@spencermountain/verbs)** - `"didn't study" → 'studied'` | ||
- **[.verbs().isNegative()](https://observablehq.com/@spencermountain/verbs)** - return verbs with 'not' | ||
- **[.verbs().isPositive()](https://observablehq.com/@spencermountain/verbs)** - only verbs without 'not' | ||
- **[.verbs().isPlural()](https://observablehq.com/@spencermountain/verbs)** - return plural verbs like 'we walk' | ||
- **[.verbs().isSingular()](https://observablehq.com/@spencermountain/verbs)** - return singular verbs like 'spencer walks' | ||
- **[.verbs().adverbs()](https://observablehq.com/@spencermountain/verbs)** - return the adverbs describing this verb. | ||
- **[.verbs().isImperative()](https://observablehq.com/@spencermountain/verbs)** - only instruction verbs like 'eat it!' | ||
<div align="center"> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221824-09809d80-ffb8-11e9-9ef0-6ed3574b0ce8.png"/> | ||
</div> | ||
### Plugins: | ||
These are some helpful extensions: | ||
##### Adjectives | ||
`npm install compromise-adjectives` | ||
- **[.adjectives()](https://observablehq.com/@spencermountain/compromise-adjectives)** - like `quick` | ||
- **[.adjectives().json()](https://observablehq.com/@spencermountain/compromise-adjectives)** - overloaded output with adjective metadata | ||
- **[.adjectives().conjugate()](https://observablehq.com/@spencermountain/compromise-adjectives)** - return all conjugated forms of this adjective | ||
- **[.adjectives().toSuperlative()](https://observablehq.com/@spencermountain/compromise-adjectives)** - convert `quick` to `quickest` | ||
- **[.adjectives().toComparative()](https://observablehq.com/@spencermountain/compromise-adjectives)** - convert `quick` to `quicker` | ||
- **[.adjectives().toAdverb()](https://observablehq.com/@spencermountain/compromise-adjectives)** - convert `quick` to `quickly` | ||
- **[.adjectives().toVerb()](https://observablehq.com/@spencermountain/compromise-adjectives)** - convert `quick` to `quicken` | ||
- **[.adjectives().toNoun()](https://observablehq.com/@spencermountain/compromise-adjectives)** - convert `quick` to `quickness` | ||
##### Dates | ||
`npm install compromise-dates` | ||
- **[.dates()](https://observablehq.com/@spencermountain/compromise-dates)** - find dates like `June 8th` or `03/03/18` | ||
- **[.dates().get()](https://observablehq.com/@spencermountain/compromise-dates)** - simple start/end json result | ||
- **[.dates().json()](https://observablehq.com/@spencermountain/compromise-dates)** - overloaded output with date metadata | ||
- **[.dates().format('')](https://observablehq.com/@spencermountain/compromise-dates)** - convert the dates to specific formats | ||
- **[.dates().toShortForm()](https://observablehq.com/@spencermountain/compromise-dates)** - convert 'Wednesday' to 'Wed', etc | ||
- **[.dates().toLongForm()](https://observablehq.com/@spencermountain/compromise-dates)** - convert 'Feb' to 'February', etc | ||
- **[.durations()](https://observablehq.com/@spencermountain/compromise-dates)** - `2 weeks` or `5mins` | ||
- **[.durations().get()](https://observablehq.com/@spencermountain/compromise-dates)** - return simple json for duration | ||
- **[.durations().json()](https://observablehq.com/@spencermountain/compromise-dates)** - overloaded output with duration metadata | ||
- **[.times()](https://observablehq.com/@spencermountain/compromise-dates)** - `4:30pm` or `half past five` | ||
- **[.durations().get()](https://observablehq.com/@spencermountain/compromise-dates)** - return simple json for times | ||
- **[.times().json()](https://observablehq.com/@spencermountain/compromise-dates)** - overloaded output with time metadata | ||
##### Numbers | ||
`npm install compromise-numbers` | ||
- **[.numbers()](https://observablehq.com/@spencermountain/compromise-values)** - grab all written and numeric values | ||
- **[.numbers().get()](https://observablehq.com/@spencermountain/compromise-values)** - retrieve the parsed number(s) | ||
- **[.numbers().parse()](https://observablehq.com/@spencermountain/compromise-values)** - get tokenized number phrase | ||
- **[.numbers().get()](https://observablehq.com/@spencermountain/compromise-values)** - get a simple javascript number | ||
- **[.numbers().json()](https://observablehq.com/@spencermountain/compromise-values)** - overloaded output with number metadata | ||
- **[.numbers().units()](https://observablehq.com/@spencermountain/compromise-values)** - grab 'kilos' from `25 kilos'` | ||
- **[.numbers().fractions()](https://observablehq.com/@spencermountain/compromise-values)** - things like `1/3rd` | ||
- **[.numbers().toText()](https://observablehq.com/@spencermountain/compromise-values)** - convert number to `five` or `fifth` | ||
- **[.numbers().toNumber()](https://observablehq.com/@spencermountain/compromise-values)** - convert number to `5` or `5th` | ||
- **[.numbers().toOrdinal()](https://observablehq.com/@spencermountain/compromise-values)** - convert number to `fifth` or `5th` | ||
- **[.numbers().toCardinal()](https://observablehq.com/@spencermountain/compromise-values)** - convert number to `five` or `5` | ||
- **[.numbers().toNumber()](https://observablehq.com/@spencermountain/compromise-values)** - convert 'five' to `5` | ||
- **[.numbers().toLocaleString()](https://observablehq.com/@spencermountain/compromise-values)** - add commas, or nicer formatting for numbers | ||
- **[.numbers().toText()](https://observablehq.com/@spencermountain/compromise-values)** - convert '5' to `five` | ||
- **[.numbers().toOrdinal()](https://observablehq.com/@spencermountain/compromise-values)** - convert 'five' to `fifth` or `5th` | ||
- **[.numbers().toCardinal()](https://observablehq.com/@spencermountain/compromise-values)** - convert 'fifth' to `five` or `5` | ||
- **[.numbers().isOrdinal()](https://observablehq.com/@spencermountain/compromise-values)** - return only ordinal numbers | ||
- **[.numbers().isCardinal()](https://observablehq.com/@spencermountain/compromise-values)** - return only cardinal numbers | ||
- **[.numbers().isEqual(n)](https://observablehq.com/@spencermountain/compromise-values)** - return numbers with this value | ||
- **[.numbers().greaterThan(min)](https://observablehq.com/@spencermountain/compromise-values)** - return numbers bigger than n | ||
- **[.numbers().lessThan(max)](https://observablehq.com/@spencermountain/compromise-values)** - return numbers smaller than n | ||
- **[.numbers().between(min, max)](https://observablehq.com/@spencermountain/compromise-values)** - return numbers between min and max | ||
- **[.numbers().set(n)](https://observablehq.com/@spencermountain/compromise-values)** - set number to n | ||
@@ -656,9 +672,2 @@ - **[.numbers().add(n)](https://observablehq.com/@spencermountain/compromise-values)** - increase number by n | ||
- **[.numbers().decrement()](https://observablehq.com/@spencermountain/compromise-values)** - decrease number by 1 | ||
- **[.numbers().isEqual(n)](https://observablehq.com/@spencermountain/compromise-values)** - return numbers with this value | ||
- **[.numbers().greaterThan(min)](https://observablehq.com/@spencermountain/compromise-values)** - return numbers bigger than n | ||
- **[.numbers().lessThan(max)](https://observablehq.com/@spencermountain/compromise-values)** - return numbers smaller than n | ||
- **[.numbers().between(min, max)](https://observablehq.com/@spencermountain/compromise-values)** - return numbers between min and max | ||
- **[.numbers().isOrdinal()](https://observablehq.com/@spencermountain/compromise-values)** - return only ordinal numbers | ||
- **[.numbers().isCardinal()](https://observablehq.com/@spencermountain/compromise-values)** - return only cardinal numbers | ||
- **[.numbers().toLocaleString()](https://observablehq.com/@spencermountain/compromise-values)** - add commas, or nicer formatting for numbers | ||
- **[.money()](https://observablehq.com/@spencermountain/compromise-values)** - things like `'$2.50'` | ||
@@ -669,2 +678,3 @@ - **[.money().get()](https://observablehq.com/@spencermountain/compromise-values)** - retrieve the parsed amount(s) of money | ||
- **[.fractions()](https://observablehq.com/@spencermountain/compromise-values)** - like '2/3rds' or 'one out of five' | ||
- **[.fractions().parse()](https://observablehq.com/@spencermountain/compromise-values)** - get tokenized fraction | ||
- **[.fractions().get()](https://observablehq.com/@spencermountain/compromise-values)** - simple numerator, denomenator data | ||
@@ -681,103 +691,248 @@ - **[.fractions().json()](https://observablehq.com/@spencermountain/compromise-values)** - json method overloaded with fractions data | ||
##### Export | ||
##### Sentences | ||
- **[.sentences()](https://observablehq.com/@spencermountain/compromise-sentences)** - return a sentence class with additional methods | ||
- **[.sentences().json()](https://observablehq.com/@spencermountain/compromise-sentences)** - overloaded output with sentence metadata | ||
- **[.sentences().subjects()](https://observablehq.com/@spencermountain/compromise-sentences)** - return the main noun of each sentence | ||
- **[.sentences().toPastTense()](https://observablehq.com/@spencermountain/compromise-sentences)** - `he walks` -> `he walked` | ||
- **[.sentences().toPresentTense()](https://observablehq.com/@spencermountain/compromise-sentences)** - `he walked` -> `he walks` | ||
- **[.sentences().toFutureTense()](https://observablehq.com/@spencermountain/compromise-sentences)** -- `he walks` -> `he will walk` | ||
- **[.sentences().toInfinitive()](https://observablehq.com/@spencermountain/compromise-sentences)** -- verb root-form `he walks` -> `he walk` | ||
- **[.sentences().toNegative()](https://observablehq.com/@spencermountain/compromise-sentences)** - - `he walks` -> `he didn't walk` | ||
- **[.sentences().isQuestion()](https://observablehq.com/@spencermountain/compromise-sentences)** - return questions with a `?` | ||
- **[.sentences().isExclamation()](https://observablehq.com/@spencermountain/compromise-sentences)** - return sentences with a `!` | ||
- **[.sentences().isStatement()](https://observablehq.com/@spencermountain/compromise-sentences)** - return sentences without `?` or `!` | ||
`npm install compromise-export` | ||
##### Misc selections | ||
- **[.export()](https://observablehq.com/@spencermountain/compromise-export)** - store a parsed document for later use | ||
- **[nlp.load()](https://observablehq.com/@spencermountain/compromise-export)** - re-generate a Doc object from .export() results | ||
- **[.clauses()](https://observablehq.com/@spencermountain/compromise-selections)** - split-up sentences into multi-term phrases | ||
- **[.chunks()](https://observablehq.com/@spencermountain/compromise-selections)** - split-up sentences noun-phrases and verb-phrases | ||
- **[.hyphenated()](https://observablehq.com/@spencermountain/compromise-selections)** - all terms connected with a hyphen or dash like `'wash-out'` | ||
- **[.phoneNumbers()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'(939) 555-0113'` | ||
- **[.hashTags()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'#nlp'` | ||
- **[.emails()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'hi@compromise.cool'` | ||
- **[.emoticons()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `:)` | ||
- **[.emojis()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `💋` | ||
- **[.atMentions()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'@nlp_compromise'` | ||
- **[.urls()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'compromise.cool'` | ||
- **[.pronouns()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'he'` | ||
- **[.conjunctions()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'but'` | ||
- **[.prepositions()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'of'` | ||
- **[.abbreviations()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'Mrs.'` | ||
- **[.people()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - names like 'John F. Kennedy' | ||
- **[.people().json()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - get person-name metadata | ||
- **[.people().parse()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - get person-name interpretation | ||
- **[.places()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - like 'Paris, France' | ||
- **[.organizations()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - like 'Google, Inc' | ||
- **[.topics()](https://observablehq.com/@spencermountain/topics-named-entity-recognition)** - `people()` + `places()` + `organizations()` | ||
- **[.adjectives()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'quickly'` | ||
- **[.adjectives().json()](https://observablehq.com/@spencermountain/compromise-selections)** - get adjective metadata | ||
- **[.adverbs()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'quickly'` | ||
- **[.adverbs().json()](https://observablehq.com/@spencermountain/compromise-selections)** - get adverb metadata | ||
- **[.acronyms()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `'FBI'` | ||
- **[.acronyms().strip()](https://observablehq.com/@spencermountain/compromise-selections)** - remove periods from acronyms | ||
- **[.acronyms().addPeriods()](https://observablehq.com/@spencermountain/compromise-selections)** - add periods to acronyms | ||
- **[.parentheses()](https://observablehq.com/@spencermountain/compromise-selections)** - return anything inside (parentheses) | ||
- **[.parentheses().strip()](https://observablehq.com/@spencermountain/compromise-selections)** - remove brackets | ||
- **[.possessives()](https://observablehq.com/@spencermountain/compromise-selections)** - things like `"Spencer's"` | ||
- **[.possessives().strip()](https://observablehq.com/@spencermountain/compromise-selections)** - "Spencer's" -> "Spencer" | ||
- **[.quotations()](https://observablehq.com/@spencermountain/compromise-selections)** - return any terms inside paired quotation marks | ||
- **[.quotations().strip()](https://observablehq.com/@spencermountain/compromise-selections)** - remove quotation marks | ||
##### Html | ||
<p> | ||
<img height="85px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
</p> | ||
`npm install compromise-html` | ||
<div align="center"> | ||
<img src="https://user-images.githubusercontent.com/399657/68221814-05ed1680-ffb8-11e9-8b6b-c7528d163871.png"/> | ||
</div> | ||
- **[.html({})](https://observablehq.com/@spencermountain/compromise-html)** - generate sanitized html from the document | ||
##### Hash | ||
`npm install compromise-hash` | ||
### .extend(): | ||
- **[.hash()](https://observablehq.com/@spencermountain/compromise-hash)** - generate an md5 hash from the document+tags | ||
- **[.isEqual(doc)](https://observablehq.com/@spencermountain/compromise-hash)** - compare the hash of two documents for semantic-equality | ||
This library comes with a considerate, common-sense baseline for english grammar. | ||
##### Keypress | ||
You're free to change, or lay-waste to any settings - which is the fun part actually. | ||
`npm install compromise-keypress` | ||
the easiest part is just to suggest tags for any given words: | ||
```js | ||
let myWords = { | ||
kermit: 'FirstName', | ||
fozzie: 'FirstName', | ||
} | ||
let doc = nlp(muppetText, myWords) | ||
``` | ||
- **[nlp.keypress('')](https://observablehq.com/@spencermountain/compromise-keypress)** - generate an md5 hash from the document+tags | ||
- **[nlp.clear('')](https://observablehq.com/@spencermountain/compromise-keypress)** - clean-up any cached sentences from memory | ||
or make heavier changes with a [compromise-plugin](https://observablehq.com/@spencermountain/compromise-plugins). | ||
##### Ngrams | ||
```js | ||
import nlp from 'compromise' | ||
nlp.extend({ | ||
// add new tags | ||
tags: { | ||
Character: { | ||
isA: 'Person', | ||
notA: 'Adjective', | ||
}, | ||
}, | ||
// add or change words in the lexicon | ||
words: { | ||
kermit: 'Character', | ||
gonzo: 'Character', | ||
}, | ||
// add new methods to compromise | ||
api: (View) => { | ||
View.prototype.kermitVoice = function () { | ||
this.sentences().prepend('well,') | ||
this.match('i [(am|was)]').prepend('um,') | ||
return this | ||
} | ||
} | ||
}) | ||
``` | ||
`npm install compromise-ngrams` | ||
<div align="right"> | ||
<a href="https://docs.compromise.cool/compromise-plugins">.plugin() docs</a> | ||
</div> | ||
<div align="center"> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221848-11404200-ffb8-11e9-90cd-3adee8d8564f.png"/> | ||
</div> | ||
- **[.ngrams({})](https://observablehq.com/@spencermountain/compromise-ngram)** - list all repeating sub-phrases, by word-count | ||
- **[.unigrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams with one word | ||
- **[.bigrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams with two words | ||
- **[.trigrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams with three words | ||
- **[.startgrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams including the first term of a phrase | ||
- **[.endgrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams including the last term of a phrase | ||
- **[.edgegrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams including the first or last term of a phrase | ||
<!-- spacer --> | ||
<div > | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
</div> | ||
##### Paragraphs | ||
### Docs: | ||
`npm install compromise-paragraphs` | ||
this plugin creates a wrapper around the default sentence objects. | ||
##### gentle introduction: | ||
- **[.paragraphs()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - return groups of sentences | ||
- **[.paragraphs().json()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - output metadata for each paragraph | ||
- **[.paragraphs().sentences()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - go back to a regular Doc object | ||
- **[.paragraphs().terms()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - return all individual terms | ||
- **[.paragraphs().eq()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - get the nth paragraph | ||
- **[.paragraphs().first()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - get the first n paragraphs | ||
- **[.paragraphs().last()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - get the last n paragraphs | ||
- **[.paragraphs().match()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - | ||
- **[.paragraphs().not()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - | ||
- **[.paragraphs().if()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - | ||
- **[.paragraphs().ifNo()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - | ||
- **[.paragraphs().has()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - | ||
- **[.paragraphs().forEach()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - | ||
- **[.paragraphs().map()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - | ||
- **[.paragraphs().filter()](https://observablehq.com/@spencermountain/compromise-paragraphs)** - | ||
- **[#1) Input → output](https://docs.compromise.cool/tutorial-1)** | ||
- **[#2) Match & transform](https://docs.compromise.cool/compromise-tutorial-2)** | ||
- **[#3) Making a chat-bot](https://docs.compromise.cool/compromise-making-a-bot)** | ||
<!-- * **[Tutorial #4]()** - Making a plugin --> | ||
##### Sentences | ||
<div > | ||
<img height="25px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
</div> | ||
`npm install compromise-sentences` | ||
##### Documentation: | ||
- **[.sentences()](https://observablehq.com/@spencermountain/compromise-sentences)** - return a sentence class with additional methods | ||
- **[.sentences().json()](https://observablehq.com/@spencermountain/compromise-sentences)** - overloaded output with sentence metadata | ||
- **[.sentences().subjects()](https://observablehq.com/@spencermountain/compromise-sentences)** - return the main noun of each sentence | ||
- **[.sentences().toPastTense()](https://observablehq.com/@spencermountain/compromise-sentences)** - `he walks` -> `he walked` | ||
- **[.sentences().toPresentTense()](https://observablehq.com/@spencermountain/compromise-sentences)** - `he walked` -> `he walks` | ||
- **[.sentences().toFutureTense()](https://observablehq.com/@spencermountain/compromise-sentences)** -- `he walks` -> `he will walk` | ||
- **[.sentences().toNegative()](https://observablehq.com/@spencermountain/compromise-sentences)** - - `he walks` -> `he didn't walk` | ||
- **[.sentences().toPositive()](https://observablehq.com/@spencermountain/compromise-sentences)** - `he doesn't walk` -> `he walks` | ||
- **[.sentences().isPassive()](https://observablehq.com/@spencermountain/compromise-sentences)** - return only sentences with a passive-voice | ||
- **[.sentences().isQuestion()](https://observablehq.com/@spencermountain/compromise-sentences)** - return questions with a `?` | ||
- **[.sentences().isExclamation()](https://observablehq.com/@spencermountain/compromise-sentences)** - return sentences with a `!` | ||
- **[.sentences().isStatement()](https://observablehq.com/@spencermountain/compromise-sentences)** - return sentences without `?` or `!` | ||
- **[.sentences().prepend()](https://observablehq.com/@spencermountain/compromise-sentences)** - smarter prepend that repairs whitespace + titlecasing | ||
- **[.sentences().append()](https://observablehq.com/@spencermountain/compromise-sentences)** - smarter append that repairs sentence punctuation | ||
- **[.sentences().toExclamation()](https://observablehq.com/@spencermountain/compromise-sentences)** - end sentence with a `!` | ||
- **[.sentences().toQuestion()](https://observablehq.com/@spencermountain/compromise-sentences)** - end sentence with a `?` | ||
- **[.sentences().toStatement()](https://observablehq.com/@spencermountain/compromise-sentences)** - end sentence with a `.` | ||
<!-- - **[.sentences().toContinuous()](#)** - --> | ||
| Concepts | API | Plugins | | ||
| ------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------: | -------------------------------------------------------------------------------------: | | ||
| [Accuracy](https://observablehq.com/@spencermountain/compromise-accuracy) | [Accessors](https://observablehq.com/@spencermountain/compromise-accessors) | [Adjectives](https://observablehq.com/@spencermountain/compromise-adjectives) | | ||
| [Caching](https://observablehq.com/@spencermountain/compromise-cache) | [Constructor-methods](https://observablehq.com/@spencermountain/compromise-constructor-methods) | [Dates](https://observablehq.com/@spencermountain/compromise-dates) | | ||
| [Case](https://observablehq.com/@spencermountain/compromise-case) | [Contractions](https://observablehq.com/@spencermountain/compromise-contractions) | [Export](https://observablehq.com/@spencermountain/compromise-export) | | ||
| [Filesize](https://observablehq.com/@spencermountain/compromise-filesize) | [Insert](https://observablehq.com/@spencermountain/compromise-insert) | [Hash](https://observablehq.com/@spencermountain/compromise-hash) | | ||
| [Internals](https://observablehq.com/@spencermountain/compromise-internals) | [Json](https://observablehq.com/@spencermountain/compromise-json) | [Html](https://observablehq.com/@spencermountain/compromise-html) | | ||
| [Justification](https://observablehq.com/@spencermountain/compromise-justification) | [Lists](https://observablehq.com/@spencermountain/compromise-lists) | [Keypress](https://observablehq.com/@spencermountain/compromise-keypress) | | ||
| [Lexicon](https://observablehq.com/@spencermountain/compromise-lexicon) | [Loops](https://observablehq.com/@spencermountain/compromise-loops) | [Ngrams](https://observablehq.com/@spencermountain/compromise-ngram) | | ||
| [Match-syntax](https://observablehq.com/@spencermountain/compromise-match-syntax) | [Match](https://observablehq.com/@spencermountain/compromise-match) | [Numbers](https://observablehq.com/@spencermountain/compromise-values) | | ||
| [Performance](https://observablehq.com/@spencermountain/compromise-performance) | [Nouns](https://observablehq.com/@spencermountain/nouns) | [Paragraphs](https://observablehq.com/@spencermountain/compromise-paragraphs) | | ||
| [Plugins](https://observablehq.com/@spencermountain/compromise-plugins) | [Output](https://observablehq.com/@spencermountain/compromise-output) | [Scan](https://observablehq.com/@spencermountain/compromise-scan) | | ||
| [Projects](https://observablehq.com/@spencermountain/compromise-projects) | [Selections](https://observablehq.com/@spencermountain/compromise-selections) | [Sentences](https://observablehq.com/@spencermountain/compromise-sentences) | | ||
| [Tagger](https://observablehq.com/@spencermountain/compromise-tagger) | [Sorting](https://observablehq.com/@spencermountain/compromise-sorting) | [Syllables](https://observablehq.com/@spencermountain/compromise-syllables) | | ||
| [Tags](https://observablehq.com/@spencermountain/compromise-tags) | [Split](https://observablehq.com/@spencermountain/compromise-split) | [Pronounce](https://observablehq.com/@spencermountain/compromise-pronounce) | | | ||
| [Tokenization](https://observablehq.com/@spencermountain/compromise-tokenization) | [Text](https://observablehq.com/@spencermountain/compromise-text) | [Strict](https://observablehq.com/@spencermountain/compromise-strict) | | ||
| [Named-Entities](https://observablehq.com/@spencermountain/compromise-topics) | [Utils](https://observablehq.com/@spencermountain/compromise-utils) | [Penn-tags](https://observablehq.com/@spencermountain/compromise-penn-tags) | | ||
| [Whitespace](https://observablehq.com/@spencermountain/compromise-whitespace) | [Verbs](https://observablehq.com/@spencermountain/verbs) | [Typeahead](https://observablehq.com/@spencermountain/compromise/compromise-typeahead) | | ||
| [World data](https://observablehq.com/@spencermountain/compromise-world) | [Normalization](https://observablehq.com/@spencermountain/compromise-normalization) | | | ||
| [Fuzzy-matching](https://observablehq.com/@spencermountain/compromise-fuzzy-matching) | [Typescript](https://observablehq.com/@spencermountain/compromise-typescript) | | | ||
##### Strict-match | ||
`npm install compromise-strict` | ||
<div > | ||
<img height="25px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
</div> | ||
- **[.strictMatch()](https://observablehq.com/@spencermountain/compromise-strict)** - perform a compromise match using a formal parser | ||
##### Talks: | ||
##### Syllables | ||
- **[Language as an Interface](https://www.youtube.com/watch?v=WuPVS2tCg8s)** - by Spencer Kelly | ||
- **[Coding Chat Bots](https://www.youtube.com/watch?v=c_hmwFwvO0U)** - by KahWee Teng | ||
- **[On Typing and data](https://vimeo.com/496095722)** - by Spencer Kelly | ||
##### Articles: | ||
- **[Geocoding Social Conversations with NLP and JavaScript](http://compromise.cool)** - by Microsoft | ||
- **[Microservice Recipe](https://eventn.com/recipes/text-parsing-with-nlp-compromise)** - by Eventn | ||
- **[Adventure Game Sentence Parsing with Compromise](https://killalldefects.com/2020/02/20/adventure-game-sentence-parsing-with-compromise/)** | ||
- **[Building Text-Based Games](https://killalldefects.com/2019/09/24/building-text-based-games-with-compromise-nlp/)** - by Matt Eland | ||
- **[Fun with javascript in BigQuery](https://medium.com/@hoffa/new-in-bigquery-persistent-udfs-c9ea4100fd83#6e09)** - by Felipe Hoffa | ||
- **[Natural Language Processing... in the Browser?](https://dev.to/charlesdlandau/natural-language-processing-in-the-browser-52hj)** - by Charles Landau | ||
##### Some fun Applications: | ||
- **[Automated Bechdel Test](https://github.com/guardian/bechdel-test)** - by The Guardian | ||
- **[Story generation framework](https://perchance.org/welcome)** - by Jose Phrocca | ||
- **[Tumbler blog of lists](https://leanstooneside.tumblr.com/)** - horse-ebooks-like lists - by Michael Paulukonis | ||
- **[Video Editing from Transcription](https://newtheory.io/)** - by New Theory | ||
- **[Browser extension Fact-checking](https://github.com/AlexanderKidd/FactoidL)** - by Alexander Kidd | ||
- **[Siri shortcut](https://routinehub.co/shortcut/3260)** - by Michael Byrns | ||
- **[Amazon skill](https://github.com/tajddin/voiceplay)** - by Tajddin Maghni | ||
- **[Tasking Slack-bot](https://github.com/kevinsuh/toki)** - by Kevin Suh | ||
[[see more]](https://observablehq.com/@spencermountain/compromise-projects) | ||
<!-- spacer --> | ||
<div align="center"> | ||
<img height="25px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
<hr/> | ||
</div> | ||
<div align="center"> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221632-b9094000-ffb7-11e9-99e0-b48edd6cdf8a.png"/> | ||
</div> | ||
<!-- <div align="center"> | ||
<img height="50px" src="https://user-images.githubusercontent.com/399657/68221824-09809d80-ffb8-11e9-9ef0-6ed3574b0ce8.png"/> | ||
</div> --> | ||
### Plugins: | ||
These are some helpful extensions: | ||
##### Dates | ||
`npm install compromise-dates` | ||
- **[.dates()](https://observablehq.com/@spencermountain/compromise-dates)** - find dates like `June 8th` or `03/03/18` | ||
- **[.dates().get()](https://observablehq.com/@spencermountain/compromise-dates)** - simple start/end json result | ||
- **[.dates().json()](https://observablehq.com/@spencermountain/compromise-dates)** - overloaded output with date metadata | ||
- **[.dates().format('')](https://observablehq.com/@spencermountain/compromise-dates)** - convert the dates to specific formats | ||
- **[.dates().toShortForm()](https://observablehq.com/@spencermountain/compromise-dates)** - convert 'Wednesday' to 'Wed', etc | ||
- **[.dates().toLongForm()](https://observablehq.com/@spencermountain/compromise-dates)** - convert 'Feb' to 'February', etc | ||
- **[.durations()](https://observablehq.com/@spencermountain/compromise-dates)** - `2 weeks` or `5mins` | ||
- **[.durations().get()](https://observablehq.com/@spencermountain/compromise-dates)** - return simple json for duration | ||
- **[.durations().json()](https://observablehq.com/@spencermountain/compromise-dates)** - overloaded output with duration metadata | ||
- **[.times()](https://observablehq.com/@spencermountain/compromise-dates)** - `4:30pm` or `half past five` | ||
- **[.durations().get()](https://observablehq.com/@spencermountain/compromise-dates)** - return simple json for times | ||
- **[.times().json()](https://observablehq.com/@spencermountain/compromise-dates)** - overloaded output with time metadata | ||
##### Stats | ||
`npm install compromise-stats` | ||
- **[.tfidf({})](https://observablehq.com/@spencermountain/compromise-tfidf)** - rank words by frequency and uniqueness | ||
- **[.ngrams({})](https://observablehq.com/@spencermountain/compromise-ngram)** - list all repeating sub-phrases, by word-count | ||
- **[.unigrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams with one word | ||
- **[.bigrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams with two words | ||
- **[.trigrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams with three words | ||
- **[.startgrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams including the first term of a phrase | ||
- **[.endgrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams including the last term of a phrase | ||
- **[.edgegrams()](https://observablehq.com/@spencermountain/compromise-ngram)** - n-grams including the first or last term of a phrase | ||
##### Speech | ||
`npm install compromise-syllables` | ||
- **[.syllables()](https://observablehq.com/@spencermountain/compromise-syllables)** - split each term by its typical pronounciation | ||
- **[.soundsLike()](https://observablehq.com/@spencermountain/compromise-soundsLike)** - produce a estimated pronounciation | ||
##### Penn-tags | ||
##### Wikipedia | ||
`npm install compromise-penn-tags` | ||
`npm install compromise-wikipedia` | ||
- **[.pennTags()](https://observablehq.com/@spencermountain/compromise-penn-tags)** - return POS tags from the Penn Tagset | ||
- **[.wikipedia()](https://observablehq.com/@spencermountain/compromise-wikipedia)** - compressed article reconciliation | ||
<!-- spacer --> | ||
@@ -795,9 +950,7 @@ <div > | ||
import nlp from 'compromise' | ||
import ngrams from 'compromise-ngrams' | ||
import numbers from 'compromise-numbers' | ||
import stats from 'compromise-stats' | ||
const nlpEx = nlp.extend(ngrams).extend(numbers) | ||
const nlpEx = nlp.extend(stats) | ||
nlpEx('This is type safe!').ngrams({ min: 1 }) | ||
nlpEx('This is type safe!').numbers() | ||
``` | ||
@@ -809,19 +962,2 @@ | ||
### Partial-builds | ||
or if you don't care about POS-tagging, you can use the tokenize-only build: (90kb!) | ||
```html | ||
<script src="https://unpkg.com/compromise/builds/compromise-tokenize.js"></script> | ||
<script> | ||
var doc = nlp('No, my son is also named Bort.') | ||
//you can see the text has no tags | ||
console.log(doc.has('#Noun')) //false | ||
//the rest of the api still works | ||
console.log(doc.has('my .* is .? named /^b[oa]rt/')) //true | ||
</script> | ||
``` | ||
<div > | ||
@@ -924,6 +1060,7 @@ <img height="50px" src="https://user-images.githubusercontent.com/399657/68221862-17ceb980-ffb8-11e9-87d4-7b30b6488f16.png"/> | ||
- **[naturalNode](https://github.com/NaturalNode/natural)** - fancier statistical nlp in javascript | ||
- **[dariusk/pos-js ](https://github.com/dariusk/pos-js)** - fastTag fork in javascript | ||
- **[compendium-js](https://github.com/Ulflander/compendium-js)** - POS and sentiment analysis in javascript | ||
- **[nodeBox linguistics](https://www.nodebox.net/code/index.php/Linguistics)** - conjugation, inflection in javascript | ||
- **[reText](https://github.com/wooorm/retext)** - very impressive [text utilities](https://github.com/wooorm/retext/blob/master/doc/plugins.md) in javascript | ||
- **[superScript](http://superscriptjs.com/)** - conversation engine in js | ||
- **[superScript](https://github.com/superscriptjs/superscript)** - conversation engine in js | ||
- **[jsPos](https://code.google.com/archive/p/jspos/)** - javascript build of the time-tested Brill-tagger | ||
@@ -930,0 +1067,0 @@ |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2103628
13
406
23280
1051
Yes
3
3
1
+ Addedefrt@2.5.0
+ Addedgrad-school@0.0.4
+ Addedsuffix-thumb@4.0.2
+ Addedefrt@2.5.0(transitive)
+ Addedgrad-school@0.0.4(transitive)
+ Addedsuffix-thumb@4.0.2(transitive)
- Removedefrt-unpack@2.2.0
- Removedefrt-unpack@2.2.0(transitive)