├── .gitignore
├── .jslintrc
├── .snyk
├── .travis.yml
├── LICENSE
├── README.md
├── index.js
├── lib
├── first.js
├── object
│ ├── index.js
│ ├── type.js
│ └── value.js
├── parse.js
├── predicate
│ ├── index.js
│ ├── type.js
│ └── value.js
├── rules-engine
│ ├── flip
│ │ └── index.js
│ ├── index.js
│ ├── parse
│ │ ├── first-non-predicate.js
│ │ ├── first-predicate.js
│ │ ├── last-predicate.js
│ │ ├── objects.js
│ │ ├── parts.js
│ │ ├── predicate.js
│ │ ├── reduce-parts.js
│ │ ├── reduce-predicates.js
│ │ ├── rules.js
│ │ └── subjects.js
│ └── rules-processor.js
├── subject
│ ├── index.js
│ ├── type.js
│ └── value.js
├── text
│ ├── classify.js
│ ├── is
│ │ └── plural.js
│ └── singularize.js
└── triple.js
├── logo.png
├── package.json
├── test
├── check.js
├── messenger
│ ├── client
│ │ ├── 001-client.js
│ │ └── index.js
│ ├── follow
│ │ └── 001-user-follows-user.js
│ └── message
│ │ ├── 001-user-creates-message.js
│ │ ├── 002-user-sends-message.js
│ │ ├── 003-user-receives-message.js
│ │ └── 004-user-messages-user.js
└── unit
│ └── flip
│ └── 001-flip.js
└── wercker.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # node-waf configuration
20 | .lock-wscript
21 |
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 |
25 | # Dependency directory
26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
27 | node_modules
28 |
--------------------------------------------------------------------------------
/.jslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "evil":false,
3 | "indent":2,
4 | "vars":true,
5 | "passfail":false,
6 | "plusplus":false,
7 | "predef": "module,require"
8 | }
9 |
--------------------------------------------------------------------------------
/.snyk:
--------------------------------------------------------------------------------
1 | ignore: {}
2 | patch: {}
3 | version: v1
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "5"
4 | - "4"
5 | - "0.12"
6 | - "0.11"
7 | - "0.10"
8 | - "iojs"
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 @DEFSTREAM
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## nl3 - Natural Language Triples
2 |
3 |
4 |
6 |
7 |
9 |
10 |
12 |
13 |
15 |
16 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
28 |
29 |
30 | **nl3** is a natural language triple library, used for parsing triples from plain english.
31 | Currently nl3 is best at generating triples from simple short phrases that contain the Subject, Predicate and Object in order.
32 |
33 |
34 |
35 |
36 |
37 | #### What is a triple?
38 | A triple is a data structure that represents a Subject, Predicate and Object or S P O.
39 |
40 | **More Information**
41 | - https://en.wikipedia.org/wiki/Triplestore
42 | - https://en.wikipedia.org/wiki/Resource_Description_Framework
43 |
44 | #### TLDR;
45 |
46 | ```javascript
47 | var nl3 = require('nl3')({
48 | /**
49 | * Specifies valid triples in plain english ex: 'Subject Predicate Object'.
50 | * All values will be singularized.
51 | * @type {Array}
52 | */
53 | grammar: [
54 | 'users message users'
55 | ],
56 | /**
57 | * Extend your vocabulary by mapping word stems to existing predicates.
58 | * @type {Object}
59 | */
60 | vocabulary: {
61 | msg: 'message', // user bob msgs user tom
62 | messag: 'message', // user bob messaged user jill
63 | contact: 'message' // user bob contacted user bill
64 | }
65 | });
66 | ```
67 |
68 | The client returned is able to parse these queries.
69 |
70 | ```javascript
71 | nl3.parse('user jack msg user jill');
72 | nl3.parse('user jack msgs user jill');
73 | nl3.parse('user jack messaged user jill');
74 | nl3.parse('user jack contacted user jill');
75 | nl3.parse('user jack contacts user jill');
76 | ```
77 |
78 | All of which will have the same output.
79 |
80 | ```javascript
81 | {
82 | subject: {
83 | type: 'user',
84 | value: 'jack'
85 | },
86 | predicate: {
87 | value: 'message'
88 | },
89 | object: {
90 | type: 'user',
91 | value: 'jill'
92 | }
93 | }
94 | ```
95 |
96 | # Installation
97 |
98 | ```shell
99 | $ npm install nl3 --save
100 | ```
101 |
102 | # Development Scripts
103 | Before running any development scripts, be sure to first install the dev modules.
104 |
105 | ```shell
106 | $ npm install nl3 --save --dev
107 | ```
108 |
109 | #### Build Documentation
110 | Outputs code documentation files to the `./doc/api` folder.
111 |
112 | ```shell
113 | $ npm run doc
114 | ```
115 |
116 | #### Static Analysis
117 | Outputs static analysis files to the `./doc/analysis` folder.
118 |
119 | ```shell
120 | $ npm run analyze
121 | ```
122 |
123 | #### Test + Coverage
124 | Outputs code coverage files to the `./doc/coverage` folder.
125 |
126 | ```shell
127 | $ npm run test
128 | ```
129 |
130 | **CURRENT COVERAGE REPORT**
131 |
132 | 
133 |
134 | # API
135 |
136 | ### `nl3(options)`
137 |
138 | Create an nl3 instance.
139 |
140 | **parameters:**
141 | - **options** {Object} The options for the nl3 client.
142 | - **options.grammar** {Array} An array of valid grammar in the format of 'S P O'.
143 | - **options.vocabulary** {Array} An object mapping the phonetic root of an object to a predicate.
144 |
145 |
146 | **returns**: a new instance of the nl3 client.
147 |
148 | Example
149 |
150 | ```javascript
151 | var nl3 = require('nl3')({
152 | /**
153 | * Specify valid triples in plain english ex: 'Subject Predicate Object'.
154 | * The Subject, Predicate and Object will be will be singularized, if presented in any tense.
155 | * @type {Array}
156 | */
157 | grammar: [
158 | 'users message users'
159 | ],
160 | /**
161 | * Extend the vocabulary of your predicates by mapping word stems to existing predicates within your grammar.
162 | * @type {Object}
163 | */
164 | vocabulary: {
165 | msg: 'message', // user bob msgs user tom
166 | messag: 'message', // user bob messaged user jill
167 | contact: 'message' // user bob contacted user bill
168 | }
169 | });
170 | ```
171 |
172 | ### `nl3.parse( text )`
173 |
174 | **parameters:**
175 | - **text**: {String} A string containing a S P O phrase in plain english.
176 | **returns**: A triple containing the results of of the parsed Subject Predicate and Object.
177 |
178 | Example
179 |
180 | ```javascript
181 |
182 | var nl3 = require('nl3')({
183 | grammar: [
184 | 'users message users'
185 | ],
186 | vocabulary: {
187 | contact: 'message', // user bob contacted user bill
188 | }
189 | });
190 |
191 | function print (description, triple) {
192 | console.log(
193 | description + ' =', JSON.stringify(triple, null, ' ');
194 | );
195 | };
196 |
197 | print( 'user jack contacts user jill', nl3.parse('user jack contacts user jill') );
198 |
199 | print( 'users who message user jill', nl3.parse('users who message user jill') );
200 |
201 | ```
202 |
203 | **returns:**
204 |
205 | ```javascript
206 |
207 | user jack contacts user jill = {
208 | "subject": {
209 | "type": "user",
210 | "value": "jack"
211 |
212 | },
213 | "predicate": {
214 | "value": "message"
215 | },
216 | "object": {
217 | "type": "user",
218 | "value": "jill"
219 | }
220 | }
221 | users who message user jill = {
222 | "subject": {
223 | "type": "user"
224 | },
225 | "predicate": {
226 | "value": "message"
227 | },
228 | "object": {
229 | "type": "user",
230 | "value": "jill"
231 | }
232 | }
233 |
234 | ```
235 |
236 | ### vNext
237 | Support for natural random order queries, these are not in (SPO) order, such as messages that user bob created (OSP), created messages by user jill (POS), created by user jill messages (PSO), (SO) user jills messages, (OS) messages for user jill.
238 |
239 | ```javascript
240 |
241 | nl3.parse('messages from user 42');
242 | nl3.parse('messages by user 32');
243 |
244 | ```
245 |
246 | ### The Backlog
247 | - Support for misspelled subjects & objects ( nearest neighbor )
248 |
249 | ### Discuss
250 | Chat channel:
251 |
252 | Questions or comments can also be posted on the nl3 Github issues page.
253 |
254 | ### Maintainers
255 | Hector Gray (Twitter: @defstream)
256 |
257 | ### Contribute
258 | Pull Requests welcome. Please make sure all tests pass:
259 |
260 | ```shell
261 | $ npm test
262 | ```
263 |
264 | Please submit Github issues for any feature enhancements, bugs or documentation problems.
265 |
266 | ### License
267 | MIT
268 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 |
4 | 'use strict';
5 |
6 | var parse = require('./lib/parse');
7 | var rules = require('./lib/rules-engine');
8 | /** @exports nl3 **/
9 | var nl3 = {
10 | //@function
11 | /**
12 | * @name parse
13 | * @description Returns a triple based on language used.
14 | * @access public
15 | * @returns {Object}
16 | * @example nl3.parse('users who follow user 42') // returns...
17 | * // {
18 | * // subject: {
19 | * // type: 'user',
20 | * // value: undefined
21 | * // },
22 | * // predicate: {
23 | * // value: 'follow'
24 | * // },
25 | * // object: {
26 | * // type: 'user',
27 | * // value: '42'
28 | * // }
29 | * // }
30 | */
31 | parse: parse
32 | };
33 |
34 | /**
35 | * @param {Object} options The options required for parsing triples
36 | * @param {Object} options.grammar A set of valid triple relations.
37 | * @param {Object} options.vocabulary Extend the known vocabulary by mapping a word stem to a predicate.
38 | * @return {Object} An instance of the nl3 client.
39 | */
40 | module.exports = function create(options) {
41 | //@info triple rules
42 | var tream = rules({
43 | //@info defined triples
44 | grammar: options.grammar || [],
45 | //@info an additional set of words that map to our items with our original grammar
46 | vocabulary: options.vocabulary || {}
47 | });
48 | //@info create & return the new instance
49 | var instance = Object.create(nl3, {
50 | rules: {
51 | enumerable: true,
52 | value: tream
53 | }
54 | });
55 |
56 | return instance;
57 | };
58 |
--------------------------------------------------------------------------------
/lib/first.js:
--------------------------------------------------------------------------------
1 | /**
2 | * returns the first item in an array
3 | * @param {Array} array The array to return the first item from.
4 | * @return {*} The value of the first item in the array or undefined.
5 | */
6 | module.exports = function first(array) {
7 | return array[0];
8 | }
9 |
--------------------------------------------------------------------------------
/lib/object/index.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var objectType = require('./type');
6 | var objectValue = require('./value');
7 |
8 | /**
9 | * Given the parts of speech, this returns an objects type & value.
10 | * @param {Object} parts The parts of speech.
11 | * @return {Object} The parsed objects type & value.
12 | */
13 | module.exports = function object(parts) {
14 | return {
15 | type: objectType(parts),
16 | value: objectValue(parts)
17 | };
18 | };
19 |
--------------------------------------------------------------------------------
/lib/object/type.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var singularize = require('../text/singularize');
6 |
7 | /**
8 | * Given the parts of speech, this returns an objects type.
9 | * @param {Object} parts The parts of speech.
10 | * @return {String} The object type
11 | */
12 | module.exports = function objectType(parts) {
13 | return parts.objects.objects[0] || parts.subjects.subjects[0];
14 | };
15 |
--------------------------------------------------------------------------------
/lib/object/value.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var first = require('../first');
6 |
7 | /**
8 | * Given the parts of speech, this returns an objects value.
9 | * @param {Object} parts The parts of speech.
10 | * @return {String} The objects value.
11 | */
12 | module.exports = function objectValue(parts) {
13 | return first(
14 | parts.objects.after.map(first).concat(
15 | parts.objects.before.map(first)
16 | )
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/lib/parse.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var triple = require('./triple');
6 | var classify = require('./text/classify');
7 |
8 | /**
9 | * parse - parses text into a triple.
10 | * @memberof nl3
11 | * @param {String} text The text to parse.
12 | * @return {Object} The parsed triple.
13 | */
14 | module.exports = function parse(text, callback) {
15 | if (typeof text !== 'string' || !text.trim()) {
16 | var err = new Error(
17 | 'The supplied text could not be parsed into a triple. value: ' + text
18 | );
19 | if (callback) {
20 | return callback(err);
21 | }
22 | throw err;
23 | }
24 | var classification = classify(text);
25 | var trip = triple(
26 | classification,
27 | this.rules
28 | );
29 | return this.rules.process({
30 | triple: trip,
31 | classification: classification
32 | },
33 | callback
34 | );
35 | };
36 |
--------------------------------------------------------------------------------
/lib/predicate/index.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var predicateType = require('./type');
6 | var predicateValue = require('./value');
7 |
8 | /**
9 | * Given the parts of speech, this returns an predicates type & value.
10 | * @param {Object} parts The parts of speech.
11 | * @return {Object} The parsed predicate.
12 | */
13 | module.exports = function predicate(parts, predicates) {
14 | return {
15 | type: predicateType(parts),
16 | value: predicateValue(parts, predicates)
17 | };
18 | };
19 |
--------------------------------------------------------------------------------
/lib/predicate/type.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | /**
6 | * Given the parts of speech, this returns an predicates type.
7 | * @return {undefined}
8 | */
9 | module.exports = function predicateType(pars) {
10 | //@info not yet implemented.
11 | return undefined;
12 | };
13 |
--------------------------------------------------------------------------------
/lib/predicate/value.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var singularize = require('../text/singularize');
6 |
7 | var predicate = require('../rules-engine/parse/predicate')
8 | /**
9 | * Given the parts of speech, this returns an predicates value.
10 | * @param {Object} classification The classification of the text
11 | * @param {Object} rules The known triple rules
12 | * @return {String} The value of the first predicate
13 | */
14 | module.exports = function predicateValue(parts, predicates) {
15 | return parts && parts.predicate && parts.predicate[0] && predicate(
16 | parts.predicate[0], predicates
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/lib/rules-engine/flip/index.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 | var lastPredicate = require('../parse/last-predicate');
5 | /**
6 | * Determines if the "source" triple is valid against the target "rules"
7 | * @access private
8 | * @param {Object} source The source triple to validate.
9 | * @param {Object} target The target rules to validate against.
10 | * @return {Boolean} True if this triple abides by the rules, otherwise false.
11 | */
12 | function itAbides(source, target) {
13 | var subject = target.subjects[source.subject.type];
14 | var predicate = subject && subject.predicates && subject.predicates[source.predicate
15 | .value];
16 | var object = predicate && predicate.objects;
17 |
18 | if (subject && predicate && object.indexOf(source.object.type) > -1) {
19 | return true;
20 | }
21 | return false;
22 | }
23 |
24 | /**
25 | * Flip - Triple Flip
26 | * @type {Object}
27 | */
28 | module.exports = {
29 | /**
30 | * Returns true if the triple should be flipped, as determined by the rules. Otherwise false.
31 | * @param {Object} triple The triple to analyze
32 | * @param {Object} rules The rules to use during analyzation
33 | * @return {Boolean} True if the triple should be flipped, otherwise false.
34 | */
35 | able: function flippable(options) {
36 | var triple = options.triple;
37 | var rules = options.rules;
38 |
39 | if (itAbides(triple, rules) === false) {
40 | return itAbides({
41 | subject: triple.object,
42 | predicate: triple.predicate,
43 | object: triple.subject
44 | }, rules) || itAbides({
45 | subject: triple.object,
46 | predicate: {
47 | type: undefined,
48 | value: lastPredicate(options.classification, rules),
49 | },
50 | object: triple.subject
51 | }, rules) || undefined; //@info returns null if this triple is not valid in either direction.
52 | }
53 | return false;
54 | },
55 | /**
56 | * it - flips the subject and object of a triple
57 | * @param {Object} triple The triple to flip
58 | * @return {Object} The flipped triple
59 | */
60 | it: function flip(options) {
61 | var triple = options.triple;
62 | return {
63 | subject: triple.object,
64 | predicate: {
65 | type: undefined,
66 | value: lastPredicate(options.classification, options.rules),
67 | },
68 | object: triple.subject
69 | };
70 | }
71 | };
72 |
--------------------------------------------------------------------------------
/lib/rules-engine/index.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var flip = require('./flip');
6 | var processRules = require('./rules-processor');
7 | var parse = {
8 | rules: require('./parse/rules')
9 | };
10 |
11 | /**
12 | * creates an instance of a triple rules engine.
13 | * @param {Object} options The options for this rules engine.
14 | * @param {Object} options.grammar A set of valid triple relations.
15 | * @param {Object} options.vocabulary Extend the known vocabulary by mapping a word stem to a predicate.
16 | * @return {Object) The rules engine.
17 | */
18 | module.exports = function rulesEngine(options) {
19 | //@info extract the grammar
20 | var grammar = [].concat(options.grammar || []);
21 |
22 | //@info build the rules engine
23 | var rules = grammar.reduce(parse.rules, {
24 | subjects: {},
25 | predicates: [],
26 | objects: {}
27 | });
28 |
29 | //@property {Function} process - validates & transforms the triple if necessary.
30 | Object.defineProperty(rules, 'process', {
31 | value: processRules(rules)
32 | });
33 |
34 | //@property {Object} vocabulary - contains properties that are stem words, which map to defined predicates.
35 | Object.defineProperty(rules, 'vocabulary', {
36 | enumerable: true,
37 | value: options.vocabulary || {}
38 | });
39 |
40 | //@info return the created engine.
41 | return rules;
42 | };
43 |
--------------------------------------------------------------------------------
/lib/rules-engine/parse/first-non-predicate.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var parsePredicate = require('./predicate');
6 |
7 | /**
8 | * firstNonPredicate returns the first non predicate in array of strings, the extended vocabulary from the grammar rules are also applied.
9 | * @param {Array} tokens An array of strings from a query.
10 | * @param {Object} rules The grammar rules..
11 | * @return {String} The first found predicate, or undefined.
12 | */
13 | module.exports = function firstNonPredicate(tokens, rules) {
14 | var i = 0;
15 | var predicate;
16 | for (i = 0; i < tokens.length; i = i + 1) {
17 | predicate = parsePredicate(tokens[i], rules.vocabulary);
18 | if (!predicate) {
19 | return tokens[i];
20 | }
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/lib/rules-engine/parse/first-predicate.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var parsePredicate = require('./predicate');
6 |
7 | /**
8 | * firstPredicate returns the first predicate from an array of strings, using the vocabulary of the specified grammar rules.
9 | * @param {Object} classification The classification of the text
10 | * @param {Object} rules The known triple rules
11 | * @return {String} The first string that is a predicate from the array of tokens.
12 | */
13 | module.exports = function firstPredicate(classification, rules) {
14 | var tokens = classification.parts.map(function(part) {
15 | return part[0]
16 | });
17 | var i = 0;
18 | var predicate;
19 | for (i = 0; i < tokens.length; i = i + 1) {
20 | predicate = parsePredicate(tokens[i], rules.vocabulary);
21 | if (predicate) {
22 | return {
23 | index: i,
24 | value: predicate
25 | };
26 | }
27 | }
28 | return undefined;
29 | };
30 |
--------------------------------------------------------------------------------
/lib/rules-engine/parse/last-predicate.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var parsePredicate = require('./predicate');
6 |
7 | /**
8 | * lastPredicate returns the last predicate from an array of strings, using the vocabulary of the specified grammar rules.
9 | * @param {Object} classification The classification of the text
10 | * @param {Object} rules The known triple rules
11 | * @return {String} The last string that is a predicate from the array of tokens.
12 | */
13 | module.exports = function lastPredicate(classification, rules) {
14 | var tokens = classification.parts.map(function(part) {
15 | return part[0]
16 | });
17 | var i = 0;
18 | var predicate;
19 | for (i = tokens.length - 1; i < -1; i = i - 1) {
20 | predicate = parsePredicate(tokens[i], rules.vocabulary);
21 | if (predicate) {
22 | return {
23 | index: i,
24 | value: predicate
25 | };
26 | }
27 | }
28 | return undefined;
29 | };
30 |
--------------------------------------------------------------------------------
/lib/rules-engine/parse/objects.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | /**
6 | * Properly stores the subject, predicate and object, within the ruleset.
7 | * @param {Object} rules The ruleset.
8 | * @param {String} subject The subject to include into the rulset.
9 | * @param {String} predicate The predicate to include into the rulset.
10 | * @param {String} object The object to include into the rulset.
11 | * @return {Object} The updated ruleset.
12 | */
13 | module.exports = function includeObjects(rules, subject, predicate, object) {
14 | if (!rules.objects[object]) {
15 | rules.objects[object] = {
16 | predicates: {}
17 | };
18 | }
19 |
20 | var predicates = rules.objects[object].predicates[predicate];
21 |
22 | if (!predicates) {
23 | predicates = rules.objects[object].predicates[predicate] = {
24 | subjects: [subject]
25 | };
26 | }
27 |
28 | return rules;
29 | };
30 |
--------------------------------------------------------------------------------
/lib/rules-engine/parse/parts.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 | var reduceParts = require('./reduce-parts');
5 | var firstPredicate = require('./first-predicate');
6 | /**
7 | * Given classification and a rule set parse the parts of speach.
8 | * @param {Object} classification The classification of the text
9 | * @param {Object} rules The known triple rules
10 | * @return {String} The mapped predicate.
11 | */
12 | module.exports = function parts(classification, rules) {
13 | var predicate = firstPredicate(classification, rules);
14 | var predicateIndex = predicate && predicate.index || undefined;
15 | var prepositionIndex = classification.parts.reduce(function(result, part) {
16 | if (part[1] === 'IN') {
17 | result.found = true
18 | }
19 | if (!result.found) {
20 | result.index = result.index + 1;
21 | }
22 | return result;
23 | }, {
24 | index: 0,
25 | found: false
26 | }).index;
27 |
28 | var index = predicate && predicate.index
29 | var beforePredicate = index && classification.parts.slice(0, index) || [];
30 | var afterPredicate = index && classification.parts.slice(index + 1) || [];
31 |
32 | return {
33 | objects: reduceParts(afterPredicate, rules),
34 | subjects: reduceParts(beforePredicate, rules),
35 | predicate: predicate && classification.parts[predicate.index] || undefined
36 | };
37 | };
38 |
--------------------------------------------------------------------------------
/lib/rules-engine/parse/predicate.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var stemmer = require('stemmer');
6 | var singularize = require('../../text/singularize');
7 |
8 | /**
9 | * Given text and a array mapping of predicates, returns the mapped predicate.
10 | * @param {String} text The text to map to a predicate.
11 | * @param {Object} predicates An object whose keys are word stems and values are predicates that have been defined within the grammar.
12 | * @return {String} The mapped predicate.
13 | */
14 | module.exports = function mapPredicate(text, predicates) {
15 | var predicate = stemmer(
16 | singularize(text)
17 | );
18 | return predicates && predicates[predicate] || undefined;
19 | };
20 |
--------------------------------------------------------------------------------
/lib/rules-engine/parse/reduce-parts.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var firstPredicate = require('./last-predicate');
6 | var singularize = require('../../text/singularize');
7 | /**
8 | * Given an array of strings, identifies valid objects or subjects in the order they occur.
9 | * @param {Array} data An array of tokenized strings.
10 | * @param {Object} rules The known triple rules.
11 | * @return {String} The mapped predicate.
12 | */
13 | module.exports = function reduceParts(data, rules) {
14 | var parts = {
15 | objects: [],
16 | subjects: [],
17 | before: [],
18 | after: []
19 | };
20 | return data && data.reduce(function(result, part) {
21 | var normalizedPart = singularize(part[0]);
22 | var added = false;
23 | if (rules.objects[normalizedPart]) {
24 | result.objects.push(normalizedPart);
25 | added = true;
26 | }
27 | if (rules.subjects[normalizedPart]) {
28 | result.subjects.push(normalizedPart);
29 | added = true;
30 | }
31 | if (!added && part[1] !== 'IN' && part[1][0] !== 'W') {
32 | if (!result.subjects.length && !result.objects.length) {
33 | result.before.push(part);
34 | } else {
35 | result.after.push(part);
36 | }
37 | }
38 | return result;
39 | }, parts) || parts;
40 | };
41 |
--------------------------------------------------------------------------------
/lib/rules-engine/parse/reduce-predicates.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | /**
6 | * reducePredicates reduces the predicates from an array into the grammar rules.
7 | * If a predicate is found to be a member of the grammar rules, it is added as a predicate.
8 | * @param {Object} rules The grammar rules.
9 | * @param {String} predicate The predicate to attempt to parse.
10 | * @return {Object} rules The grammar rules.
11 | */
12 | module.exports = function reducePredicates(rules, predicate) {
13 | if (rules.predicates.indexOf(predicate) === -1) {
14 | rules.predicates.push(predicate);
15 | }
16 | return rules;
17 | };
18 |
--------------------------------------------------------------------------------
/lib/rules-engine/parse/rules.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var parseSubjects = require('./subjects');
6 | var parsePredicates = require('./reduce-predicates');
7 | var parseObjects = require('./objects');
8 | var singularize = require('../../text/singularize');
9 |
10 | /**
11 | * parses the grammar rules from a string array.
12 | * @param {Object} ruleset The ruleset to apply the parsed grammar rules to.
13 | * @param {Array} data An array of strings representing the grammar rules.
14 | * @return {Object} The parsed grammar rules.
15 | */
16 | module.exports = function rules(ruleset, data) {
17 | data = data.toString().split(' ');
18 |
19 | var subject = singularize(data[0]);
20 | var predicate = singularize(data[1]);
21 | var object = singularize(data[2]);
22 |
23 | ruleset = parseSubjects(ruleset, subject, predicate, object);
24 | ruleset = parsePredicates(ruleset, predicate);
25 | ruleset = parseObjects(ruleset, subject, predicate, object);
26 |
27 | return ruleset;
28 | };
29 |
--------------------------------------------------------------------------------
/lib/rules-engine/parse/subjects.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | /**
6 | * Properly stores the subject, predicate and object, within the ruleset.
7 | * @param {Object} rules The ruleset.
8 | * @param {String} subject The subject to include into the rulset.
9 | * @param {String} predicate The predicate to include into the rulset.
10 | * @param {String} object The object to include into the rulset.
11 | * @return {Object} The updated ruleset.
12 | */
13 | module.exports = function includeSubjects(rules, subject, predicate, object) {
14 | if (!rules.subjects[subject]) {
15 | rules.subjects[subject] = {
16 | predicates: {}
17 | };
18 | }
19 |
20 | var predicates = rules.subjects[subject].predicates[predicate];
21 |
22 | if (!predicates) {
23 | predicates = rules.subjects[subject].predicates[predicate] = {
24 | objects: [object]
25 | };
26 | }
27 |
28 | return rules;
29 | };
30 |
--------------------------------------------------------------------------------
/lib/rules-engine/rules-processor.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var flip = require('./flip');
6 |
7 | /**
8 | * Evaluates and returns triple, resolves any issues if necessary. An error is thrown if the triple is invalid.
9 | * @param {Object} triple The triple to process
10 | * @param {Function} callback The callback used to handle the result.
11 | */
12 | module.exports = function rulesProcessor(rules) {
13 | return function processRules(options, callback) {
14 | var triple = options.triple;
15 | var classification = options.classification;
16 | var opts = {
17 | triple: triple,
18 | classification: classification,
19 | rules: rules
20 | };
21 | var shouldFlip = flip.able(opts); //@info returns null if invalid.
22 | if (shouldFlip === true) {
23 | triple = flip.it(opts);
24 | return (callback && callback(null, triple)) || triple;
25 | }
26 | if (shouldFlip === false) {
27 | return (callback && callback(null, triple)) || triple;
28 | }
29 | //@info if we've received null, then return error.
30 | var err = new Error('Invalid triple:\n' + JSON.stringify(triple, null,
31 | ' '));
32 | if (callback) {
33 | return callback(err, triple);
34 | }
35 | throw err;
36 | };
37 | };
38 |
--------------------------------------------------------------------------------
/lib/subject/index.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var subjectType = require('./type');
6 | var subjectValue = require('./value');
7 |
8 | /**
9 | * Given the parts of speech, this returns an subjects type & value.
10 | * @param {Object} parts The parts of speech.
11 | * @return {Object} The parsed subjects type & value.
12 | */
13 | module.exports = function subject(parts) {
14 | return {
15 | type: subjectType(parts),
16 | value: subjectValue(parts)
17 | };
18 | };
19 |
--------------------------------------------------------------------------------
/lib/subject/type.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var singularize = require('../text/singularize');
6 |
7 | /**
8 | * Given the parts of speech, this returns an subjects type.
9 | * @param {Object} parts The parts of speech.
10 | * @return {String} The subject type
11 | */
12 | module.exports = function subjectType(parts) {
13 | return parts.subjects.subjects[0] || parts.subjects.objects[0];
14 | };
15 |
--------------------------------------------------------------------------------
/lib/subject/value.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var first = require('../first');
6 |
7 | /**
8 | * Given the parts of speech, this returns an subjects value.
9 | * @param {Object} parts The parts of speech.
10 | * @return {String} The subjects value.
11 | */
12 | module.exports = function subjectValue(parts) {
13 | return first(
14 | parts.subjects.after.map(first).concat(
15 | parts.subjects.before.map(first)
16 | )
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/lib/text/classify.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var pos = require('pos');
6 | var speakEasy = require('speakeasy-nlp');
7 |
8 | var lexer = new pos.Lexer();
9 | var tagger = new pos.Tagger();
10 |
11 | /**
12 | * Classifys the text within a given query ( identifies, nouns, subjects, verbs etc...).
13 | * @param {String} text The text to classify.
14 | * @return {Object} The text classification.
15 | */
16 | module.exports = function classify(text) {
17 | //@info classify the text within the text
18 | var classification = speakEasy.classify(text);
19 | classification.parts = tagger.tag(
20 | lexer.lex(text)
21 | );
22 | classification.text = text.trim();
23 | classification.value = parse(text);
24 | return classification;
25 | };
26 |
27 |
28 | function tag(text) {
29 | return tagger.tag(
30 | lexer.lex(text)
31 | );
32 | }
33 |
34 | function parse(text) {
35 | var parts = tag(text).reduce(function(result, tag) {
36 | if (tag[1] !== 'IN' && (tag[1][tag[1].length - 1] === 'N' || tag[1][0] === 'N') || tag[1] === 'CD') {
37 | if (!result.predicate.length) {
38 | result.subject = result.subject.concat(tag[0]);
39 | } else {
40 | result.object = result.object.concat(tag[0]);
41 | }
42 | }
43 | if (tag[1][0] === 'V') {
44 | if (!result.predicate.length) {
45 | result.predicate = result.predicate.concat(tag[0]);
46 | }
47 | }
48 | return result;
49 | }, {
50 | subject: [],
51 | predicate: [],
52 | object: []
53 | });
54 | return format(parts);
55 | }
56 |
57 |
58 | function format(parts) {
59 |
60 | if (parts.subject.length > 2 && !parts.object.length) {
61 | parts.object = parts.subject.splice(0, 1);
62 | }
63 | return {
64 | subject: {
65 | type: parts.subject[0],
66 | value: parts.subject[1]
67 | },
68 | predicate: {
69 | type: parts.predicate[1],
70 | value: parts.predicate[0]
71 | },
72 | object: {
73 | type: parts.object[0],
74 | value: parts.object[1]
75 | }
76 | };
77 | }
78 |
--------------------------------------------------------------------------------
/lib/text/is/plural.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var singularize = require('../singularize');
6 |
7 | /**
8 | * Returns true if the text is pluralized.
9 | * @param {String} text
10 | * @return {Boolean}
11 | */
12 | module.exports = function isPlural(text) {
13 | var textEndsWithS = text[text.length - 1].toLowerCase() === 's';
14 | var textMatchesSingularForm = text.toLowerCase() !== singularize(text).toLowerCase();
15 |
16 | if (textMatchesSingularForm || textEndsWithS) {
17 | return true;
18 | }
19 |
20 | return false;
21 | };
22 |
--------------------------------------------------------------------------------
/lib/text/singularize.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var singular = require('pluralize').singular;
6 |
7 | /**
8 | * Given text, returns the singularized form. ie: cats => cat.
9 | * @param {String} text [description]
10 | * @return {String} [description]
11 | */
12 | module.exports = function singularize(text) {
13 | //@info if text exists, return the singularized form, otherwise return the input.
14 | return (text && singular(text)) || text;
15 | };
16 |
--------------------------------------------------------------------------------
/lib/triple.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require*/
3 | 'use strict';
4 |
5 | var object = require('./object');
6 | var subject = require('./subject');
7 | var predicate = require('./predicate');
8 |
9 | var parseParts = require('./rules-engine/parse/parts');
10 |
11 | /**
12 | * Given a classification and a ruleset - returns a triple.
13 | * @param {Array} grammar A list of possible triples.
14 | * @param {Object} vocabulary Extend the known vocabulary by mapping a word stem to a predicate.
15 | * @return {Object} The parsed triple.
16 | */
17 | module.exports = function triple(classification, rules) {
18 | var parts = parseParts(classification, rules);
19 | return {
20 | subject: subject(parts),
21 | predicate: predicate(parts, rules.vocabulary),
22 | object: object(parts)
23 | };
24 | };
25 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/defstream/nl3/418f58b112b35c9108bb3a8c03332b9f1f45907c/logo.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nl3",
3 | "version": "0.0.3",
4 | "description": "nl3 - natural language triples",
5 | "license": "MIT",
6 | "author": "Hector Gray (https://github.com/defstream)",
7 | "main": "index.js",
8 | "engines": {
9 | "node": ">=0.10"
10 | },
11 | "scripts": {
12 | "doc": "jsdoc -R ./README.md -r -d ./doc/api ./lib ./index.js",
13 | "test": "snyk test && istanbul cover --dir ./doc/coverage _mocha -- --recursive && cat ./doc/coverage/lcov.info | ./node_modules/codecov/bin/codecov",
14 | "analyze": "plato -d ./doc/analysis -r ./lib ./index.js",
15 | "clean": "rm -rf ./doc",
16 | "build": "npm run clean && npm run doc && npm run test && npm run analyze"
17 | },
18 | "keywords": [
19 | "nl3",
20 | "nl",
21 | "l3n",
22 | "lne3",
23 | "n3l",
24 | "natural",
25 | "language",
26 | "triple",
27 | "tripple",
28 | "3",
29 | "nodejs",
30 | "node",
31 | "rdf",
32 | "triples",
33 | "english",
34 | "text",
35 | "graph",
36 | "search",
37 | "javascript"
38 | ],
39 | "dependencies": {
40 | "neo-async": "1.8.2",
41 | "pluralize": "1.2.1",
42 | "pos": "0.3.0",
43 | "speakeasy-nlp": "0.2.2",
44 | "stemmer": "0.1.4"
45 | },
46 | "devDependencies": {
47 | "chai": "3.5.0",
48 | "snyk": "1.14.3",
49 | "codecov": "1.0.1",
50 | "istanbul": "0.4.3",
51 | "jsdoc": "3.4.0",
52 | "mocha": "2.4.5",
53 | "plato": "1.5.0"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/test/check.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require,describe,it*/
3 | 'use strict';
4 |
5 | var async = require('neo-async');
6 | var mocha = require('mocha');
7 | var expect = require('chai').expect;
8 |
9 | function test(triple, expected) {
10 | it('should have subject.type equal to ' + expected.subject.type, function(
11 | done) {
12 | expect(triple.subject.type).to.equal(expected.subject.type);
13 | done();
14 | });
15 | it('should have subject.value equal to ' + expected.subject.value, function(
16 | done) {
17 | expect(triple.subject.value).to.equal(expected.subject.value);
18 | done();
19 | });
20 |
21 | it('should have predicate.value equal to ' + expected.predicate.value,
22 | function(done) {
23 | expect(triple.predicate.value).to.equal(expected.predicate.value);
24 | done();
25 | });
26 |
27 | it('should have predicate.type equal to ' + expected.predicate.type, function(
28 | done) {
29 | expect(triple.predicate.type).to.equal(expected.predicate.type);
30 | done();
31 | });
32 | it('should have object.type equal to ' + expected.object.type, function(done) {
33 | expect(triple.object.type).to.equal(expected.object.type);
34 | done();
35 | });
36 | it('should have object.value equal to ' + expected.object.value, function(
37 | done) {
38 | expect(triple.object.value).to.equal(expected.object.value);
39 | done();
40 | });
41 | };
42 |
43 | /**
44 | * exports check - validates a triple against another object.
45 | * @param {Array} triples
46 | */
47 | module.exports = function check(triples) {
48 | return {
49 | against: function(expected) {
50 | async.eachSeries(triples, function(triple, done) {
51 | test(triple, expected);
52 | done();
53 | });
54 | }
55 | };
56 | };
57 |
--------------------------------------------------------------------------------
/test/messenger/client/001-client.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require,describe,it*/
3 | 'use strict';
4 |
5 | var mocha = require('mocha');
6 | var assert = require('assert');
7 | var expect = require('chai').expect;
8 |
9 | var nl3 = new require('../client')();
10 | var check = require('../../check.js');
11 |
12 | describe('invalid parse parameters', function() {
13 | it('should fail parsing - no parameters', function() {
14 | expect(function() {
15 | nl3.parse();
16 | }).to.throw(Error);
17 | });
18 | it('should fail parsing - undefined', function() {
19 | expect(function() {
20 | nl3.parse(undefined);
21 | }).to.throw(Error);
22 | });
23 | it('should fail parsing - " "', function() {
24 | expect(function() {
25 | nl3.parse(' ');
26 | }).to.throw(Error);
27 | });
28 | it('should fail parsing - " "', function() {
29 | expect(function() {
30 | nl3.parse(' ');
31 | }).to.throw(Error);
32 | });
33 | it('should fail parsing non string - 42', function() {
34 | expect(function() {
35 | nl3.parse(42);
36 | }).to.throw(Error);
37 | });
38 | it('should fail parsing non string - {}', function() {
39 | expect(function() {
40 | nl3.parse({});
41 | }).to.throw(Error);
42 | });
43 | it('should fail parsing invalid triple - dogs hate cats', function() {
44 | expect(function() {
45 | nl3.parse('dog jim hates cat sue');
46 | }).to.throw(Error);
47 | });
48 | });
49 |
50 |
51 | describe('parse + callback', function() {
52 | it('should fail parsing - no parameters', function(done) {
53 | nl3.parse(null, function(err, result) {
54 | expect(err).to.be.instanceOf(Error);
55 | done();
56 | });
57 | });
58 |
59 | it('should fail parsing - invalid triple', function(done) {
60 | nl3.parse('monkey a jumped on bed b', function(err, result) {
61 | expect(err).to.be.instanceOf(Error);
62 | done();
63 | });
64 | });
65 |
66 | it('should pass parsing - valid triple', function(done) {
67 | nl3.parse('user Aaron messaged user Micah', function(err, result) {
68 | assert(expect(err).to.not.exist);
69 | done();
70 | });
71 | });
72 |
73 | it('should fail parsing - reversed triple', function(done) {
74 | nl3.parse('message 32 created user bob', function(err, result) {
75 | expect(err).to.be.instanceOf(Error);
76 | done();
77 | });
78 | });
79 | });
80 |
--------------------------------------------------------------------------------
/test/messenger/client/index.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require,describe,it*/
3 | 'use strict';
4 |
5 | var client = require('../../../index');
6 |
7 | module.exports = function createClient() {
8 | return client({
9 | /**
10 | * The grammar rules for creating valid triples
11 | * @type {Array}
12 | */
13 | grammar: [
14 | 'users follow users',
15 | 'users mention content',
16 | 'users create messages',
17 | 'users send messages',
18 | 'users receive messages',
19 | 'users message users'
20 | ],
21 | /**
22 | * Allows you to extend the vocabulary of your predicates mapping phonetic roots to your existing grammar.
23 | * @type {Object}
24 | */
25 | vocabulary: {
26 | follow: 'follow', // user bob followed user jill
27 | stalk: 'follow', // user bob stalked user tom
28 | watch: 'follow', // user bob watches user bill
29 | creat: 'create', // user bob created message 12
30 | made: 'create', // user bob made mesage 34
31 | wrote: 'create', // user bob wrote mesage 55
32 | send: 'send', // user bob sends message 12
33 | sent: 'send', // user bob sent message 34
34 | mail: 'send', // user bob mailed message 55
35 | retriev: 'receive', // user jill recieved message 12
36 | receiv: 'receive', // user tom received message 34
37 | reciev: 'receive', // user tom recieved message 34
38 | got: 'receive', // user bill got message 55
39 | messag: 'message', // user bob messaged user jill
40 | msg: 'message', // user bob msgd user tom
41 | contact: 'message', // user bob msgd conctacted user bill
42 | }
43 | });
44 | };
45 |
--------------------------------------------------------------------------------
/test/messenger/follow/001-user-follows-user.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require,describe,it*/
3 | 'use strict';
4 |
5 | var mocha = require('mocha');
6 | var expect = require('chai').expect;
7 | var nl3 = require('../client')();
8 | var check = require('../../check.js');
9 |
10 | describe('users following users', function test() {
11 | var queries = [
12 | nl3.parse('users that follow user 42'),
13 | nl3.parse('users who follow user 42'),
14 | nl3.parse('users following user 42'),
15 | nl3.parse('users followed user 42'),
16 | nl3.parse('users which follow user 42'),
17 | nl3.parse('users stalking user 42'),
18 | nl3.parse('users who stalk user 42'),
19 | nl3.parse('users which stalk user 42'),
20 | nl3.parse('users watching user 42'),
21 | nl3.parse('users who watch user 42'),
22 | nl3.parse('users followed by user 42')
23 | ];
24 | check(queries).against({
25 | subject: {
26 | type: 'user',
27 | value: undefined
28 | },
29 | predicate: {
30 | value: 'follow'
31 | },
32 | object: {
33 | type: 'user',
34 | value: '42'
35 | }
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/test/messenger/message/001-user-creates-message.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require,describe,it*/
3 | 'use strict';
4 |
5 | var mocha = require('mocha');
6 | var nl3 = new require('../client')();
7 | var check = require('../../check.js');
8 |
9 | describe('users create messages', function() {
10 | var queries = [
11 | nl3.parse('user bob creates message 42'),
12 | nl3.parse('user bob created message 42'),
13 | nl3.parse('user bob wrote message 42'),
14 | nl3.parse('user bob made message 42')
15 | ];
16 | check(queries).against({
17 | subject: {
18 | type: 'user',
19 | value: 'bob'
20 | },
21 | predicate: {
22 | value: 'create'
23 | },
24 | object: {
25 | type: 'message',
26 | value: '42'
27 | }
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/test/messenger/message/002-user-sends-message.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require,describe,it*/
3 | 'use strict';
4 |
5 | var mocha = require('mocha');
6 | var nl3 = require('../client')();
7 | var check = require('../../check.js');
8 |
9 | describe('users sends messages', function() {
10 | var queries = [
11 | nl3.parse('user bob sent message 42'),
12 | nl3.parse('user bob sends message 42'),
13 | nl3.parse('user bob mailed message 42'),
14 | nl3.parse('user bob sended message 42')
15 | ];
16 | check(queries).against({
17 | subject: {
18 | type: 'user',
19 | value: 'bob'
20 | },
21 | predicate: {
22 | value: 'send'
23 | },
24 | object: {
25 | type: 'message',
26 | value: '42'
27 | }
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/test/messenger/message/003-user-receives-message.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require,describe,it*/
3 | 'use strict';
4 |
5 | var mocha = require('mocha');
6 | var nl3 = require('../client')();
7 | var check = require('../../check.js');
8 |
9 | describe('user receives message', function() {
10 | var queries = [
11 | nl3.parse('user bob got message 42'),
12 | nl3.parse('user bob received message 42'),
13 | nl3.parse('user bob retrieved message 42'),
14 | nl3.parse('user bob recieved message 42')
15 | ];
16 | check(queries).against({
17 | subject: {
18 | type: 'user',
19 | value: 'bob'
20 | },
21 | predicate: {
22 | value: 'receive'
23 | },
24 | object: {
25 | type: 'message',
26 | value: '42'
27 | }
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/test/messenger/message/004-user-messages-user.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module, require,describe,it*/
3 | 'use strict';
4 |
5 | var mocha = require('mocha');
6 | var nl3 = new require('../client')();
7 | var check = require('../../check.js');
8 |
9 | describe('user messages user', function() {
10 | var queries = [
11 | nl3.parse('user bob msg user jill'),
12 | nl3.parse('user bob msgs user jill'),
13 | nl3.parse('user bob messaged user jill'),
14 | nl3.parse('user bob contacted user jill'),
15 | nl3.parse('user bob contacts user jill')
16 | ];
17 | check(queries).against({
18 | subject: {
19 | type: 'user',
20 | value: 'bob'
21 | },
22 | predicate: {
23 | value: 'message'
24 | },
25 | object: {
26 | type: 'user',
27 | value: 'jill'
28 | }
29 | });
30 | });
31 |
--------------------------------------------------------------------------------
/test/unit/flip/001-flip.js:
--------------------------------------------------------------------------------
1 | /*jslint node: true */
2 | /*global module,require,describe,it*/
3 | 'use strict';
4 |
5 | var assert = require('assert');
6 | var mocha = require('mocha');
7 | var expect = require('chai').expect;
8 |
9 | var flip = require('../../../lib/rules-engine/flip');
10 | var check = require('../../check.js');
11 |
12 | describe('Flip.it', function() {
13 | it('should exist', function() {
14 | assert(expect(flip).to.exist);
15 | assert(expect(flip.it).to.exist);
16 | });
17 |
18 | function opts(triple) {
19 | return {
20 | "classification": {
21 | "owner": "message 32 created user bob",
22 | "subject": "message 32 created user bob",
23 | "tokens": [
24 | "message",
25 | "32",
26 | "created",
27 |
28 | "user",
29 | "bob",
30 | "."
31 | ],
32 | "verbs": [
33 | "created"
34 | ],
35 | "nouns": [
36 | "message",
37 | "user",
38 | "bob"
39 | ],
40 | "adjectives": [],
41 | "parts": [
42 | [
43 | "message",
44 | "NN"
45 | ],
46 | [
47 | "32",
48 | "CD"
49 | ],
50 | [
51 | "created",
52 | "VBN"
53 | ],
54 | [
55 | "user",
56 | "NN"
57 | ],
58 | [
59 | "bob",
60 | "NN"
61 | ]
62 | ],
63 | "text": "message 32 created user bob",
64 | "value": {
65 | "subject": {
66 | "type": "message",
67 | "value": "32"
68 | },
69 | "predicate": {
70 | "value": "created"
71 | },
72 | "object": {
73 | "type": "user",
74 | "value": "bob",
75 | }
76 | }
77 | },
78 | "triple": triple,
79 | "rules": {
80 | "subjects": {
81 | "user": {
82 | "predicates": {
83 | "follow": {
84 | "objects": [
85 | "user"
86 | ]
87 | },
88 | "mention": {
89 | "objects": [
90 | "content"
91 | ]
92 | },
93 | "create": {
94 | "objects": [
95 | "message"
96 | ]
97 | },
98 | "send": {
99 | "objects": [
100 | "message"
101 | ]
102 | },
103 | "receive": {
104 | "objects": [
105 | "message"
106 | ]
107 | },
108 | "message": {
109 | "objects": [
110 | "user"
111 | ]
112 | }
113 | }
114 | }
115 | },
116 | "predicates": [
117 | "follow",
118 | "mention",
119 | "create",
120 | "send",
121 | "receive",
122 | "message"
123 | ],
124 | "objects": {
125 | "user": {
126 | "predicates": {
127 | "follow": {
128 | "subjects": [
129 | "user"
130 | ]
131 | },
132 | "message": {
133 | "subjects": [
134 | "user"
135 | ]
136 | }
137 | }
138 | },
139 | "content": {
140 | "predicates": {
141 | "mention": {
142 | "subjects": [
143 | "user"
144 | ]
145 | }
146 | }
147 | },
148 | "message": {
149 | "predicates": {
150 | "create": {
151 | "subjects": [
152 | "user"
153 | ]
154 | },
155 | "send": {
156 | "subjects": [
157 | "user"
158 | ]
159 | },
160 | "receive": {
161 | "subjects": [
162 | "user"
163 | ]
164 | }
165 | }
166 | }
167 | },
168 | "vocabulary": {
169 | "follow": "follow",
170 | "stalk": "follow",
171 | "watch": "follow",
172 | "creat": "create",
173 | "made": "create",
174 | "wrote": "create",
175 | "send": "send",
176 | "sent": "send",
177 | "mail": "send",
178 | "retriev": "receive",
179 | "receiv": "receive",
180 | "reciev": "receive",
181 | "got": "receive",
182 | "messag": "message",
183 | "msg": "message",
184 | "contact": "message"
185 | }
186 | }
187 | };
188 |
189 | }
190 | it('should flip different', function() {
191 | var triple = {
192 | subject: {
193 | type: 'user',
194 | value: 'Bob'
195 | },
196 | predicate: {
197 | value: 'message'
198 | },
199 | object: {
200 | type: 'user',
201 | value: 'Bob'
202 | }
203 | };
204 |
205 | var originalSubject = triple.subject;
206 | var originalObject = triple.object;
207 | var flippedTriple = flip.it(opts(triple));
208 |
209 | expect(flippedTriple.object).to.equal(originalSubject);
210 | expect(flippedTriple.subject).to.equal(originalObject);
211 | });
212 | });
213 |
--------------------------------------------------------------------------------
/wercker.yml:
--------------------------------------------------------------------------------
1 | # This references the default nodejs container from
2 | # the Docker Hub: https://registry.hub.docker.com/_/node/
3 | # If you want Nodesource's container you would reference nodesource/node
4 | # Read more about containers on our dev center
5 | # http://devcenter.wercker.com/docs/containers/index.html
6 | box: node
7 | # This is the build pipeline. Pipelines are the core of wercker
8 | # Read more about pipelines on our dev center
9 | # http://devcenter.wercker.com/docs/pipelines/index.html
10 |
11 | # You can also use services such as databases. Read more on our dev center:
12 | # http://devcenter.wercker.com/docs/services/index.html
13 | # services:
14 | # - postgres
15 | # http://devcenter.wercker.com/docs/services/postgresql.html
16 |
17 | # - mongodb
18 | # http://devcenter.wercker.com/docs/services/mongodb.html
19 | build:
20 | # The steps that will be executed on build
21 | # Steps make up the actions in your pipeline
22 | # Read more about steps on our dev center:
23 | # http://devcenter.wercker.com/docs/steps/index.html
24 | steps:
25 | # A step that executes `npm install` command
26 | - npm-install
27 | # A step that executes `npm test` command
28 | - npm-test
29 |
30 | # A custom script step, name value is used in the UI
31 | # and the code value contains the command that get executed
32 | - script:
33 | name: echo nodejs information
34 | code: |
35 | echo "node version $(node -v) running"
36 | echo "npm version $(npm -v) running"
37 |
--------------------------------------------------------------------------------