mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-11 22:53:04 +00:00
* docs: add Objective-C fork provider notes * feat(objective-c): add deterministic provider and grammar * feat(objective-c): finalize provider MVP * fix(objective-c): harden provider integration * fix(objective-c): normalize bare macro markers * docs(objective-c): integrate provider documentation * fix(objective-c): harden resolution and header classification * fix(objective-c): complete provider follow-ups * fix: address Objective-C review follow-ups * chore: format Objective-C grammar sources * fix(objective-c): harden review follow-ups * Address PR review feedback (#3179) Keep Objective-C chunking and macro recovery aligned with the grammar, and stop Community MEMBER_OF edges from leaking into symbol context. Co-authored-by: Cursor <cursoragent@cursor.com> * Address follow-up review on ObjC chunking and language fallback. Keep preprocessor directive text from changing file-scope brace depth, group real ivar nodes, skip header modifiers, and restore Rakefile/Gemfile detection through getLanguageFromFilename. Co-authored-by: Cursor <cursoragent@cursor.com> * Parse Objective-C headers with the objc grammar in embeddings. ensureAndParse and structural extraction now use the same content classifier as ingest, including method snippets from .h files, so Protocol/Category/Class chunks are not re-parsed as C++. Co-authored-by: Cursor <cursoragent@cursor.com> * Address PR review feedback (#3179) Keep file-scope macro elision off C line splices and @interface/@protocol/@implementation bodies, and attach ivar attributes to the following instance variable when chunking. Co-authored-by: Cursor <cursoragent@cursor.com> * chore(bench): rebaseline Objective-C CSV emit * feat(objective-c): add workspace resolution and linear emit benches Plain .h files are classified as C++, so the ObjC pass could not resolve #import of those headers. Load a C/C#-style workspace once per pass, and keep protocol-candidate USES linear. Refs #3179 Co-authored-by: Cursor <cursoragent@cursor.com> * Address PR review feedback (#3179) - Compare LadybugDB labels() as a scalar when excluding Community MEMBER_OF edges. - Walk superclass members, skip file-static C sibling defs, and ignore comments in ObjC header/macro scans. Note: pre-existing failure in objective-c-provider integration (worker-pool ready timeout) not addressed by this PR. Co-authored-by: Cursor <cursoragent@cursor.com> * Address PR review feedback (#3179) Emit Objective-C declaration captures so compilation-unit siblings can share header/implementation bindings, and keep class vs protocol visibility groups distinct. Note: pre-existing failure in worker-pool startup (GITNEXUS_WORKER_READY_TIMEOUT_MS) not addressed by this PR. Co-authored-by: Cursor <cursoragent@cursor.com> * Address PR review feedback (#3179) Emit every comma-separated property/ivar declarator, and count @interface after a multiline block comment closes so in-declaration macros stay intact. Note: pre-existing failure in worker-pool startup (GITNEXUS_WORKER_READY_TIMEOUT_MS) not addressed by this PR. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: ximengkai <ximengkai@soyoung.com> Co-authored-by: Gergő Magyar <gergomagyar@icloud.com> Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com>
136 lines
5 KiB
TypeScript
136 lines
5 KiB
TypeScript
/**
|
|
* Native-parser-unavailable handling.
|
|
*
|
|
* When a file's language has no loadable native parser (e.g. a Swift grammar
|
|
* that didn't build), the parse phase must SKIP the file with a warning — never
|
|
* crash. The sequential parser used to enforce this in-process; with it removed,
|
|
* the guarantee lives in the parse phase's pre-dispatch availability filter
|
|
* (`runChunkedParseAndResolve` → `isLanguageAvailable`), which runs on the MAIN
|
|
* thread before any worker is spawned. Mocking `parser-loader` exercises that
|
|
* filter; because the only file is filtered out, no worker pool is created — so
|
|
* this stays a fast unit test with no dist dependency.
|
|
*
|
|
* (Replaces `sequential-language-availability.test.ts`, which drove the deleted
|
|
* in-process parser and asserted its now-removed log message. `vi.mock` cannot
|
|
* cross the worker_threads isolate boundary, so the worker's own skip path can't
|
|
* be exercised this way — the main-thread filter is the testable seam.)
|
|
*/
|
|
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
|
|
|
|
vi.mock('../../src/core/tree-sitter/parser-loader.js', async (importOriginal) => {
|
|
const actual =
|
|
await importOriginal<typeof import('../../src/core/tree-sitter/parser-loader.js')>();
|
|
return { ...actual, isLanguageAvailable: vi.fn(() => true) };
|
|
});
|
|
|
|
import fs from 'node:fs';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import { SupportedLanguages } from 'gitnexus-shared';
|
|
import { createKnowledgeGraph } from '../../src/core/graph/graph.js';
|
|
import { runChunkedParseAndResolve } from '../../src/core/ingestion/pipeline-phases/parse-impl.js';
|
|
import * as parserLoader from '../../src/core/tree-sitter/parser-loader.js';
|
|
import { _captureLogger } from '../../src/core/logger.js';
|
|
import type { LoggerCapture } from '../../src/core/logger.js';
|
|
|
|
describe('native parser availability — unavailable language is skipped, not crashed', () => {
|
|
let cap: LoggerCapture | undefined;
|
|
let repoDir = '';
|
|
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
repoDir = fs.mkdtempSync(path.join(os.tmpdir(), 'lang-availability-'));
|
|
});
|
|
|
|
afterEach(() => {
|
|
cap?.restore();
|
|
cap = undefined;
|
|
if (repoDir) fs.rmSync(repoDir, { recursive: true, force: true });
|
|
});
|
|
|
|
/** Run the parse phase over a single Swift file in the temp repo. */
|
|
const runWithSwift = () => {
|
|
const rel = 'App.swift';
|
|
fs.writeFileSync(path.join(repoDir, rel), 'class AppViewController: UIViewController {}\n');
|
|
const scanned = [{ path: rel, size: fs.statSync(path.join(repoDir, rel)).size }];
|
|
return runChunkedParseAndResolve(
|
|
createKnowledgeGraph(),
|
|
scanned,
|
|
[rel],
|
|
1,
|
|
repoDir,
|
|
Date.now(),
|
|
() => {},
|
|
);
|
|
};
|
|
|
|
const runWithObjectiveCHeader = () => {
|
|
const rel = 'App.h';
|
|
fs.writeFileSync(path.join(repoDir, rel), '@interface App : NSObject\n@end\n');
|
|
const scanned = [{ path: rel, size: fs.statSync(path.join(repoDir, rel)).size }];
|
|
return runChunkedParseAndResolve(
|
|
createKnowledgeGraph(),
|
|
scanned,
|
|
[rel],
|
|
1,
|
|
repoDir,
|
|
Date.now(),
|
|
() => {},
|
|
);
|
|
};
|
|
|
|
it('skips the Swift file without crashing (and without spawning a pool) when its parser is unavailable', async () => {
|
|
vi.mocked(parserLoader.isLanguageAvailable).mockReturnValue(false);
|
|
// The only file is filtered out before dispatch, so the parse phase
|
|
// completes (returns its result) instead of throwing, and never needs a
|
|
// worker pool — `usedWorkerPool` stays false.
|
|
const result = await runWithSwift();
|
|
expect(result.usedWorkerPool).toBe(false);
|
|
});
|
|
|
|
it('warns that the unavailable-parser file was skipped', async () => {
|
|
cap = _captureLogger();
|
|
vi.mocked(parserLoader.isLanguageAvailable).mockReturnValue(false);
|
|
await runWithSwift();
|
|
const warned = cap
|
|
.records()
|
|
.some(
|
|
(r) =>
|
|
typeof r.msg === 'string' &&
|
|
r.msg.includes('Skipping 1 swift file(s)') &&
|
|
r.msg.includes('swift parser not available'),
|
|
);
|
|
expect(warned).toBe(true);
|
|
});
|
|
|
|
it('admits a content-classified Objective-C header when only C++ is unavailable', async () => {
|
|
vi.mocked(parserLoader.isLanguageAvailable).mockImplementation(
|
|
(language) => language === SupportedLanguages.ObjectiveC,
|
|
);
|
|
|
|
const result = await runWithObjectiveCHeader();
|
|
|
|
expect(result.usedWorkerPool).toBe(true);
|
|
});
|
|
|
|
it('skips a content-classified Objective-C header when only its parser is unavailable', async () => {
|
|
cap = _captureLogger();
|
|
vi.mocked(parserLoader.isLanguageAvailable).mockImplementation(
|
|
(language) => language !== SupportedLanguages.ObjectiveC,
|
|
);
|
|
|
|
const result = await runWithObjectiveCHeader();
|
|
|
|
expect(result.usedWorkerPool).toBe(false);
|
|
expect(
|
|
cap
|
|
.records()
|
|
.some(
|
|
(record) =>
|
|
typeof record.msg === 'string' &&
|
|
record.msg.includes('Skipping 1 objective-c file(s)') &&
|
|
record.msg.includes('objective-c parser not available'),
|
|
),
|
|
).toBe(true);
|
|
});
|
|
});
|