@springfield/ham-radio-utils 4.9.0 → 4.10.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/dist/schemas/radio-protocol-schema.json +12 -1
- package/dist/utils/schema-validator.d.ts.map +1 -1
- package/dist/utils/schema-validator.js +34 -1
- package/dist/utils/schema-validator.js.map +1 -1
- package/package.json +1 -1
- package/src/schemas/radio-protocol-schema.json +12 -1
- package/src/utils/schema-validator.ts +45 -1
|
@@ -78,10 +78,21 @@
|
|
|
78
78
|
"properties": {
|
|
79
79
|
"baudRate": {
|
|
80
80
|
"type": "integer",
|
|
81
|
-
"description": "
|
|
81
|
+
"description": "Default serial baud rate used to open the programming port. Must be included in baudRates when that list is present.",
|
|
82
82
|
"minimum": 1200,
|
|
83
83
|
"maximum": 115200
|
|
84
84
|
},
|
|
85
|
+
"baudRates": {
|
|
86
|
+
"type": "array",
|
|
87
|
+
"description": "Baud rates the radio programming port accepts. Omit when only baudRate is valid. The HamBench import and write dialogs show a selector when more than one value is listed.",
|
|
88
|
+
"minItems": 1,
|
|
89
|
+
"uniqueItems": true,
|
|
90
|
+
"items": {
|
|
91
|
+
"type": "integer",
|
|
92
|
+
"minimum": 1200,
|
|
93
|
+
"maximum": 115200
|
|
94
|
+
}
|
|
95
|
+
},
|
|
85
96
|
"dataBits": {
|
|
86
97
|
"type": "integer",
|
|
87
98
|
"description": "Number of data bits",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-validator.d.ts","sourceRoot":"","sources":["../../src/utils/schema-validator.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAOD,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAAM;IAEjB,cAMC;IAED,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,gBAAgB,
|
|
1
|
+
{"version":3,"file":"schema-validator.d.ts","sourceRoot":"","sources":["../../src/utils/schema-validator.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAOD,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAAM;IAEjB,cAMC;IAED,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,gBAAgB,CAiBvD;IAED,iBAAiB,CAAC,SAAS,EAAE,OAAO,GAAG,gBAAgB,CAEtD;IAED,OAAO,CAAC,eAAe;CAsBxB"}
|
|
@@ -12,7 +12,18 @@ export class SchemaValidator {
|
|
|
12
12
|
addFormats(this.ajv);
|
|
13
13
|
}
|
|
14
14
|
validateRadioProtocol(config) {
|
|
15
|
-
|
|
15
|
+
const schemaResult = this.validateAgainst(radioProtocolSchema, config);
|
|
16
|
+
if (!schemaResult.valid) {
|
|
17
|
+
return schemaResult;
|
|
18
|
+
}
|
|
19
|
+
const baudRateErrors = baudRateMembershipErrors(config);
|
|
20
|
+
if (baudRateErrors.length === 0) {
|
|
21
|
+
return schemaResult;
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
valid: false,
|
|
25
|
+
errors: baudRateErrors,
|
|
26
|
+
};
|
|
16
27
|
}
|
|
17
28
|
validateMemoryMap(memoryMap) {
|
|
18
29
|
return this.validateAgainst(radioMemoryMapSchema, memoryMap);
|
|
@@ -36,4 +47,26 @@ export class SchemaValidator {
|
|
|
36
47
|
};
|
|
37
48
|
}
|
|
38
49
|
}
|
|
50
|
+
function isRecord(value) {
|
|
51
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* `baudRate` is the default open speed. When a radio lists `baudRates`, that
|
|
55
|
+
* default must be one of the accepted values so the UI can preselect it.
|
|
56
|
+
*/
|
|
57
|
+
function baudRateMembershipErrors(config) {
|
|
58
|
+
if (!isRecord(config) || !isRecord(config.serialConfig)) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
const serialConfig = config.serialConfig;
|
|
62
|
+
const baudRate = serialConfig.baudRate;
|
|
63
|
+
const baudRates = serialConfig.baudRates;
|
|
64
|
+
if (!Array.isArray(baudRates) || typeof baudRate !== 'number') {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
if (baudRates.includes(baudRate)) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
return ['/serialConfig/baudRate: must be included in baudRates'];
|
|
71
|
+
}
|
|
39
72
|
//# sourceMappingURL=schema-validator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema-validator.js","sourceRoot":"","sources":["../../src/utils/schema-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,mBAAmB,MAAM,uCAAuC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC9F,OAAO,oBAAoB,MAAM,yCAAyC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAYjG,MAAM,OAAO,eAAe;IAClB,GAAG,CAAM;IAEjB;QACE,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC;YACjB,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACF,UAA2C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzD,CAAC;IAED,qBAAqB,CAAC,MAAe;QACnC,
|
|
1
|
+
{"version":3,"file":"schema-validator.js","sourceRoot":"","sources":["../../src/utils/schema-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,UAAU,MAAM,aAAa,CAAC;AACrC,OAAO,mBAAmB,MAAM,uCAAuC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC9F,OAAO,oBAAoB,MAAM,yCAAyC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAYjG,MAAM,OAAO,eAAe;IAClB,GAAG,CAAM;IAEjB;QACE,IAAI,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC;YACjB,SAAS,EAAE,IAAI;YACf,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACF,UAA2C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACzD,CAAC;IAED,qBAAqB,CAAC,MAAe;QACnC,MAAM,YAAY,GAAG,IAAI,CAAC,eAAe,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QAEvE,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;YACxB,OAAO,YAAY,CAAC;QACtB,CAAC;QAED,MAAM,cAAc,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;QAExD,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,OAAO,YAAY,CAAC;QACtB,CAAC;QAED,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,cAAc;SACvB,CAAC;IACJ,CAAC;IAED,iBAAiB,CAAC,SAAkB;QAClC,OAAO,IAAI,CAAC,eAAe,CAAC,oBAAoB,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC;IAEO,eAAe,CAAC,MAAc,EAAE,IAAa;QACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAE7B,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;QAED,IAAI,MAAM,GAAa,EAAE,CAAC;QAE1B,IAAI,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClD,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAe,EAAE,EAAE;gBAC/C,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,IAAI,MAAM,CAAC;gBAC1C,OAAO,GAAG,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;YACrC,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO;YACL,MAAM;YACN,KAAK,EAAE,KAAK;SACb,CAAC;IACJ,CAAC;CACF;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED;;;GAGG;AACH,SAAS,wBAAwB,CAAC,MAAe;IAC/C,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QACxD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;IACzC,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC;IACvC,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC;IAEzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9D,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,CAAC,uDAAuD,CAAC,CAAC;AACnE,CAAC","sourcesContent":["import { Ajv } from 'ajv';\nimport addFormats from 'ajv-formats';\nimport radioProtocolSchema from '../schemas/radio-protocol-schema.json' with { type: 'json' };\nimport radioMemoryMapSchema from '../schemas/radio-memory-map-schema.json' with { type: 'json' };\n\nexport interface ValidationResult {\n valid: boolean;\n errors?: string[];\n}\n\ninterface AjvError {\n instancePath?: string;\n message?: string;\n}\n\nexport class SchemaValidator {\n private ajv: Ajv;\n\n constructor() {\n this.ajv = new Ajv({\n allErrors: true,\n verbose: true,\n });\n (addFormats as unknown as (ajv: Ajv) => Ajv)(this.ajv);\n }\n\n validateRadioProtocol(config: unknown): ValidationResult {\n const schemaResult = this.validateAgainst(radioProtocolSchema, config);\n\n if (!schemaResult.valid) {\n return schemaResult;\n }\n\n const baudRateErrors = baudRateMembershipErrors(config);\n\n if (baudRateErrors.length === 0) {\n return schemaResult;\n }\n\n return {\n valid: false,\n errors: baudRateErrors,\n };\n }\n\n validateMemoryMap(memoryMap: unknown): ValidationResult {\n return this.validateAgainst(radioMemoryMapSchema, memoryMap);\n }\n\n private validateAgainst(schema: object, data: unknown): ValidationResult {\n const validate = this.ajv.compile(schema);\n const valid = validate(data);\n\n if (valid) {\n return { valid: true };\n }\n\n let errors: string[] = [];\n\n if (validate.errors && validate.errors.length > 0) {\n errors = validate.errors.map((error: AjvError) => {\n const path = error.instancePath || 'root';\n return `${path}: ${error.message}`;\n });\n }\n\n return {\n errors,\n valid: false,\n };\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\n/**\n * `baudRate` is the default open speed. When a radio lists `baudRates`, that\n * default must be one of the accepted values so the UI can preselect it.\n */\nfunction baudRateMembershipErrors(config: unknown): string[] {\n if (!isRecord(config) || !isRecord(config.serialConfig)) {\n return [];\n }\n\n const serialConfig = config.serialConfig;\n const baudRate = serialConfig.baudRate;\n const baudRates = serialConfig.baudRates;\n\n if (!Array.isArray(baudRates) || typeof baudRate !== 'number') {\n return [];\n }\n\n if (baudRates.includes(baudRate)) {\n return [];\n }\n\n return ['/serialConfig/baudRate: must be included in baudRates'];\n}\n"]}
|
package/package.json
CHANGED
|
@@ -78,10 +78,21 @@
|
|
|
78
78
|
"properties": {
|
|
79
79
|
"baudRate": {
|
|
80
80
|
"type": "integer",
|
|
81
|
-
"description": "
|
|
81
|
+
"description": "Default serial baud rate used to open the programming port. Must be included in baudRates when that list is present.",
|
|
82
82
|
"minimum": 1200,
|
|
83
83
|
"maximum": 115200
|
|
84
84
|
},
|
|
85
|
+
"baudRates": {
|
|
86
|
+
"type": "array",
|
|
87
|
+
"description": "Baud rates the radio programming port accepts. Omit when only baudRate is valid. The HamBench import and write dialogs show a selector when more than one value is listed.",
|
|
88
|
+
"minItems": 1,
|
|
89
|
+
"uniqueItems": true,
|
|
90
|
+
"items": {
|
|
91
|
+
"type": "integer",
|
|
92
|
+
"minimum": 1200,
|
|
93
|
+
"maximum": 115200
|
|
94
|
+
}
|
|
95
|
+
},
|
|
85
96
|
"dataBits": {
|
|
86
97
|
"type": "integer",
|
|
87
98
|
"description": "Number of data bits",
|
|
@@ -25,7 +25,22 @@ export class SchemaValidator {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
validateRadioProtocol(config: unknown): ValidationResult {
|
|
28
|
-
|
|
28
|
+
const schemaResult = this.validateAgainst(radioProtocolSchema, config);
|
|
29
|
+
|
|
30
|
+
if (!schemaResult.valid) {
|
|
31
|
+
return schemaResult;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const baudRateErrors = baudRateMembershipErrors(config);
|
|
35
|
+
|
|
36
|
+
if (baudRateErrors.length === 0) {
|
|
37
|
+
return schemaResult;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
valid: false,
|
|
42
|
+
errors: baudRateErrors,
|
|
43
|
+
};
|
|
29
44
|
}
|
|
30
45
|
|
|
31
46
|
validateMemoryMap(memoryMap: unknown): ValidationResult {
|
|
@@ -41,6 +56,7 @@ export class SchemaValidator {
|
|
|
41
56
|
}
|
|
42
57
|
|
|
43
58
|
let errors: string[] = [];
|
|
59
|
+
|
|
44
60
|
if (validate.errors && validate.errors.length > 0) {
|
|
45
61
|
errors = validate.errors.map((error: AjvError) => {
|
|
46
62
|
const path = error.instancePath || 'root';
|
|
@@ -54,3 +70,31 @@ export class SchemaValidator {
|
|
|
54
70
|
};
|
|
55
71
|
}
|
|
56
72
|
}
|
|
73
|
+
|
|
74
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
75
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* `baudRate` is the default open speed. When a radio lists `baudRates`, that
|
|
80
|
+
* default must be one of the accepted values so the UI can preselect it.
|
|
81
|
+
*/
|
|
82
|
+
function baudRateMembershipErrors(config: unknown): string[] {
|
|
83
|
+
if (!isRecord(config) || !isRecord(config.serialConfig)) {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const serialConfig = config.serialConfig;
|
|
88
|
+
const baudRate = serialConfig.baudRate;
|
|
89
|
+
const baudRates = serialConfig.baudRates;
|
|
90
|
+
|
|
91
|
+
if (!Array.isArray(baudRates) || typeof baudRate !== 'number') {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (baudRates.includes(baudRate)) {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return ['/serialConfig/baudRate: must be included in baudRates'];
|
|
100
|
+
}
|