diff --git a/.github/workflows/vehicle_profiles_validate.yml b/.github/workflows/vehicle_profiles_validate.yml new file mode 100644 index 0000000..da85119 --- /dev/null +++ b/.github/workflows/vehicle_profiles_validate.yml @@ -0,0 +1,17 @@ +name: Validate Vehicle Profiles + +on: [pull_request] + +jobs: + validate-vehicle-profiles: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '20.x' + - run: | + cd .vehicle_profiles + npm ci + npm run validate \ No newline at end of file diff --git a/.vehicle_profiles/package-lock.json b/.vehicle_profiles/package-lock.json index d1bd1ea..f6f6859 100644 --- a/.vehicle_profiles/package-lock.json +++ b/.vehicle_profiles/package-lock.json @@ -8,6 +8,7 @@ "name": "wican-fw-vehicle_profiles", "version": "0.1.0", "dependencies": { + "ajv": "^8.17.1", "glob": "^11.0.0" } }, @@ -36,6 +37,21 @@ "node": ">=14" } }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -110,6 +126,16 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-uri": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", + "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" + }, "node_modules/foreground-child": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", @@ -177,6 +203,11 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, "node_modules/lru-cache": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.0.tgz", @@ -235,6 +266,14 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", diff --git a/.vehicle_profiles/package.json b/.vehicle_profiles/package.json index 4132f2f..def8ab7 100644 --- a/.vehicle_profiles/package.json +++ b/.vehicle_profiles/package.json @@ -5,11 +5,13 @@ "main": "merge.js", "scripts": { "build": "node merge.js", + "validate": "node validate.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "jay-oswald", "type": "module", "dependencies": { + "ajv": "^8.17.1", "glob": "^11.0.0" } } diff --git a/.vehicle_profiles/schema.json b/.vehicle_profiles/schema.json new file mode 100644 index 0000000..21dfe21 --- /dev/null +++ b/.vehicle_profiles/schema.json @@ -0,0 +1,53 @@ +{ + "title": "WiCan Vehicle Profile", + "description": "Data about various models of cars and their settings", + "type": "object", + "properties": { + "car_model": { + "description": "Name of car model, should include Make and Model(s)", + "type": "string" + }, + "init": { + "description": "Init String, don't forget the final ;", + "type": "string" + }, + "pids": { + "description": "Array of PID's and their parameters", + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "properties": { + "pid": { + "description": "The PID for this group of parameters", + "type": "string" + }, + "parameters": { + "description": "Array of Parameters for this PID", + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "properties": { + "name": { + "description": "Used in MQTT JSON, no spaces", + "type": "string" + }, + "expression": { + "description": "Expression to calculate value", + "type": "string" + }, + "unit": { + "description": "Unit for this parameter", + "type": "string" + } + } + } + } + } + } + } + }, + "additionalProperties": false, + "required": [ "car_model", "init", "pids"] +} \ No newline at end of file diff --git a/.vehicle_profiles/validate.js b/.vehicle_profiles/validate.js new file mode 100644 index 0000000..ac0afcd --- /dev/null +++ b/.vehicle_profiles/validate.js @@ -0,0 +1,34 @@ +import Ajv from "ajv" +import { readFile } from 'fs/promises'; +import { glob } from 'glob' + +const ajv = new Ajv() +const schema = JSON.parse(await readFile("schema.json", "utf-8")) +const validate = ajv.compile(schema) + +const source_folder = '../vehicle_profiles'; +const files = await glob(source_folder + '/**/*.json') + +let errors = 0; + +async function validate_profile(path){ + let file = await readFile(path, "utf-8"); + let data = JSON.parse(file); + let valid = validate(data); + if(valid) return + + console.log(path) + console.log(validate.errors) + errors++; +} + +let promises = []; +files.forEach(file => { + promises.push(validate_profile(file)); +}); + +await Promise.all(promises); + +if(errors > 0){ + throw new Error('Validation issues found, see log for details'); +} \ No newline at end of file