Automate code generation for config schema (#16)
Use a fork of https://github.com/lstrojny/json-schema-to-zod to generate the boundary check for the config automatically.
This commit is contained in:
parent
1088a78079
commit
52efa69bf0
7 changed files with 71 additions and 34 deletions
29
code-generation/config-scheme-gen.js
Executable file
29
code-generation/config-scheme-gen.js
Executable file
|
@ -0,0 +1,29 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const { parseSchema } = require('json-schema-to-zod-with-defaults')
|
||||||
|
const { schema } = require('../config.schema.json')
|
||||||
|
const { format } = require('prettier')
|
||||||
|
const { join, basename } = require('path')
|
||||||
|
const prettierConfig = require('../prettier.config')
|
||||||
|
const { writeFileSync } = require('fs')
|
||||||
|
|
||||||
|
const file = join(__dirname, '../src/generated/config_boundary.ts')
|
||||||
|
|
||||||
|
console.log(`Starting code generation for ${file}`)
|
||||||
|
|
||||||
|
const zodSchema = parseSchema(schema, true)
|
||||||
|
|
||||||
|
const code = format(
|
||||||
|
`
|
||||||
|
// Auto-generated by "${join(basename(__dirname), basename(__filename))}", don’t manually edit
|
||||||
|
|
||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
export const ConfigBoundary = ${zodSchema}
|
||||||
|
`,
|
||||||
|
{ filepath: 'codegen.ts', ...prettierConfig },
|
||||||
|
)
|
||||||
|
|
||||||
|
writeFileSync(file, code)
|
||||||
|
|
||||||
|
console.log(`Finished code generation for ${file}`)
|
|
@ -7,6 +7,9 @@ const { join, basename } = require('path')
|
||||||
|
|
||||||
const uuidToServiceMap = {}
|
const uuidToServiceMap = {}
|
||||||
const serviceToUuidMap = {}
|
const serviceToUuidMap = {}
|
||||||
|
const file = join(__dirname, '../src/generated/services.ts')
|
||||||
|
|
||||||
|
console.log(`Starting code generation for ${file}`)
|
||||||
|
|
||||||
for (const [name, service] of Object.entries(hap.Service)) {
|
for (const [name, service] of Object.entries(hap.Service)) {
|
||||||
if (typeof service !== 'function' || typeof service.UUID !== 'string') {
|
if (typeof service !== 'function' || typeof service.UUID !== 'string') {
|
||||||
|
@ -28,4 +31,6 @@ export const Services: Record<string,string> = ${JSON.stringify(serviceToUuidMap
|
||||||
{ filepath: 'codegen.ts', ...prettierConfig },
|
{ filepath: 'codegen.ts', ...prettierConfig },
|
||||||
)
|
)
|
||||||
|
|
||||||
writeFileSync(join(__dirname, '../src/generated/services.ts'), code)
|
writeFileSync(file, code)
|
||||||
|
|
||||||
|
console.log(`Finished code generation for ${file}`)
|
||||||
|
|
18
package-lock.json
generated
18
package-lock.json
generated
|
@ -27,7 +27,7 @@
|
||||||
"homebridge": "^1.3.5",
|
"homebridge": "^1.3.5",
|
||||||
"homebridge-cmdswitch2": "^0.2.10",
|
"homebridge-cmdswitch2": "^0.2.10",
|
||||||
"jest": "^29.3.0",
|
"jest": "^29.3.0",
|
||||||
"json-schema-to-zod": "^0.2.0",
|
"json-schema-to-zod-with-defaults": "^0.2.1",
|
||||||
"nodemon": "^2.0.13",
|
"nodemon": "^2.0.13",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
|
@ -5328,10 +5328,10 @@
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/json-schema-to-zod": {
|
"node_modules/json-schema-to-zod-with-defaults": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-schema-to-zod/-/json-schema-to-zod-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/json-schema-to-zod-with-defaults/-/json-schema-to-zod-with-defaults-0.2.1.tgz",
|
||||||
"integrity": "sha512-UmbLC6VnWBt6dxA6s42Ku2l0vIhJMrYpPxB2QCWUx9gMXtW4TpT5p/BMXUGg7zmhwLElOmlsx9bONlkNvlukbQ==",
|
"integrity": "sha512-5T4GUM4Koo7COTrOknBwsIgBrhp4FqM5BAhofWewLiBt3Q+ViWy8xNIeB6d3ZGHnEwKGVIbMaRaJyuwpM9x4SA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/json-schema": "^7.0.9",
|
"@types/json-schema": "^7.0.9",
|
||||||
|
@ -11742,10 +11742,10 @@
|
||||||
"@apidevtools/json-schema-ref-parser": "9.0.9"
|
"@apidevtools/json-schema-ref-parser": "9.0.9"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"json-schema-to-zod": {
|
"json-schema-to-zod-with-defaults": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/json-schema-to-zod/-/json-schema-to-zod-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/json-schema-to-zod-with-defaults/-/json-schema-to-zod-with-defaults-0.2.1.tgz",
|
||||||
"integrity": "sha512-UmbLC6VnWBt6dxA6s42Ku2l0vIhJMrYpPxB2QCWUx9gMXtW4TpT5p/BMXUGg7zmhwLElOmlsx9bONlkNvlukbQ==",
|
"integrity": "sha512-5T4GUM4Koo7COTrOknBwsIgBrhp4FqM5BAhofWewLiBt3Q+ViWy8xNIeB6d3ZGHnEwKGVIbMaRaJyuwpM9x4SA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/json-schema": "^7.0.9",
|
"@types/json-schema": "^7.0.9",
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
"test": "ifNotCi() { test \"$CI\" && echo \"$2\" || echo \"$1\"; }; npm run code-generation && `npm bin`/jest `ifNotCi --watchAll`",
|
"test": "ifNotCi() { test \"$CI\" && echo \"$2\" || echo \"$1\"; }; npm run code-generation && `npm bin`/jest `ifNotCi --watchAll`",
|
||||||
"link": "npm install --no-save file:///$PWD/",
|
"link": "npm install --no-save file:///$PWD/",
|
||||||
"build": "rimraf ./dist && npm run code-generation && tsc",
|
"build": "rimraf ./dist && npm run code-generation && tsc",
|
||||||
"code-generation": "./code-generation/hap-gen.js",
|
"code-generation": "./code-generation/hap-gen.js && ./code-generation/config-scheme-gen.js",
|
||||||
"prepublishOnly": "npm run code-generation && npm run lint && npm run build",
|
"prepublishOnly": "npm run code-generation && npm run lint && npm run build",
|
||||||
"release": "release() { test \"$1\" && test `git rev-parse --abbrev-ref HEAD` == \"develop\" && npm run code-generation && git pull origin develop --rebase && npm version $1 && npm publish && git push origin develop && git push origin --tags; }; release"
|
"release": "release() { test \"$1\" && test `git rev-parse --abbrev-ref HEAD` == \"develop\" && npm run code-generation && git pull origin develop --rebase && npm version $1 && npm publish && git push origin develop && git push origin --tags; }; release"
|
||||||
},
|
},
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
"homebridge": "^1.3.5",
|
"homebridge": "^1.3.5",
|
||||||
"homebridge-cmdswitch2": "^0.2.10",
|
"homebridge-cmdswitch2": "^0.2.10",
|
||||||
"jest": "^29.3.0",
|
"jest": "^29.3.0",
|
||||||
"json-schema-to-zod": "^0.2.0",
|
"json-schema-to-zod-with-defaults": "^0.2.1",
|
||||||
"nodemon": "^2.0.13",
|
"nodemon": "^2.0.13",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
|
|
|
@ -1,19 +1,5 @@
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
|
import { ConfigBoundary as ConfigBoundaryWithoutPlatform } from '../generated/config_boundary'
|
||||||
|
|
||||||
export const ConfigBoundary = z.object({
|
export const ConfigBoundary = z.intersection(ConfigBoundaryWithoutPlatform, z.object({ platform: z.string() }))
|
||||||
pin: z.string().regex(new RegExp('^\\d{3}-\\d{2}-\\d{3}$')).describe('Homebridge PIN for service authentication'),
|
export type Config = z.infer<typeof ConfigBoundary>
|
||||||
debug: z.boolean().default(false),
|
|
||||||
prefix: z.string().default('homebridge'),
|
|
||||||
port: z.number().int().describe('TCP port for the prometheus probe server to listen to').default(36123),
|
|
||||||
refresh_interval: z.number().int().describe('Discover new services every <interval> seconds').default(60),
|
|
||||||
request_timeout: z
|
|
||||||
.number()
|
|
||||||
.int()
|
|
||||||
.describe('Request timeout when interacting with homebridge instances')
|
|
||||||
.default(10),
|
|
||||||
discovery_timeout: z
|
|
||||||
.number()
|
|
||||||
.int()
|
|
||||||
.describe('Discovery timeout after which the current discovery is considered failed')
|
|
||||||
.default(20),
|
|
||||||
})
|
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
import z from 'zod'
|
|
||||||
import { ConfigBoundary as BaseConfigBoundary } from './config'
|
|
||||||
|
|
||||||
export * from './checker'
|
export * from './checker'
|
||||||
export * from './hap'
|
export * from './hap'
|
||||||
export const ConfigBoundary = z.intersection(BaseConfigBoundary, z.object({ platform: z.string() }))
|
export * from './config'
|
||||||
export type Config = z.infer<typeof ConfigBoundary>
|
|
||||||
|
|
21
src/generated/config_boundary.ts
Normal file
21
src/generated/config_boundary.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Auto-generated by "code-generation/config-scheme-gen.js", don’t manually edit
|
||||||
|
|
||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
export const ConfigBoundary = z.object({
|
||||||
|
pin: z.string().regex(new RegExp('^\\d{3}-\\d{2}-\\d{3}$')).describe('Homebridge PIN for service authentication'),
|
||||||
|
debug: z.boolean().default(false),
|
||||||
|
prefix: z.string().default('homebridge'),
|
||||||
|
port: z.number().int().describe('TCP port for the prometheus probe server to listen to').default(36123),
|
||||||
|
refresh_interval: z.number().int().describe('Discover new services every <interval> seconds').default(60),
|
||||||
|
request_timeout: z
|
||||||
|
.number()
|
||||||
|
.int()
|
||||||
|
.describe('Request timeout when interacting with homebridge instances')
|
||||||
|
.default(10),
|
||||||
|
discovery_timeout: z
|
||||||
|
.number()
|
||||||
|
.int()
|
||||||
|
.describe('Discovery timeout after which the current discovery is considered failed')
|
||||||
|
.default(20),
|
||||||
|
})
|
Loading…
Reference in a new issue