forked from joe-re/sql-language-server
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathloadConfig.ts
More file actions
133 lines (126 loc) · 3.57 KB
/
loadConfig.ts
File metadata and controls
133 lines (126 loc) · 3.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import { extname } from 'path'
import * as yaml from 'js-yaml'
import Ajv from 'ajv'
import { Config, ErrorLevel } from '../rules'
import schemaConf from '../../schema.conf'
import { fileExists, readFile, directoryExists } from './utils'
const configFiles = [
{ name: '.sqlintrc.json' },
{ name: '.sqlintrc.yaml' },
{ name: '.sqlintrc.yml' },
]
const defaultConfig: Config = {
rules: {
'align-column-to-the-first': { level: ErrorLevel.Error },
'column-new-line': { level: ErrorLevel.Error },
'linebreak-after-clause-keyword': { level: ErrorLevel.Error },
'reserved-word-case': { level: ErrorLevel.Error, option: 'upper' },
'space-surrounding-operators': { level: ErrorLevel.Error },
'where-clause-new-line': { level: ErrorLevel.Error },
'align-where-clause-to-the-first': { level: ErrorLevel.Error },
'require-as-to-rename-column': { level: ErrorLevel.Error },
},
}
function formatErrors(errors: Ajv.ErrorObject[]) {
return errors
.map((error) => {
if (error.keyword === 'additionalProperties') {
return `Unexpected property "${error.data.invalidProp}"`
}
})
.map((message) => `\t- ${message}.\n`)
.join('')
}
function validateSchema(config: Record<string, unknown>) {
const ajv = new Ajv({
verbose: true,
schemaId: 'auto',
missingRefs: 'ignore',
})
const validate = ajv.compile(schemaConf)
if (!validate(config)) {
throw new Error(
`SQLint configuration is invalid:\n${formatErrors(validate.errors || [])}`
)
}
return true
}
type RuleLevel = string | number
type RuleVelue = RuleLevel | { level: RuleLevel; option: unknown }
export type RawConfig = {
rules: {
[key: string]: RuleVelue
}
}
export function convertToConfig(rawConfig: RawConfig): Config {
return Object.entries(rawConfig.rules).reduce(
(p, c) => {
let level = 0
let option = null
const getLevel = (v: RuleVelue) => {
if (typeof v === 'number') {
return v
}
if (typeof v === 'string') {
switch (v) {
case 'error':
return 2
case 'warning':
return 1
case 'off':
return 0
default:
throw new Error(`unknown error type: ${c[1]}`)
}
}
return 0
}
if (Array.isArray(c[1])) {
level = getLevel(c[1][0])
option = c[1][1]
} else {
level = getLevel(c[1])
}
p.rules[c[0]] = { level, option }
return p
},
{ rules: {} } as Config
)
}
export function loadConfig(directoryOrFile: string): Config {
let filePath = ''
if (fileExists(directoryOrFile)) {
filePath = directoryOrFile
} else if (directoryExists(directoryOrFile)) {
const file = configFiles.find((v) =>
fileExists(`${directoryOrFile}/${v.name}`)
)
if (file) filePath = `${directoryOrFile}/${file.name}`
}
if (!filePath) {
// try to lookup personal config file
const file = configFiles.find((v) =>
fileExists(`${process.env.HOME}/.config/sql-language-server/${v.name}`)
)
if (file)
filePath = `${process.env.HOME}/.config/sql-language-server/${file.name}`
}
if (!filePath) {
return defaultConfig
}
const fileContent = readFile(filePath)
let config: RawConfig
switch (extname(filePath)) {
case '.json':
config = JSON.parse(fileContent)
break
case '.yaml':
case '.yml':
config = yaml.load(fileContent) as RawConfig
break
default:
config = JSON.parse(fileContent)
}
validateSchema(config)
return convertToConfig(config)
}