mqtt-pattern 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,6 +21,13 @@ var params = MQTTPattern.exec(pattern, topic);
21
21
  data: ["rate", "bmp"]
22
22
  }
23
23
 
24
+ var filled = MQTTPattern.fill(pattern, params);
25
+ // filled will be
26
+ "device/fitbit/undefined/rate/bmp"
27
+
28
+ MQTTPattern.clean("hello/+param1/world/#param2");
29
+ // hello/+/world/#
30
+
24
31
  ```
25
32
 
26
33
  ## Installing
@@ -46,6 +53,9 @@ Useful if you know in advance that your `topic` will be valid and want to extrac
46
53
  If the `topic` doesn't match, or the `pattern` doesn't contain named wildcards, returns an empty object.
47
54
  Do not use this for validation.
48
55
 
56
+ ### `fill(pattern : String, params: Object) : String`
57
+ Reverse of `extract`, traverse the `pattern` and fill in params with keys in an object. Missing keys for `+` params are set to `undefined`. Missing keys for `#` params yeid empty strings.
58
+
49
59
  ## How params work
50
60
 
51
61
  MQTT defines two types of "wildcards", one for matching a single section of the path (`+`), and one for zero or more sections of the path (`#`).
package/index.js CHANGED
@@ -7,6 +7,8 @@ module.exports = {
7
7
  matches: matches,
8
8
  extract: extract,
9
9
  exec: exec,
10
+ fill: fill,
11
+ clean: clean
10
12
  };
11
13
 
12
14
  function exec(pattern, topic) {
@@ -26,7 +28,10 @@ function matches(pattern, topic) {
26
28
  var patternChar = currentPattern[0];
27
29
  var currentTopic = topicSegments[i];
28
30
 
29
- if(!currentTopic) return false;
31
+ if(!currentTopic && !currentPattern)
32
+ continue;
33
+
34
+ if(!currentTopic && currentPattern !== ALL) return false;
30
35
 
31
36
  // Only allow # at end
32
37
  if(patternChar === ALL)
@@ -38,6 +43,34 @@ function matches(pattern, topic) {
38
43
  return patternLength === topicLength;
39
44
  }
40
45
 
46
+ function fill(pattern, params){
47
+ var patternSegments = pattern.split(SEPARATOR);
48
+ var patternLength = patternSegments.length;
49
+
50
+ var result = [];
51
+
52
+ for (var i = 0; i < patternLength; i++) {
53
+ var currentPattern = patternSegments[i];
54
+ var patternChar = currentPattern[0];
55
+ var patternParam = currentPattern.slice(1);
56
+ var paramValue = params[patternParam];
57
+
58
+ if(patternChar === ALL){
59
+ // Check that it isn't undefined
60
+ if(paramValue !== void 0)
61
+ result.push([].concat(paramValue).join(SEPARATOR)); // Ensure it's an array
62
+
63
+ // Since # wildcards are always at the end, break out of the loop
64
+ break;
65
+ } else if (patternChar === SINGLE)
66
+ // Coerce param into a string, missing params will be undefined
67
+ result.push("" + paramValue);
68
+ else result.push(currentPattern);
69
+ }
70
+
71
+ return result.join(SEPARATOR);
72
+ }
73
+
41
74
 
42
75
  function extract(pattern, topic) {
43
76
  var params = {};
@@ -63,3 +96,26 @@ function extract(pattern, topic) {
63
96
 
64
97
  return params;
65
98
  }
99
+
100
+
101
+ function clean(pattern) {
102
+ var patternSegments = pattern.split(SEPARATOR);
103
+ var patternLength = patternSegments.length;
104
+
105
+ var cleanedSegments = [];
106
+
107
+ for(var i = 0; i < patternLength; i++){
108
+ var currentPattern = patternSegments[i];
109
+ var patternChar = currentPattern[0];
110
+
111
+ if(patternChar === ALL){
112
+ cleanedSegments.push(ALL);
113
+ } else if(patternChar === SINGLE){
114
+ cleanedSegments.push(SINGLE);
115
+ } else {
116
+ cleanedSegments.push(currentPattern);
117
+ }
118
+ }
119
+
120
+ return cleanedSegments.join('/');
121
+ }
package/package.json CHANGED
@@ -1,33 +1,33 @@
1
- {
2
- "name": "mqtt-pattern",
3
- "version": "1.0.0",
4
- "description": "Fast library for matching MQTT patterns with named wildcards",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "node test"
8
- },
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/RangerMauve/mqtt-pattern.git"
12
- },
13
- "keywords": [
14
- "mqtt",
15
- "pattern",
16
- "match",
17
- "topic"
18
- ],
19
- "author": "rangermauve",
20
- "license": "MIT",
21
- "bugs": {
22
- "url": "https://github.com/RangerMauve/mqtt-pattern/issues"
23
- },
24
- "homepage": "https://github.com/RangerMauve/mqtt-pattern#readme",
25
- "devDependencies": {
26
- "eslint": "^3.19.0",
27
- "eslint-plugin-node": "^4.2.2",
28
- "tape": "^4.6.3"
29
- },
30
- "dependencies": {
31
- "mqtt-match": "^1.0.2"
32
- }
33
- }
1
+ {
2
+ "name": "mqtt-pattern",
3
+ "version": "1.2.0",
4
+ "description": "Fast library for matching MQTT patterns with named wildcards",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "node test"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/RangerMauve/mqtt-pattern.git"
12
+ },
13
+ "keywords": [
14
+ "mqtt",
15
+ "pattern",
16
+ "match",
17
+ "topic"
18
+ ],
19
+ "author": "rangermauve",
20
+ "license": "MIT",
21
+ "bugs": {
22
+ "url": "https://github.com/RangerMauve/mqtt-pattern/issues"
23
+ },
24
+ "homepage": "https://github.com/RangerMauve/mqtt-pattern#readme",
25
+ "devDependencies": {
26
+ "eslint": "^3.19.0",
27
+ "eslint-plugin-node": "^4.2.2",
28
+ "tape": "^4.6.3"
29
+ },
30
+ "dependencies": {
31
+ "mqtt-match": "^1.0.2"
32
+ }
33
+ }
package/test.js CHANGED
@@ -1,4 +1,5 @@
1
1
  "use strict";
2
+
2
3
  var test = require("tape");
3
4
 
4
5
  var MQTTPattern = require("./");
@@ -23,6 +24,11 @@ test("matches() supports patterns with # at the end", function (t) {
23
24
  t.ok(MQTTPattern.matches("foo/#", "foo/bar/baz"), "Matched topic");
24
25
  });
25
26
 
27
+ test("matches() supports patterns with # at the end and topic has no children", function (t) {
28
+ t.plan(1);
29
+ t.ok(MQTTPattern.matches("foo/bar/#", "foo/bar"), "Matched childless topic");
30
+ });
31
+
26
32
  test("matches() doesn't support # wildcards with more after them", function (t) {
27
33
  t.plan(1);
28
34
  t.notOk(MQTTPattern.matches("#/bar/baz", "foo/bar/baz"), "Didn't match topic");
@@ -53,6 +59,12 @@ test("matches() supports named wildcards", function (t) {
53
59
  t.ok(MQTTPattern.matches("foo/+something/#else", "foo/bar/baz"), "Matched topic");
54
60
  });
55
61
 
62
+ test("matches() supports leading slashes", function (t){
63
+ t.plan(2);
64
+ t.ok(MQTTPattern.matches("/foo/bar", "/foo/bar"), "Matched topic");
65
+ t.notok(MQTTPattern.matches("/foo/bar", "/bar/foo"), "Didn't match invalid topic");
66
+ });
67
+
56
68
  test("extract() returns empty object of there's nothing to extract", function (t) {
57
69
  t.plan(1);
58
70
  t.deepEqual(MQTTPattern.extract("foo/bar/baz", "foo/bar/baz"), {}, "Extracted empty object");
@@ -99,3 +111,57 @@ test("exec() returns params if they can be parsed", function(t){
99
111
  world: ["baz"]
100
112
  }, "Extracted params");
101
113
  });
114
+
115
+ test("fill() fills in pattern with both types of wildcards", function(t){
116
+ t.plan(1);
117
+ t.deepEqual(MQTTPattern.fill("foo/+hello/#world", {
118
+ hello: "Hello",
119
+ world: ["the", "world", "wow"],
120
+ }), "foo/Hello/the/world/wow", "Filled in params");
121
+ });
122
+
123
+ test("fill() fills missing + params with undefined", function(t){
124
+ t.plan(1);
125
+ t.deepEqual(
126
+ MQTTPattern.fill("foo/+hello", {}),
127
+ "foo/undefined",
128
+ "Filled in params"
129
+ );
130
+ });
131
+
132
+ test("fill() ignores empty # params", function(t){
133
+ t.plan(1);
134
+ t.deepEqual(
135
+ MQTTPattern.fill("foo/#hello", {}),
136
+ "foo",
137
+ "Filled in params"
138
+ );
139
+ });
140
+
141
+ test("fill() ignores non-named # params", function (t) {
142
+ t.plan(1);
143
+ t.deepEqual(
144
+ MQTTPattern.fill("foo/#", {}),
145
+ "foo",
146
+ "Filled in params"
147
+ );
148
+ });
149
+
150
+ test("fill() uses `undefined` for non-named + params", function(t){
151
+ t.plan(1);
152
+ t.deepEqual(
153
+ MQTTPattern.fill("foo/+", {}),
154
+ "foo/undefined",
155
+ "Filled in params"
156
+ );
157
+ });
158
+
159
+ test("clean() removes parameter names", function(t){
160
+ t.plan(1);
161
+ t.equal(MQTTPattern.clean("hello/+param1/world/#param2"), "hello/+/world/#", "Got hello/+/world/#");
162
+ });
163
+
164
+ test("clean() works when there aren't any parameter names", function(t){
165
+ t.plan(1);
166
+ t.equal(MQTTPattern.clean("hello/+/world/#"), "hello/+/world/#", "Got hello/+/world/#");
167
+ });
package/.npmignore DELETED
@@ -1,37 +0,0 @@
1
- # Logs
2
- logs
3
- *.log
4
- npm-debug.log*
5
-
6
- # Runtime data
7
- pids
8
- *.pid
9
- *.seed
10
-
11
- # Directory for instrumented libs generated by jscoverage/JSCover
12
- lib-cov
13
-
14
- # Coverage directory used by tools like istanbul
15
- coverage
16
-
17
- # nyc test coverage
18
- .nyc_output
19
-
20
- # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21
- .grunt
22
-
23
- # node-waf configuration
24
- .lock-wscript
25
-
26
- # Compiled binary addons (http://nodejs.org/api/addons.html)
27
- build/Release
28
-
29
- # Dependency directories
30
- node_modules
31
- jspm_packages
32
-
33
- # Optional npm cache directory
34
- .npm
35
-
36
- # Optional REPL history
37
- .node_repl_history