Skip to content

Commit d158e45

Browse files
authored
feat: make application protocols into a package (#10)
* feat: add validation for LTE messages - Add entry point in dist/index.js - index.ts takes a message and validates appId, messageType, and data * build: change tsconfig to target es2015 * build: include dist
1 parent e499227 commit d158e45

File tree

8 files changed

+158
-4
lines changed

8 files changed

+158
-4
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
dist/
21
node_modules/
32
npm-debug.log
43
.idea/
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { isMessageValid } from '../index';
2+
3+
const validGPSLTEMessage = {
4+
appId: 'GPS',
5+
messageType: 'DATA',
6+
data:
7+
'$GPGGA,141856.00,6326.27336,N,01028.08721,E,1,09,0.81,34.7,M,39.8,M,,*64',
8+
};
9+
10+
const invalidGPSLTEMessageAppId = {
11+
appId: 'MAGNETIC', // appId is not supported
12+
messageType: 'DATA',
13+
data: '{x: 0.5, y: 0.2, z: 0.3}',
14+
};
15+
16+
const invalidGPSLTEMessageType = {
17+
appId: 'GPS',
18+
messageType: 'COORDINATES', // message type is not supported
19+
data:
20+
'$GPGGA,141856.00,6326.27336,N,01028.08721,E,1,09,0.81,34.7,M,39.8,M,,*64',
21+
};
22+
23+
const invalidGPSLTEMessageData = {
24+
appId: 'GPS',
25+
messageType: 'DATA',
26+
data: '$GPWPL,5128.62,N,00027.58,W,EGLL*59', // GPWPL - waypoint location format, this is not supported
27+
};
28+
29+
describe('schema validation', () => {
30+
beforeEach(() => {
31+
console.error = jest.fn();
32+
});
33+
34+
afterEach(() => {
35+
(console.error as jest.Mock).mockRestore();
36+
});
37+
38+
it('should return true for a valid schema', () => {
39+
expect(isMessageValid(validGPSLTEMessage)).toBe(true);
40+
});
41+
it('should return false for a schema with invalid appId', () => {
42+
expect(isMessageValid(invalidGPSLTEMessageAppId)).toBe(false);
43+
expect((console.error as jest.Mock).mock.calls[0][0]).toBe(
44+
'Schema does not exist',
45+
);
46+
});
47+
it('should return false for a schema with invalid message type', () => {
48+
expect(isMessageValid(invalidGPSLTEMessageType)).toBe(false);
49+
expect((console.error as jest.Mock).mock.calls[0][0]).toBe(
50+
'validation error',
51+
);
52+
});
53+
it('should return false for an invalid schema data', () => {
54+
expect(isMessageValid(invalidGPSLTEMessageData)).toBe(false);
55+
expect((console.error as jest.Mock).mock.calls[0][0]).toBe(
56+
'validation error',
57+
);
58+
});
59+
});

dist/index.d.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export declare enum AppId {
2+
Gps = "GPS",
3+
Flip = "FLIP",
4+
Gen = "GEN",
5+
Temp = "TEMP",
6+
Humid = "HUMID",
7+
AirPress = "AIR_PRESS",
8+
RSRP = "RSRP",
9+
Button = "BUTTON",
10+
Device = "DEVICE"
11+
}
12+
export declare const isMessageValid: (message: any) => boolean;

dist/index.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import * as Ajv from 'ajv';
2+
import * as path from 'path';
3+
import * as fs from 'fs';
4+
const ajv = new Ajv();
5+
export var AppId;
6+
(function (AppId) {
7+
AppId["Gps"] = "GPS";
8+
AppId["Flip"] = "FLIP";
9+
AppId["Gen"] = "GEN";
10+
AppId["Temp"] = "TEMP";
11+
AppId["Humid"] = "HUMID";
12+
AppId["AirPress"] = "AIR_PRESS";
13+
AppId["RSRP"] = "RSRP";
14+
AppId["Button"] = "BUTTON";
15+
AppId["Device"] = "DEVICE";
16+
})(AppId || (AppId = {}));
17+
const getJsonSchema = (appId) => {
18+
const filePath = path.join(__dirname, 'schemas', `${appId.toLowerCase()}.json`);
19+
const schema = fs.readFileSync(filePath, 'utf8');
20+
return JSON.parse(schema);
21+
};
22+
export const isMessageValid = (message) => {
23+
const appId = message.appId;
24+
let jsonSchema;
25+
try {
26+
jsonSchema = getJsonSchema(appId);
27+
}
28+
catch (e) {
29+
console.error('Schema does not exist', e);
30+
return false;
31+
}
32+
const compiledSchema = ajv.compile(jsonSchema);
33+
const isValid = compiledSchema(message);
34+
if (!isValid) {
35+
console.error('validation error', compiledSchema.errors);
36+
}
37+
return isValid;
38+
};

index.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import * as Ajv from 'ajv';
2+
import * as path from 'path';
3+
import * as fs from 'fs';
4+
5+
const ajv = new Ajv();
6+
7+
export enum AppId {
8+
Gps = 'GPS',
9+
Flip = 'FLIP',
10+
Gen = 'GEN',
11+
Temp = 'TEMP',
12+
Humid = 'HUMID',
13+
AirPress = 'AIR_PRESS',
14+
RSRP = 'RSRP',
15+
Button = 'BUTTON',
16+
Device = 'DEVICE',
17+
}
18+
19+
const getJsonSchema = (appId: AppId) => {
20+
const filePath = path.join(__dirname, 'schemas', `${appId.toLowerCase()}.json`);
21+
const schema = fs.readFileSync(filePath, 'utf8');
22+
return JSON.parse(schema);
23+
};
24+
25+
export const isMessageValid = (message: any): boolean => {
26+
const appId = message.appId;
27+
let jsonSchema;
28+
29+
try {
30+
jsonSchema = getJsonSchema(appId);
31+
} catch (e) {
32+
console.error('Schema does not exist', e);
33+
return false;
34+
}
35+
36+
const compiledSchema = ajv.compile(jsonSchema);
37+
const isValid = compiledSchema(message) as boolean;
38+
39+
if (!isValid) {
40+
console.error('validation error', compiledSchema.errors);
41+
}
42+
43+
return isValid;
44+
};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"name": "@nrfcloud/application-protocols",
33
"version": "1.0.0",
4+
"main": "dist/index.js",
45
"description": "Contains the application protocol definition for long-range devices connecting to nRF Connect for Cloud",
56
"scripts": {
67
"test": "jest",
File renamed without changes.

tsconfig.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
{
22
"compilerOptions": {
3-
"module": "commonjs",
4-
"target": "es2017",
3+
"module": "es2015",
4+
"target": "es2015",
55
"strict": true,
66
"outDir": "dist/",
7+
"moduleResolution": "node",
78
"declaration": true,
89
"skipLibCheck": true,
910
"noUnusedParameters": true,
1011
"noUnusedLocals": true
1112
},
1213
"include": [
13-
"src/**/*"
14+
"index.ts"
1415
]
1516
}

0 commit comments

Comments
 (0)