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 +10 -0
- package/index.js +57 -1
- package/package.json +33 -33
- package/test.js +66 -0
- package/.npmignore +0 -37
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
|
|
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.
|
|
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
|