Skip to content

Instantly share code, notes, and snippets.

@lierdakil
Created January 23, 2021 21:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lierdakil/696ee408dbf27e2346765a5441787687 to your computer and use it in GitHub Desktop.
Save lierdakil/696ee408dbf27e2346765a5441787687 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ts-node
const path = require('path')
const fs = require('fs')
if (!process.argv[2]) {
process.stderr.write(`Usage: ${process.argv[1]} <filename>\n`)
return -1
}
const filePath = path.join(process.cwd(), process.argv[2])
let outfile
let config
const packageJson = require(path.join(process.cwd(), 'package.json'))
if (packageJson.configSchema) {
config = packageJson.configSchema
outfile = "export {}"
} else {
config = require(filePath).config
outfile = fs.readFileSync(filePath)
}
const pn = packageJson.name
const output = {
buffer: [],
write: function(str) {
output.buffer.push(str)
}
}
const indentOne = ' '
output.write(`
// generated by typed-config.js
declare module 'atom' {
interface ConfigValues {
`)
function writeFlat(pn, config, indentLevel) {
const indent = indentOne.repeat(indentLevel)
for (const k of Object.keys(config)) {
if (config[k].type === 'object') {
writeFlat(`${pn}.${k}`, config[k].properties, indentLevel)
writeDeep(`${pn}.${k}`, config[k].properties, indentLevel)
} else {
output.write(`${indent}'${pn}.${k}': ${getType(config[k])}\n`)
}
}
}
writeFlat(pn, config, 2)
function writeDeep(pn, config, indentLevel) {
const indent = indentOne.repeat(indentLevel)
const indent2 = indentOne.repeat(indentLevel + 1)
output.write(`${indent}'${pn}': {\n`)
for (const k of Object.keys(config)) {
if (config[k].type === 'object') {
writeFlat(k, config[k].properties, indentLevel + 1)
writeDeep(k, config[k].properties, indentLevel + 1)
} else {
output.write(`${indent2}${needQuote(k)}: ${getType(config[k])}\n`)
}
}
output.write(`${indent}}\n`)
}
writeDeep(pn, config, 2)
function needQuote(str) {
if (str.match(/^[A-Za-z]\w+$/)) return str
else return `'${str}'`
}
function getType(t, useDefaultRule = true) {
let type
if (t.enum) {
const vals = []
for (const v of t.enum) {
if (v.value !== undefined) {
vals.push(v.value)
} else {
vals.push(v)
}
}
type = vals
.map(x => {
if (typeof x === 'string') return `'${x}'`
else if (typeof x.value === 'string') return `'${x.value}'`
else if (x.value) return x.value
else return x
})
.join(' | ')
return type
}
switch (t.type) {
case 'string':
type = 'string'
break
case 'integer':
type = 'number'
break
case 'number':
type = 'number'
break
case 'boolean':
type = 'boolean'
break
case 'array':
if (t.items) {
const rt = getType(t.items, false)
if (rt.includes(' ')) type = `Array<${rt}>`
else type = `${rt}[]`
} else {
type = 'any[]'
}
break
case 'color':
type = 'string'
break
case 'object':
type = 'object'
break
}
if (!type) throw new Error(`Unknown occured: ${JSON.stringify(t)}`)
if (useDefaultRule && t.default === undefined) type += ' | undefined'
return type
}
output.write(`\
}
}
`)
let result = output.buffer.join('')
result = outfile.toString().replace(/(:?\n\/\/ generated by typed-config\.js[^]*)?$/, result)
fs.writeFileSync(filePath, result, {encoding: 'utf8'})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment