mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-14 23:22:54 +00:00
* fix(zig): vendor tree-sitter-zig so npm i -g no longer warns on peers Published overrides do not apply to dependents, so the Zig optionalDependency kept warning that tree-sitter@0.21.1 does not satisfy peerOptional ^0.22.1. Load it from vendor/ like Dart/Kotlin/Swift instead. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(ci): add zig parse snippet to prebuild validate The six zig prebuild jobs failed at "Validate the .node loads and parses" because snippets[GRAMMAR] was undefined and tree-sitter threw "Input must be a function". Co-authored-by: Cursor <cursoragent@cursor.com> * chore: drop Unreleased changelog note from the Zig vendor PR CHANGELOG.md is owned by the release process, not individual PRs. Co-authored-by: Cursor <cursoragent@cursor.com> * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33949409205 * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33949616521 * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33949829377 * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33950025077 * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33950220655 * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33950400275 * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33950607933 * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33950882912 * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33951170483 * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33951386477 * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33951624305 * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33951813452 * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33951998309 * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33952225172 * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33952524393 * fix(ci): stop native prebuild rebuild loops PR path filters and source checks see the cumulative diff, so generated binaries kept rebuilding the original source change. Skip output-only synchronize events using their exact before/head range, failing closed when Git cannot compare it. Exercise the workflow against real commit histories, including multi-commit source pushes and merge-ref drift. * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33953226606 * fix: address Zig PR review feedback (#3180) Check for the vendored package without loading its native binding so a broken installed Zig grammar fails the parsing test instead of skipping. Match the optional child descriptor in the Zig metadata declaration and include Zig in the two optional/vendored grammar comments. Validation: 159 targeted tests, TypeScript, metadata type fixture, and formatting passed. Injected native-load failure now fails instead of skipping; explicit Zig opt-out still skips. * chore(vendor): rebuild native prebuilds (tree-sitter-zig) Built by https://github.com/abhigyanpatwari/GitNexus/actions/runs/33956342308 --------- Co-authored-by: Gergo Magyar <gergomagyar0@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: gitnexus-release-bot[bot] <gitnexus-release-bot[bot]@users.noreply.github.com>
152 lines
7.8 KiB
TypeScript
152 lines
7.8 KiB
TypeScript
import { describe, it, expect, afterEach, vi } from 'vitest';
|
|
import { SupportedLanguages } from '../../src/config/supported-languages.js';
|
|
|
|
/**
|
|
* Runtime opt-out for optional grammars (#2091, #2093).
|
|
*
|
|
* `GITNEXUS_SKIP_OPTIONAL_GRAMMARS` used to be an install-time-only env (the
|
|
* postinstall build scripts read it). `parser-loader` now also honors it at
|
|
* analyze time: when set, genuinely-optional grammars (swift/dart/kotlin/zig)
|
|
* report unavailable so the ingestion pipeline skips their files, mirroring a
|
|
* genuinely-absent binding. Grammars that are required `dependencies` routed
|
|
* through the optional machinery for ABI safety (C — `severity: 'error'`) are
|
|
* NEVER skippable this way.
|
|
*
|
|
* `parser-loader` memoizes load results at module scope, so each case loads a
|
|
* fresh copy via `vi.resetModules()` after setting the env. These assertions
|
|
* are install-state-robust: they only assert the SKIP direction (skip → false)
|
|
* and that required grammars are unaffected (true) — never that an optional
|
|
* grammar is positively available, which depends on the install/platform.
|
|
*/
|
|
|
|
const ENV = 'GITNEXUS_SKIP_OPTIONAL_GRAMMARS';
|
|
|
|
async function freshLoader(skipValue: string | undefined) {
|
|
vi.resetModules();
|
|
if (skipValue === undefined) delete process.env[ENV];
|
|
else process.env[ENV] = skipValue;
|
|
return import('../../src/core/tree-sitter/parser-loader.js');
|
|
}
|
|
|
|
afterEach(() => {
|
|
delete process.env[ENV];
|
|
vi.resetModules();
|
|
});
|
|
|
|
describe('parser-loader GITNEXUS_SKIP_OPTIONAL_GRAMMARS runtime gate', () => {
|
|
it('skip=1 reports every optional grammar as unavailable', async () => {
|
|
const { isLanguageAvailable } = await freshLoader('1');
|
|
expect(isLanguageAvailable(SupportedLanguages.Swift)).toBe(false);
|
|
expect(isLanguageAvailable(SupportedLanguages.Dart)).toBe(false);
|
|
expect(isLanguageAvailable(SupportedLanguages.Kotlin)).toBe(false);
|
|
// Zig is a vendored optional grammar: the documented opt-out must cover
|
|
// it too (`optional-grammars.ts` lists it among the skippable grammars).
|
|
expect(isLanguageAvailable(SupportedLanguages.Zig)).toBe(false);
|
|
});
|
|
|
|
it('a comma list can name zig on its own', async () => {
|
|
const { isLanguageAvailable, isGrammarRuntimeSkipped } = await freshLoader('zig');
|
|
expect(isLanguageAvailable(SupportedLanguages.Zig)).toBe(false);
|
|
expect(isGrammarRuntimeSkipped(SupportedLanguages.Zig)).toBe(true);
|
|
expect(isGrammarRuntimeSkipped(SupportedLanguages.Swift)).toBe(false);
|
|
});
|
|
|
|
it('skip=all/true/* also skip every optional grammar', async () => {
|
|
for (const v of ['all', 'true', '*']) {
|
|
const { isLanguageAvailable } = await freshLoader(v);
|
|
expect(isLanguageAvailable(SupportedLanguages.Swift), `value=${v}`).toBe(false);
|
|
expect(isLanguageAvailable(SupportedLanguages.Dart), `value=${v}`).toBe(false);
|
|
expect(isLanguageAvailable(SupportedLanguages.Kotlin), `value=${v}`).toBe(false);
|
|
expect(isLanguageAvailable(SupportedLanguages.Zig), `value=${v}`).toBe(false);
|
|
}
|
|
});
|
|
|
|
it('does NOT skip required grammars — skip=all is a no-op for C / Python', async () => {
|
|
// Compare availability WITH skip=all against the baseline (no skip). The
|
|
// runtime opt-out must never change a required grammar's availability:
|
|
// C is `optional: true` + `severity: 'error'` (a required dep routed
|
|
// through the optional machinery for ABI safety, #1242), and Python is a
|
|
// plain required dep. Asserting EQUALITY (not positive truth) keeps this
|
|
// install-state-robust — C's native binding is intentionally fallible, so
|
|
// a positive assertion could flake on an ABI-mismatched matrix.
|
|
const base = await freshLoader(undefined);
|
|
const cBase = base.isLanguageAvailable(SupportedLanguages.C);
|
|
const pyBase = base.isLanguageAvailable(SupportedLanguages.Python);
|
|
const skipped = await freshLoader('all');
|
|
expect(skipped.isLanguageAvailable(SupportedLanguages.C)).toBe(cBase);
|
|
expect(skipped.isLanguageAvailable(SupportedLanguages.Python)).toBe(pyBase);
|
|
});
|
|
|
|
it('a comma list skips ONLY the named grammars — un-named ones unaffected', async () => {
|
|
// Baseline (no skip) so the isolation check is install-state-robust.
|
|
const base = await freshLoader(undefined);
|
|
const dartBase = base.isLanguageAvailable(SupportedLanguages.Dart);
|
|
const kotlinBase = base.isLanguageAvailable(SupportedLanguages.Kotlin);
|
|
const { isLanguageAvailable } = await freshLoader('swift');
|
|
expect(isLanguageAvailable(SupportedLanguages.Swift)).toBe(false);
|
|
// A prefix/union bug would skip these too — assert they match baseline.
|
|
expect(isLanguageAvailable(SupportedLanguages.Dart)).toBe(dartBase);
|
|
expect(isLanguageAvailable(SupportedLanguages.Kotlin)).toBe(kotlinBase);
|
|
});
|
|
|
|
it('accepts the tree-sitter-<lang> package spelling — others unaffected', async () => {
|
|
const base = await freshLoader(undefined);
|
|
const swiftBase = base.isLanguageAvailable(SupportedLanguages.Swift);
|
|
const kotlinBase = base.isLanguageAvailable(SupportedLanguages.Kotlin);
|
|
const { isLanguageAvailable } = await freshLoader('tree-sitter-dart');
|
|
expect(isLanguageAvailable(SupportedLanguages.Dart)).toBe(false);
|
|
expect(isLanguageAvailable(SupportedLanguages.Swift)).toBe(swiftBase);
|
|
expect(isLanguageAvailable(SupportedLanguages.Kotlin)).toBe(kotlinBase);
|
|
});
|
|
|
|
it('accepts a multi-entry list', async () => {
|
|
const { isLanguageAvailable } = await freshLoader('kotlin, dart');
|
|
expect(isLanguageAvailable(SupportedLanguages.Kotlin)).toBe(false);
|
|
expect(isLanguageAvailable(SupportedLanguages.Dart)).toBe(false);
|
|
});
|
|
|
|
it('getLanguageGrammar throws a clean "Unsupported language" for a skipped optional grammar', async () => {
|
|
const { getLanguageGrammar } = await freshLoader('all');
|
|
expect(() => getLanguageGrammar(SupportedLanguages.Swift)).toThrow(/Unsupported language/);
|
|
});
|
|
|
|
it('an empty / unset env does not skip (required grammars load)', async () => {
|
|
const { isLanguageAvailable } = await freshLoader(undefined);
|
|
expect(isLanguageAvailable(SupportedLanguages.Python)).toBe(true);
|
|
});
|
|
|
|
it('isGrammarRuntimeSkipped reflects the opt-out, never for required grammars', async () => {
|
|
const swiftOnly = await freshLoader('swift');
|
|
expect(swiftOnly.isGrammarRuntimeSkipped(SupportedLanguages.Swift)).toBe(true);
|
|
expect(swiftOnly.isGrammarRuntimeSkipped(SupportedLanguages.Dart)).toBe(false);
|
|
const all = await freshLoader('all');
|
|
expect(all.isGrammarRuntimeSkipped(SupportedLanguages.Swift)).toBe(true);
|
|
// C is not `userSkippable` (required dep via the optional machinery) — even
|
|
// `all` must not mark it runtime-skipped.
|
|
expect(all.isGrammarRuntimeSkipped(SupportedLanguages.C)).toBe(false);
|
|
});
|
|
|
|
it('logs an accurate runtime-skip note, not a missing-binding message', async () => {
|
|
// Import the logger AND parser-loader from the SAME fresh module registry so
|
|
// the capture intercepts the loader's logger instance.
|
|
vi.resetModules();
|
|
process.env[ENV] = 'swift';
|
|
const { _captureLogger } = await import('../../src/core/logger.js');
|
|
const { isLanguageAvailable } = await import('../../src/core/tree-sitter/parser-loader.js');
|
|
const cap = _captureLogger();
|
|
try {
|
|
isLanguageAvailable(SupportedLanguages.Swift); // triggers the one-time skip log
|
|
const msgs = cap
|
|
.records()
|
|
.map((r) => (typeof r.msg === 'string' ? r.msg : ''))
|
|
.filter(Boolean);
|
|
const skipMsg = msgs.find((m) => m.includes('GITNEXUS_SKIP_OPTIONAL_GRAMMARS'));
|
|
expect(skipMsg, `captured:\n${msgs.join('\n')}`).toBeTruthy();
|
|
// The opt-out note must NOT borrow the install/platform "missing binding"
|
|
// language — that would tell a deliberate opt-out to reinstall/rebuild.
|
|
expect(skipMsg).not.toMatch(/no prebuilt|failed to load|npm rebuild/i);
|
|
} finally {
|
|
cap.restore();
|
|
}
|
|
});
|
|
});
|