fix(ci): complete formatting, lint, and typecheck fixes

- prettier: format call-processor.ts, imported-return-types.ts,
  include-extractor.test.ts, cpp-captures.test.ts, cpp-imports.test.ts
- eslint: suppress intentional console.warn in manifest-extractor.ts
- typecheck: restore 'thrift' in ContractType union (was accidentally
  removed) and add thrift case to exhaustive switch in manifest-extractor
This commit is contained in:
HuangWenjie 2026-05-12 14:15:47 +08:00
parent 19ef13e101
commit 2ba7d57e43
7 changed files with 32 additions and 56 deletions

View file

@ -291,6 +291,7 @@ export class ManifestExtractor {
// fail the whole manifest extraction. Unresolved contracts still
// get a synthetic symbolUid below, so cross-impact can proceed.
const message = err instanceof Error ? err.message : String(err);
// eslint-disable-next-line no-console
console.warn(
`[manifest-extractor] resolveSymbol failed for ${link.type}:${link.contract} ` +
`in ${repoPathKey}: ${message}`,
@ -345,6 +346,8 @@ export class ManifestExtractor {
return `custom::${contract}`;
case 'include':
return `include::${contract}`;
case 'thrift':
return `thrift::${contract}`;
default: {
const _exhaustive: never = type;
throw new Error(`Unhandled ContractType: ${String(_exhaustive)}`);

View file

@ -1,4 +1,4 @@
export type ContractType = 'http' | 'grpc' | 'topic' | 'lib' | 'custom' | 'include';
export type ContractType = 'http' | 'grpc' | 'thrift' | 'topic' | 'lib' | 'custom' | 'include';
export type MatchType = 'exact' | 'manifest' | 'wildcard' | 'bm25' | 'embedding';
export type ContractRole = 'provider' | 'consumer';

View file

@ -934,7 +934,13 @@ export const processCalls = async (
// Defer resolution: Ruby attr_accessor properties are registered during
// this same loop, so cross-file lookups fail if the declaring file hasn't
// been processed yet. Collect now, resolve after all files are done.
pendingWrites.push({ receiverTypeName, propertyName, filePath: file.path, srcId, line: captureMap['assignment'].startPosition.row + 1 });
pendingWrites.push({
receiverTypeName,
propertyName,
filePath: file.path,
srcId,
line: captureMap['assignment'].startPosition.row + 1,
});
}
// Assignment-only capture (no @call sibling): skip the rest of this
// forEach iteration — this acts as a `continue` in the match loop.
@ -1383,7 +1389,10 @@ export const processCalls = async (
);
if (fieldOwner) {
graph.addRelationship({
id: generateId('ACCESSES', `${pw.srcId}:${fieldOwner.nodeId}:write${pw.line !== undefined ? `:${pw.line}` : ''}`),
id: generateId(
'ACCESSES',
`${pw.srcId}:${fieldOwner.nodeId}:write${pw.line !== undefined ? `:${pw.line}` : ''}`,
),
sourceId: pw.srcId,
targetId: fieldOwner.nodeId,
type: 'ACCESSES',
@ -2980,7 +2989,10 @@ export const processAssignmentsFromExtracted = (
const fieldOwner = resolveFieldOwnership(receiverTypeName, asn.propertyName, asn.filePath, ctx);
if (!fieldOwner) continue;
graph.addRelationship({
id: generateId('ACCESSES', `${asn.sourceId}:${fieldOwner.nodeId}:write${asn.line !== undefined ? `:${asn.line}` : ''}`),
id: generateId(
'ACCESSES',
`${asn.sourceId}:${fieldOwner.nodeId}:write${asn.line !== undefined ? `:${asn.line}` : ''}`,
),
sourceId: asn.sourceId,
targetId: fieldOwner.nodeId,
type: 'ACCESSES',

View file

@ -151,11 +151,7 @@ export function propagateImportedReturnTypes(
const refs = lookupBindingsAt(importerModule.id, localName, indexes);
for (const ref of refs) {
if (
ref.origin !== 'import' &&
ref.origin !== 'reexport' &&
ref.origin !== 'wildcard'
)
if (ref.origin !== 'import' && ref.origin !== 'reexport' && ref.origin !== 'wildcard')
continue;
const sourceModule = moduleScopeByFile.get(ref.def.filePath);
if (sourceModule === undefined) continue;

View file

@ -45,10 +45,7 @@ describe('IncludeExtractor', () => {
expect(providers).toHaveLength(2);
const ids = providers.map((p) => p.contractId).sort();
expect(ids).toEqual([
'include::map/base/types.h',
'include::map/base/view.h',
]);
expect(ids).toEqual(['include::map/base/types.h', 'include::map/base/view.h']);
expect(providers[0].type).toBe('include');
expect(providers[0].confidence).toBeGreaterThanOrEqual(0.95);
});
@ -91,10 +88,7 @@ int main() { return 0; }`,
expect(consumers).toHaveLength(2);
const ids = consumers.map((c) => c.contractId).sort();
expect(ids).toEqual([
'include::map/base/types.h',
'include::map/base/view.h',
]);
expect(ids).toEqual(['include::map/base/types.h', 'include::map/base/view.h']);
expect(consumers[0].type).toBe('include');
expect(consumers[0].confidence).toBe(0.85);
});
@ -181,22 +175,11 @@ int main() { return 0; }`,
fs.mkdirSync(consumerDir, { recursive: true });
const consumerFile = path.join(consumerDir, 'src/controller.cpp');
fs.mkdirSync(path.dirname(consumerFile), { recursive: true });
fs.writeFileSync(
consumerFile,
'#include "map/base/dice_map_view.h"\nvoid init() {}',
);
fs.writeFileSync(consumerFile, '#include "map/base/dice_map_view.h"\nvoid init() {}');
try {
const providerContracts = await extractor.extract(
null,
providerDir,
makeRepo(providerDir),
);
const consumerContracts = await extractor.extract(
null,
consumerDir,
makeRepo(consumerDir),
);
const providerContracts = await extractor.extract(null, providerDir, makeRepo(providerDir));
const consumerContracts = await extractor.extract(null, consumerDir, makeRepo(consumerDir));
const providers = providerContracts.filter((c) => c.role === 'provider');
const consumers = consumerContracts.filter((c) => c.role === 'consumer');
@ -220,14 +203,8 @@ int main() { return 0; }`,
describe('deduplication', () => {
it('deduplicates same include from multiple source files', async () => {
writeFile(
'src/a.cpp',
'#include "ext/api.h"\nvoid a() {}',
);
writeFile(
'src/b.cpp',
'#include "ext/api.h"\nvoid b() {}',
);
writeFile('src/a.cpp', '#include "ext/api.h"\nvoid a() {}');
writeFile('src/b.cpp', '#include "ext/api.h"\nvoid b() {}');
const contracts = await extractor.extract(null, tmpDir, makeRepo(tmpDir));
const consumers = contracts.filter((c) => c.role === 'consumer');

View file

@ -126,9 +126,7 @@ describe('emitCppScopeCaptures — namespace declarations', () => {
});
it('anonymous namespace has no @declaration.namespace (only @scope.namespace)', () => {
const matches = allMatches('namespace { int x; }', (t) =>
t.includes('@declaration.namespace'),
);
const matches = allMatches('namespace { int x; }', (t) => t.includes('@declaration.namespace'));
// Anonymous namespace should NOT produce a @declaration.namespace
expect(matches.length).toBe(0);
});
@ -220,9 +218,7 @@ describe('emitCppScopeCaptures — variable declarations', () => {
describe('emitCppScopeCaptures — enum declarations', () => {
it('captures enum with @declaration.enum', () => {
const m = findMatch('enum Color { Red, Green, Blue };', (t) =>
t.includes('@declaration.enum'),
);
const m = findMatch('enum Color { Red, Green, Blue };', (t) => t.includes('@declaration.enum'));
expect(m).toBeDefined();
expect(m!['@declaration.name'].text).toBe('Color');
});
@ -288,9 +284,7 @@ describe('emitCppScopeCaptures — imports', () => {
});
it('captures using namespace as wildcard import', () => {
const m = findMatch('using namespace std;', (t) =>
t.includes('@import.using-namespace'),
);
const m = findMatch('using namespace std;', (t) => t.includes('@import.using-namespace'));
expect(m).toBeDefined();
expect(m!['@import.source'].text).toBe('std');
expect(m!['@import.kind'].text).toBe('wildcard');
@ -381,9 +375,7 @@ describe('emitCppScopeCaptures — arity enrichment', () => {
});
it('enriches zero-parameter function', () => {
const m = findMatch('void foo() {}', (t) =>
t.includes('@declaration.parameter-count'),
);
const m = findMatch('void foo() {}', (t) => t.includes('@declaration.parameter-count'));
expect(m).toBeDefined();
expect(m!['@declaration.parameter-count'].text).toBe('0');
});

View file

@ -151,11 +151,7 @@ describe('C++ import target resolution (resolveCppImportTarget)', () => {
});
it('resolves suffix match with depth tiebreak', () => {
const result = resolveCppImportTarget(
'foo.h',
'main.cpp',
new Set(['a/b/c/foo.h', 'z/foo.h']),
);
const result = resolveCppImportTarget('foo.h', 'main.cpp', new Set(['a/b/c/foo.h', 'z/foo.h']));
expect(result).toBe('z/foo.h');
});