Skip to content

Commit 7d023f8

Browse files
committed
feat(config): add support for JSONC configuration files and update tests
1 parent e8f0916 commit 7d023f8

File tree

5 files changed

+97
-0
lines changed

5 files changed

+97
-0
lines changed

lib/config/app-strings.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
export const configFileNames = [
22
'renovate.json',
33
'renovate.json5',
4+
'renovate.jsonc',
45
'.github/renovate.json',
56
'.github/renovate.json5',
7+
'.github/renovate.jsonc',
68
'.gitlab/renovate.json',
79
'.gitlab/renovate.json5',
10+
'.gitlab/renovate.jsonc',
811
'.renovaterc',
912
'.renovaterc.json',
1013
'.renovaterc.json5',
14+
'.renovaterc.jsonc',
1115
'package.json',
1216
];

lib/config/parse.spec.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,37 @@ describe('config/parse', () => {
5656
});
5757
});
5858
});
59+
60+
describe('jsonc', () => {
61+
it('parses', () => {
62+
expect(parseFileConfig('config.jsonc', '{}')).toEqual({
63+
success: true,
64+
parsedContents: {},
65+
});
66+
});
67+
68+
it('parses with comments', () => {
69+
const jsoncContent = `{
70+
// This is a comment
71+
"extends": ["config:base"],
72+
"enabled": true // Another comment
73+
}`;
74+
expect(parseFileConfig('config.jsonc', jsoncContent)).toEqual({
75+
success: true,
76+
parsedContents: {
77+
extends: ['config:base'],
78+
enabled: true,
79+
},
80+
});
81+
});
82+
83+
it('returns error', () => {
84+
expect(parseFileConfig('config.jsonc', '{')).toEqual({
85+
success: false,
86+
validationError: 'Invalid JSONC (parsing failed)',
87+
validationMessage:
88+
'JSONC.parse error: `Invalid JSONC`',
89+
});
90+
});
91+
});
5992
});

lib/config/parse.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,22 @@ export function parseFileConfig(
2828
validationMessage,
2929
};
3030
}
31+
} else if (fileType === '.jsonc') {
32+
try {
33+
return { success: true, parsedContents: parseJson(fileContents, fileName) };
34+
} catch (err) {
35+
logger.debug({ fileName, fileContents }, 'Error parsing JSONC file');
36+
const validationError = 'Invalid JSONC (parsing failed)';
37+
const validationMessage = `JSONC.parse error: \`${err.message.replaceAll(
38+
'`',
39+
"'",
40+
)}\``;
41+
return {
42+
success: false,
43+
validationError,
44+
validationMessage,
45+
};
46+
}
3147
} else {
3248
let allowDuplicateKeys = true;
3349
let jsonValidationError = jsonValidator.validate(

lib/workers/global/config/parse/file.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export async function getParsedContent(file: string): Promise<RenovateConfig> {
2121
case '.yml':
2222
return parseSingleYaml(await readSystemFile(file, 'utf8'));
2323
case '.json5':
24+
case '.jsonc':
2425
case '.json':
2526
return parseJson(
2627
await readSystemFile(file, 'utf8'),

lib/workers/repository/init/merge.spec.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,19 @@ describe('workers/repository/init/merge', () => {
199199
});
200200
});
201201

202+
it('finds and parse renovate.jsonc', async () => {
203+
const configFileRaw = `{
204+
// this is jsonc format with comments
205+
"extends": ["config:base"]
206+
}`;
207+
scm.getFileList.mockResolvedValue(['package.json', 'renovate.jsonc']);
208+
fs.readLocalFile.mockResolvedValue(configFileRaw);
209+
expect(await detectRepoFileConfig()).toEqual({
210+
configFileName: 'renovate.jsonc',
211+
configFileParsed: { extends: ['config:base'] },
212+
});
213+
});
214+
202215
it('finds .github/renovate.json', async () => {
203216
scm.getFileList.mockResolvedValue([
204217
'package.json',
@@ -223,6 +236,36 @@ describe('workers/repository/init/merge', () => {
223236
});
224237
});
225238

239+
it('finds .github/renovate.jsonc', async () => {
240+
scm.getFileList.mockResolvedValue([
241+
'package.json',
242+
'.github/renovate.jsonc',
243+
]);
244+
fs.readLocalFile.mockResolvedValue(`{
245+
// JSONC config with comments
246+
"extends": ["config:base"]
247+
}`);
248+
expect(await detectRepoFileConfig()).toEqual({
249+
configFileName: '.github/renovate.jsonc',
250+
configFileParsed: { extends: ['config:base'] },
251+
});
252+
});
253+
254+
it('finds .gitlab/renovate.jsonc', async () => {
255+
scm.getFileList.mockResolvedValue([
256+
'package.json',
257+
'.gitlab/renovate.jsonc',
258+
]);
259+
fs.readLocalFile.mockResolvedValue(`{
260+
// JSONC config with comments
261+
"enabled": true
262+
}`);
263+
expect(await detectRepoFileConfig()).toEqual({
264+
configFileName: '.gitlab/renovate.jsonc',
265+
configFileParsed: { enabled: true },
266+
});
267+
});
268+
226269
it('finds .renovaterc.json', async () => {
227270
scm.getFileList.mockResolvedValue(['package.json', '.renovaterc.json']);
228271
fs.readLocalFile.mockResolvedValue('{}');

0 commit comments

Comments
 (0)