Skip to content

Commit

Permalink
validation
Browse files Browse the repository at this point in the history
  • Loading branch information
RahulGautamSingh committed Nov 28, 2024
1 parent cb0dd89 commit 6caecbd
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 28 deletions.
1 change: 1 addition & 0 deletions lib/config/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ export async function validateConfig(
'customType',
'description',
'fileMatch',
'matchQueries',
'matchStrings',
'matchStringsStrategy',
'depNameTemplate',
Expand Down
12 changes: 12 additions & 0 deletions lib/modules/manager/custom/jsonata/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,18 @@ describe('modules/manager/custom/jsonata/index', () => {
expect(res?.deps).toHaveLength(2);
});

it('excludes and warns if invalid jsonata query found', async () => {
const config = {
matchQueries: ['{', `{"depName": "foo"}`, `{"depName": "bar"}`],
};
const res = await extractPackageFile('{}', 'unused', config);
expect(res?.deps).toHaveLength(2);
expect(logger.warn).toHaveBeenCalledWith(
{ err: expect.any(Object) },
`Failed to compile JSONata query: {. Excluding it from queries.`,
);
});

it('extracts dependency with autoReplaceStringTemplate', async () => {
const config = {
matchQueries: [`{"depName": "foo"}`],
Expand Down
58 changes: 37 additions & 21 deletions lib/modules/manager/custom/jsonata/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import is from '@sindresorhus/is';
import jsonata from 'jsonata';
import { logger } from '../../../../logger';
import type { PackageDependency, PackageFile, Result } from '../../types';
import type { PackageDependency, PackageFileContent } from '../../types';
import type { JSONataManagerTemplates, JsonataExtractConfig } from './types';
import { createDependency } from './utils';

Expand All @@ -11,14 +11,6 @@ export const defaultConfig = {
fileMatch: [],
};

export interface CustomPackageFile extends PackageFile {
matchQueries: string[];
}

export function testJsonQuery(query: string): void {
jsonata(query);
}

const validMatchFields = [
'depName',
'packageName',
Expand All @@ -31,24 +23,48 @@ const validMatchFields = [
'depType',
];

function handleMatching(
async function handleMatching(
json: unknown,
packageFile: string,
config: JsonataExtractConfig,
): PackageDependency[] {
return config.matchQueries
.flatMap((matchQuery) => jsonata(matchQuery).evaluate(json) ?? [])
.map((queryResult) =>
createDependency(queryResult as Record<string, string>, config),
)
.filter(is.truthy);
): Promise<PackageDependency[]> {
// Pre-compile all JSONata expressions once
const compiledExpressions = config.matchQueries
.map((query) => {
try {
return jsonata(query);
} catch (err) {
logger.warn(
{ err },
`Failed to compile JSONata query: ${query}. Excluding it from queries.`,
);
return null;
}
})
.filter((expr) => expr !== null);

// Execute all expressions in parallel
const results = await Promise.all(
compiledExpressions.map(async (expr) => {
const result = (await expr.evaluate(json)) ?? [];
return is.array(result) ? result : [result];
}),
);

// Flatten results and create dependencies
return results
.flat()
.map((queryResult) => {
return createDependency(queryResult as Record<string, string>, config);
})
.filter((dep) => dep !== null);
}

export function extractPackageFile(
export async function extractPackageFile(
content: string,
packageFile: string,
config: JsonataExtractConfig,
): Result<PackageFile | null> {
): Promise<PackageFileContent | null> {
let deps: PackageDependency[];

let json;
Expand All @@ -62,12 +78,12 @@ export function extractPackageFile(
return null;
}

deps = handleMatching(json, packageFile, config);
deps = await handleMatching(json, packageFile, config);

// filter all null values
deps = deps.filter(is.truthy);
if (deps.length) {
const res: CustomPackageFile & JSONataManagerTemplates = {
const res: PackageFileContent & JSONataManagerTemplates = {
deps,
matchQueries: config.matchQueries,
};
Expand Down
13 changes: 7 additions & 6 deletions lib/modules/manager/custom/jsonata/readme.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
The `json-jsonata` manager is designed to allow users to manually configure Renovate for how to find dependencies in JSON files that aren't detected by the built-in package managers.
The `jsonata` manager is designed to allow users to manually configure Renovate for how to find dependencies in JSON files that aren't detected by the built-in package managers.

This manager is unique in Renovate in that:

- It is configurable via [JSONata](https://jsonata.org/) queries.
- Through the use of the `jsonataManagers` config, multiple "JSONata managers" can be created for the same repository.
- Through the use of the `customManagers` config, multiple "JSONata managers" can be created for the same repository.
- It can extract any `datasource`.

To configure it, use the following syntax:

```
```javascript
{
"jsonataManagers": [
"customManagers": [
{
"type": "jsonata",
"fileMatch": ["<file match pattern>"],
"matchQueries": ['<query>'],
...
Expand All @@ -36,9 +37,9 @@ Where `<query>` is a [JSONata](https://docs.jsonata.org/overview.html) query tha
}
```

The meaning of each field is the same as the meaning of the capturing groups for regex managers.
The meaning of each field is the same as the meaning of the capturing groups for the `regex` manager.

The following configuration is also available for each `jsonManager` element, again with the same meaning as for the regex manager:
The following configuration is also available for each `jsonata` manager's element, again with the same meaning as for the regex manager:

- `depNameTemplate`.
- `packageNameTemplate`.
Expand Down
1 change: 0 additions & 1 deletion lib/modules/manager/custom/jsonata/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export interface JSONataManagerTemplates {
}

export interface JSONataManagerConfig extends JSONataManagerTemplates {
// fileMatch: string[];
matchQueries: string[];
autoReplaceStringTemplate?: string;
}
Expand Down
1 change: 1 addition & 0 deletions lib/modules/manager/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export interface PackageFileContent<T = Record<string, any>>
packageFileVersion?: string;
skipInstalls?: boolean | null;
matchStrings?: string[];
matchQueries?: string[];
matchStringsStrategy?: MatchStringsStrategy;
}

Expand Down

0 comments on commit 6caecbd

Please sign in to comment.