feat(group): expand grpc extraction and proto resolution coverage

This commit is contained in:
ivkond 2026-04-09 18:12:52 +03:00
parent 54d681a434
commit e1d226d904
2 changed files with 35 additions and 10 deletions

View file

@ -595,13 +595,19 @@ export class GrpcExtractor implements ContractExtractor {
);
};
const getServiceRe = /\.getService(?:<[^>]+>)?\s*\(\s*['"](\w+)['"]\s*\)/g;
const grpcClientDecoratorRe =
/@GrpcClient\s*\([^)]*\)\s*(?:private|protected|public)?\s*(?:readonly\s+)?\w+[!?]?\s*:\s*(\w+Service)Client\b/g;
let match: RegExpExecArray | null;
while ((match = grpcClientDecoratorRe.exec(content)) !== null) {
pushConsumer(match[1], `${match[1]}Client`, 'ts_grpc_client_decorator');
}
const getServiceRe = /\.getService(?:<[^>]+>)?\s*\(\s*['"](\w+)['"]\s*\)/g;
while ((match = getServiceRe.exec(content)) !== null) {
pushConsumer(match[1], `${match[1]}Client`, 'ts_client_grpc_get_service');
}
const clientCtorRe = /new\s+(\w+)Client\s*\(/g;
const clientCtorRe = /new\s+(\w+Service)Client\s*\(/g;
while ((match = clientCtorRe.exec(content)) !== null) {
pushConsumer(match[1], `${match[1]}Client`, 'ts_generated_client');
}

View file

@ -380,7 +380,7 @@ export class AuthController {
expect(providers[0].confidence).toBe(0.8);
});
it('test_extract_ts_grpc_client_decorator_and_getService_returns_consumer', async () => {
it('test_extract_ts_grpc_client_decorator_returns_consumer', async () => {
writeFile(
'proto/auth.proto',
`syntax = "proto3";
@ -391,15 +391,12 @@ service AuthService {
);
writeFile(
'src/auth.client.ts',
`import { ClientGrpc, GrpcClient } from '@nestjs/microservices';
`import { GrpcClient } from '@nestjs/microservices';
import type { AuthServiceClient } from './generated/auth';
export class AuthGateway {
@GrpcClient('AUTH_PACKAGE')
private readonly client!: ClientGrpc;
onModuleInit(): void {
this.client.getService<AuthService>('AuthService');
}
@GrpcClient({ package: 'auth.v1', protoPath: 'proto/auth.proto' })
private readonly authClient!: AuthServiceClient;
}`,
);
@ -459,6 +456,28 @@ export const authClient = new AuthServiceClient('localhost:50051', credentials.c
expect(consumers[0].contractId).toBe('grpc::auth.v1.AuthService/*');
});
it('test_extract_ts_non_service_client_constructor_is_ignored', async () => {
writeFile(
'proto/auth.proto',
`syntax = "proto3";
package auth.v1;
service AuthService {
rpc Login (LoginRequest) returns (LoginResponse);
}`,
);
writeFile(
'src/auth.client.ts',
`import { AuthClient } from './generated/auth';
export const authClient = new AuthClient('localhost:50051');`,
);
const contracts = await extractor.extract(null, tmpDir, makeRepo(tmpDir));
const consumers = contracts.filter((c) => c.role === 'consumer');
expect(consumers).toHaveLength(0);
});
it('test_extract_ts_loadPackageDefinition_constructor_returns_consumer', async () => {
writeFile(
'proto/auth.proto',