1
1
import * as fs from "fs" ;
2
2
import * as path from "path" ;
3
3
4
+ /**
5
+ * Interface defining the structure of a configuration definition
6
+ * @interface ConfigDefinition
7
+ * @property {string } key - The configuration key
8
+ * @property {'string'|'boolean'|'number' } type - The type of the configuration value
9
+ * @property {any } [default] - Optional default value
10
+ * @property {string } description - Description of the configuration
11
+ * @property {(readonly string[]|string[]) } [enum] - Optional list of allowed values
12
+ * @property {(readonly string[]|string[]) } [enumDescriptions] - Optional descriptions for enum values
13
+ * @property {boolean } [isSpecial] - Optional flag for special configurations
14
+ */
4
15
export interface ConfigDefinition {
5
16
key : string ;
6
17
type : "string" | "boolean" | "number" ;
@@ -11,13 +22,27 @@ export interface ConfigDefinition {
11
22
isSpecial ?: boolean ;
12
23
}
13
24
25
+ /**
26
+ * Class responsible for generating and updating configuration related files
27
+ * @class ConfigGenerator
28
+ */
14
29
export class ConfigGenerator {
30
+ /**
31
+ * Constants for configuration file paths
32
+ * @private
33
+ * @readonly
34
+ */
15
35
private static CONFIG_FILES = {
16
36
PACKAGE : "package.json" ,
17
37
TYPES : "src/config/types.ts" ,
18
38
SCHEMA : "src/config/config-schema.ts" ,
19
39
} ;
20
40
41
+ /**
42
+ * Adds a new configuration by updating all necessary files
43
+ * @param {ConfigDefinition } config - The configuration to add
44
+ * @returns {Promise<void> }
45
+ */
21
46
static async addConfig ( config : ConfigDefinition ) {
22
47
await Promise . all ( [
23
48
this . updatePackageJson ( config ) ,
@@ -26,10 +51,18 @@ export class ConfigGenerator {
26
51
] ) ;
27
52
}
28
53
54
+ /**
55
+ * Updates package.json with new configuration
56
+ * @private
57
+ * @param {ConfigDefinition } config - The configuration to add
58
+ * @returns {Promise<void> }
59
+ */
29
60
private static async updatePackageJson ( config : ConfigDefinition ) {
61
+ // Read package.json
30
62
const packagePath = path . join ( process . cwd ( ) , this . CONFIG_FILES . PACKAGE ) ;
31
63
const pkg = JSON . parse ( fs . readFileSync ( packagePath , "utf8" ) ) ;
32
64
65
+ // Add new configuration
33
66
pkg . contributes . configuration . properties [ `dish-ai-commit.${ config . key } ` ] = {
34
67
type : config . type ,
35
68
default : config . default ,
@@ -40,33 +73,47 @@ export class ConfigGenerator {
40
73
: { } ) ,
41
74
} ;
42
75
76
+ // Write updated package.json
43
77
fs . writeFileSync ( packagePath , JSON . stringify ( pkg , null , 2 ) ) ;
44
78
}
45
79
80
+ /**
81
+ * Updates types.ts with new configuration
82
+ * @private
83
+ * @param {ConfigDefinition } config - The configuration to add
84
+ * @returns {Promise<void> }
85
+ */
46
86
private static async updateTypes ( config : ConfigDefinition ) {
47
87
const typesPath = path . join ( process . cwd ( ) , this . CONFIG_FILES . TYPES ) ;
48
88
let content = fs . readFileSync ( typesPath , "utf8" ) ;
49
89
50
- // 处理嵌套配置
90
+ // Generate config key based on nesting level
51
91
const configKey = config . key . includes ( "." )
52
92
? `${ config . key . split ( "." ) [ 0 ] } : { ${ config . key . split ( "." ) [ 1 ] } : ${
53
93
config . type
54
94
} ; }`
55
95
: `${ config . key } : ${ config . type } ;` ;
56
96
97
+ // Skip if config already exists
57
98
if ( content . includes ( configKey ) ) {
58
- return ; // 如果配置已存在,直接返回
99
+ return ;
59
100
}
60
101
61
- // 添加到 ConfigKeys
102
+ // Update content with new config
62
103
content = this . addToConfigKeys ( content , config ) ;
63
-
64
- // 添加到 ExtensionConfiguration
65
104
content = this . addToExtensionConfiguration ( content , config ) ;
66
105
106
+ // Write updated content
67
107
fs . writeFileSync ( typesPath , content ) ;
68
108
}
69
109
110
+ /**
111
+ * Adds configuration to ConfigKeys section
112
+ * @private
113
+ * @param {string } content - Current file content
114
+ * @param {ConfigDefinition } config - Configuration to add
115
+ * @returns {string } Updated content
116
+ */
70
117
private static addToConfigKeys (
71
118
content : string ,
72
119
config : ConfigDefinition
@@ -80,64 +127,111 @@ export class ConfigGenerator {
80
127
) ;
81
128
}
82
129
130
+ /**
131
+ * Adds configuration to ExtensionConfiguration interface
132
+ * @private
133
+ * @param {string } content - Current file content
134
+ * @param {ConfigDefinition } config - Configuration to add
135
+ * @returns {string } Updated content
136
+ */
83
137
private static addToExtensionConfiguration (
84
138
content : string ,
85
139
config : ConfigDefinition
86
140
) : string {
87
141
const parts = config . key . split ( "." ) ;
88
142
89
- // 根据现有的配置结构处理路径
143
+ // Handle different nesting levels
90
144
if ( parts . length > 2 ) {
91
- // 处理两层以上的嵌套,如 features.diffSimplification.enabled
92
- const [ section , category , property ] = parts ;
93
- const parentPath = `${ section } .${ category } ` ;
94
-
95
- if ( ! content . includes ( `${ section } : {` ) ) {
96
- // 如果主分类不存在,创建完整的嵌套结构
97
- content = content . replace (
98
- / ( e x p o r t i n t e r f a c e E x t e n s i o n C o n f i g u r a t i o n { [ \s \S ] * ?) ( } ) / ,
99
- `$1 ${ section } : {\n ${ category } : {\n ${ property } : ${ config . type } ;\n };\n };\n$2`
100
- ) ;
101
- } else if ( ! content . includes ( `${ parentPath } : {` ) ) {
102
- // 如果主分类存在但子分类不存在
103
- content = content . replace (
104
- new RegExp ( `(${ section } : {[\\s\\S]*?)(}[\n\r\s]*};)` ) ,
105
- `$1 ${ category } : {\n ${ property } : ${ config . type } ;\n };\n $2`
106
- ) ;
107
- } else {
108
- // 如果主分类和子分类都存在,只添加属性
109
- content = content . replace (
110
- new RegExp ( `(${ parentPath } : {[\\s\\S]*?)(}[\n\r\s]*};)` ) ,
111
- `$1 ${ property } : ${ config . type } ;\n $2`
112
- ) ;
113
- }
145
+ // Handle multi-level nesting (>2 levels)
146
+ return this . handleMultiLevelNesting ( content , parts , config . type ) ;
114
147
} else if ( parts . length === 2 ) {
115
- // 处理一层嵌套,如 base.language
116
- const [ section , property ] = parts ;
117
- if ( ! content . includes ( `${ section } : {` ) ) {
118
- content = content . replace (
119
- / ( e x p o r t i n t e r f a c e E x t e n s i o n C o n f i g u r a t i o n { [ \s \S ] * ?) ( } ) / ,
120
- `$1 ${ section } : {\n ${ property } : ${ config . type } ;\n };\n$2`
121
- ) ;
122
- } else {
123
- content = content . replace (
124
- new RegExp ( `(${ section } : {[\\s\\S]*?)(}[\n\r\s]*};)` ) ,
125
- `$1 ${ property } : ${ config . type } ;\n $2`
126
- ) ;
127
- }
148
+ // Handle single-level nesting
149
+ return this . handleSingleLevelNesting ( content , parts , config . type ) ;
128
150
} else {
129
- // 处理顶层配置
130
- content = content . replace (
151
+ // Handle top-level config
152
+ return content . replace (
131
153
/ ( e x p o r t i n t e r f a c e E x t e n s i o n C o n f i g u r a t i o n { [ \s \S ] * ?) ( } ) / ,
132
154
`$1 ${ config . key } : ${ config . type } ;\n$2`
133
155
) ;
134
156
}
135
- return content ;
136
157
}
137
158
159
+ /**
160
+ * Handles updating content for multi-level nested configurations
161
+ * @private
162
+ * @param {string } content - Current file content
163
+ * @param {string[] } parts - Configuration key parts
164
+ * @param {string } type - Configuration type
165
+ * @returns {string } Updated content
166
+ */
167
+ private static handleMultiLevelNesting (
168
+ content : string ,
169
+ parts : string [ ] ,
170
+ type : string
171
+ ) : string {
172
+ const [ section , category , property ] = parts ;
173
+ const parentPath = `${ section } .${ category } ` ;
174
+
175
+ // Handle different cases based on existing structure
176
+ if ( ! content . includes ( `${ section } : {` ) ) {
177
+ // Create complete nested structure if main section doesn't exist
178
+ return content . replace (
179
+ / ( e x p o r t i n t e r f a c e E x t e n s i o n C o n f i g u r a t i o n { [ \s \S ] * ?) ( } ) / ,
180
+ `$1 ${ section } : {\n ${ category } : {\n ${ property } : ${ type } ;\n };\n };\n$2`
181
+ ) ;
182
+ } else if ( ! content . includes ( `${ parentPath } : {` ) ) {
183
+ // Add category if main section exists but category doesn't
184
+ return content . replace (
185
+ new RegExp ( `(${ section } : {[\\s\\S]*?)(}[\n\r\s]*};)` ) ,
186
+ `$1 ${ category } : {\n ${ property } : ${ type } ;\n };\n $2`
187
+ ) ;
188
+ } else {
189
+ // Add property if both section and category exist
190
+ return content . replace (
191
+ new RegExp ( `(${ parentPath } : {[\\s\\S]*?)(}[\n\r\s]*};)` ) ,
192
+ `$1 ${ property } : ${ type } ;\n $2`
193
+ ) ;
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Handles updating content for single-level nested configurations
199
+ * @private
200
+ * @param {string } content - Current file content
201
+ * @param {string[] } parts - Configuration key parts
202
+ * @param {string } type - Configuration type
203
+ * @returns {string } Updated content
204
+ */
205
+ private static handleSingleLevelNesting (
206
+ content : string ,
207
+ parts : string [ ] ,
208
+ type : string
209
+ ) : string {
210
+ const [ section , property ] = parts ;
211
+
212
+ if ( ! content . includes ( `${ section } : {` ) ) {
213
+ // Create new section if it doesn't exist
214
+ return content . replace (
215
+ / ( e x p o r t i n t e r f a c e E x t e n s i o n C o n f i g u r a t i o n { [ \s \S ] * ?) ( } ) / ,
216
+ `$1 ${ section } : {\n ${ property } : ${ type } ;\n };\n$2`
217
+ ) ;
218
+ } else {
219
+ // Add property to existing section
220
+ return content . replace (
221
+ new RegExp ( `(${ section } : {[\\s\\S]*?)(}[\n\r\s]*};)` ) ,
222
+ `$1 ${ property } : ${ type } ;\n $2`
223
+ ) ;
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Updates schema file with new configuration
229
+ * @private
230
+ * @param {ConfigDefinition } config - The configuration to add
231
+ * @returns {Promise<void> }
232
+ */
138
233
private static async updateSchema ( config : ConfigDefinition ) {
139
- // 如果需要更新schema文件的话
234
+ // TODO: Implement schema update logic if needed
140
235
const schemaPath = path . join ( process . cwd ( ) , this . CONFIG_FILES . SCHEMA ) ;
141
- // 根据需要实现schema更新逻辑
142
236
}
143
237
}
0 commit comments