mirror of
https://github.com/renovatebot/renovate.git
synced 2025-04-12 20:08:13 +00:00
fix(util): parse jsonc as jsonc (#35177)
This commit is contained in:
parent
c8baf9a270
commit
c1581761cb
3 changed files with 62 additions and 14 deletions
|
@ -27,6 +27,14 @@ const onlyJson5parsableString = `
|
|||
"isMarried": false,
|
||||
}
|
||||
`;
|
||||
const validJsoncString = `
|
||||
{
|
||||
// This is a comment
|
||||
"name": "John Doe",
|
||||
"age": 30,
|
||||
"city": "New York"
|
||||
}
|
||||
`;
|
||||
|
||||
describe('util/common', () => {
|
||||
beforeEach(() => hostRules.clear());
|
||||
|
@ -106,7 +114,7 @@ describe('util/common', () => {
|
|||
expect(() => parseJson(invalidJsonString, 'renovate.json')).toThrow();
|
||||
});
|
||||
|
||||
it('catches and warns if content parsing faield with JSON.parse but not with JSON5.parse', () => {
|
||||
it('catches and warns if content parsing failed with JSON.parse but not with JSON5.parse', () => {
|
||||
expect(parseJson(onlyJson5parsableString, 'renovate.json')).toEqual({
|
||||
name: 'Bob',
|
||||
age: 35,
|
||||
|
@ -118,5 +126,29 @@ describe('util/common', () => {
|
|||
'File contents are invalid JSON but parse using JSON5. Support for this will be removed in a future release so please change to a support .json5 file name or ensure correct JSON syntax.',
|
||||
);
|
||||
});
|
||||
|
||||
it('does not warn if filename ends with .jsonc', () => {
|
||||
parseJson(validJsoncString, 'renovate.jsonc');
|
||||
expect(logger.logger.warn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not warn if filename ends with .json5', () => {
|
||||
parseJson(onlyJson5parsableString, 'renovate.json5');
|
||||
expect(logger.logger.warn).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseJsonc', () => {
|
||||
it('returns parsed jsonc', () => {
|
||||
expect(parseJson(validJsoncString, 'renovate.jsonc')).toEqual({
|
||||
name: 'John Doe',
|
||||
age: 30,
|
||||
city: 'New York',
|
||||
});
|
||||
});
|
||||
|
||||
it('throws error for invalid jsonc', () => {
|
||||
expect(() => parseJson(invalidJsonString, 'renovate.jsonc')).toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import JSON5 from 'json5';
|
||||
import * as JSONC from 'jsonc-parser';
|
||||
import type { JsonValue } from 'type-fest';
|
||||
import {
|
||||
BITBUCKET_API_USING_HOST_TYPES,
|
||||
BITBUCKET_SERVER_API_USING_HOST_TYPES,
|
||||
|
@ -80,21 +82,27 @@ export function noLeadingAtSymbol(input: string): string {
|
|||
return input.startsWith('@') ? input.slice(1) : input;
|
||||
}
|
||||
|
||||
export function parseJson(content: string | null, filename: string): unknown {
|
||||
export function parseJson(content: string | null, filename: string): JsonValue {
|
||||
if (!content) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return filename.endsWith('.json5')
|
||||
? JSON5.parse(content)
|
||||
: parseJsonWithFallback(content, filename);
|
||||
if (filename.endsWith('.jsonc')) {
|
||||
return parseJsonc(content);
|
||||
}
|
||||
|
||||
if (filename.endsWith('.json5')) {
|
||||
return JSON5.parse(content);
|
||||
}
|
||||
|
||||
return parseJsonWithFallback(content, filename);
|
||||
}
|
||||
|
||||
export function parseJsonWithFallback(
|
||||
content: string,
|
||||
context: string,
|
||||
): unknown {
|
||||
let parsedJson: unknown;
|
||||
): JsonValue {
|
||||
let parsedJson: JsonValue;
|
||||
|
||||
try {
|
||||
parsedJson = JSON.parse(content);
|
||||
|
@ -108,3 +116,12 @@ export function parseJsonWithFallback(
|
|||
|
||||
return parsedJson;
|
||||
}
|
||||
|
||||
export function parseJsonc(content: string): JsonValue {
|
||||
const errors: JSONC.ParseError[] = [];
|
||||
const value = JSONC.parse(content, errors, { allowTrailingComma: true });
|
||||
if (errors.length === 0) {
|
||||
return value;
|
||||
}
|
||||
throw new Error('Invalid JSONC');
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import JSON5 from 'json5';
|
||||
import * as JSONC from 'jsonc-parser';
|
||||
import { DateTime } from 'luxon';
|
||||
import type { JsonArray, JsonValue } from 'type-fest';
|
||||
import {
|
||||
|
@ -11,6 +10,7 @@ import {
|
|||
} from 'zod';
|
||||
import { logger } from '../logger';
|
||||
import type { PackageDependency } from '../modules/manager/types';
|
||||
import { parseJsonc } from './common';
|
||||
import { parse as parseToml } from './toml';
|
||||
import type { YamlOptions } from './yaml';
|
||||
import { parseSingleYaml, parseYaml } from './yaml';
|
||||
|
@ -226,13 +226,12 @@ export const Json5 = z.string().transform((str, ctx): JsonValue => {
|
|||
});
|
||||
|
||||
export const Jsonc = z.string().transform((str, ctx): JsonValue => {
|
||||
const errors: JSONC.ParseError[] = [];
|
||||
const value = JSONC.parse(str, errors, { allowTrailingComma: true });
|
||||
if (errors.length === 0) {
|
||||
return value;
|
||||
try {
|
||||
return parseJsonc(str);
|
||||
} catch {
|
||||
ctx.addIssue({ code: 'custom', message: 'Invalid JSONC' });
|
||||
return z.NEVER;
|
||||
}
|
||||
ctx.addIssue({ code: 'custom', message: 'Invalid JSONC' });
|
||||
return z.NEVER;
|
||||
});
|
||||
|
||||
export const UtcDate = z
|
||||
|
|
Loading…
Add table
Reference in a new issue