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 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)) {
|
||||
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 },
|
||||
)
|
||||
|
||||
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-cmdswitch2": "^0.2.10",
|
||||
"jest": "^29.3.0",
|
||||
"json-schema-to-zod": "^0.2.0",
|
||||
"json-schema-to-zod-with-defaults": "^0.2.1",
|
||||
"nodemon": "^2.0.13",
|
||||
"prettier": "^2.7.1",
|
||||
"rimraf": "^3.0.2",
|
||||
|
@ -5328,10 +5328,10 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/json-schema-to-zod": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-to-zod/-/json-schema-to-zod-0.2.0.tgz",
|
||||
"integrity": "sha512-UmbLC6VnWBt6dxA6s42Ku2l0vIhJMrYpPxB2QCWUx9gMXtW4TpT5p/BMXUGg7zmhwLElOmlsx9bONlkNvlukbQ==",
|
||||
"node_modules/json-schema-to-zod-with-defaults": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-to-zod-with-defaults/-/json-schema-to-zod-with-defaults-0.2.1.tgz",
|
||||
"integrity": "sha512-5T4GUM4Koo7COTrOknBwsIgBrhp4FqM5BAhofWewLiBt3Q+ViWy8xNIeB6d3ZGHnEwKGVIbMaRaJyuwpM9x4SA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.9",
|
||||
|
@ -11742,10 +11742,10 @@
|
|||
"@apidevtools/json-schema-ref-parser": "9.0.9"
|
||||
}
|
||||
},
|
||||
"json-schema-to-zod": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-to-zod/-/json-schema-to-zod-0.2.0.tgz",
|
||||
"integrity": "sha512-UmbLC6VnWBt6dxA6s42Ku2l0vIhJMrYpPxB2QCWUx9gMXtW4TpT5p/BMXUGg7zmhwLElOmlsx9bONlkNvlukbQ==",
|
||||
"json-schema-to-zod-with-defaults": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-to-zod-with-defaults/-/json-schema-to-zod-with-defaults-0.2.1.tgz",
|
||||
"integrity": "sha512-5T4GUM4Koo7COTrOknBwsIgBrhp4FqM5BAhofWewLiBt3Q+ViWy8xNIeB6d3ZGHnEwKGVIbMaRaJyuwpM9x4SA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@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`",
|
||||
"link": "npm install --no-save file:///$PWD/",
|
||||
"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",
|
||||
"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-cmdswitch2": "^0.2.10",
|
||||
"jest": "^29.3.0",
|
||||
"json-schema-to-zod": "^0.2.0",
|
||||
"json-schema-to-zod-with-defaults": "^0.2.1",
|
||||
"nodemon": "^2.0.13",
|
||||
"prettier": "^2.7.1",
|
||||
"rimraf": "^3.0.2",
|
||||
|
|
|
@ -1,19 +1,5 @@
|
|||
import { z } from 'zod'
|
||||
import { ConfigBoundary as ConfigBoundaryWithoutPlatform } from '../generated/config_boundary'
|
||||
|
||||
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),
|
||||
})
|
||||
export const ConfigBoundary = z.intersection(ConfigBoundaryWithoutPlatform, z.object({ platform: z.string() }))
|
||||
export type Config = z.infer<typeof ConfigBoundary>
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
import z from 'zod'
|
||||
import { ConfigBoundary as BaseConfigBoundary } from './config'
|
||||
|
||||
export * from './checker'
|
||||
export * from './hap'
|
||||
export const ConfigBoundary = z.intersection(BaseConfigBoundary, z.object({ platform: z.string() }))
|
||||
export type Config = z.infer<typeof ConfigBoundary>
|
||||
export * from './config'
|
||||
|
|
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