Skip to content

Commit c80a561

Browse files
authored
Merge branch 'main' into fix/1115-groovy-interface-inheritance
2 parents 732c82d + d255297 commit c80a561

1 file changed

Lines changed: 82 additions & 0 deletions

File tree

tests/parsers/native-drop-classification.test.ts

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { describe, expect, it } from 'vitest';
55
import {
66
classifyNativeDrops,
77
formatDropExtensionSummary,
8+
LANGUAGE_REGISTRY,
89
NATIVE_SUPPORTED_EXTENSIONS,
910
} from '../../src/domain/parser.js';
1011

@@ -203,3 +204,84 @@ describe('NATIVE_SUPPORTED_EXTENSIONS drift guard', () => {
203204
).toEqual([]);
204205
});
205206
});
207+
208+
/**
209+
* Parity gate for `LANGUAGE_REGISTRY` ↔ `NATIVE_SUPPORTED_EXTENSIONS`.
210+
*
211+
* Acceptance criterion from #1071 (tracked in #1121): a CI gate prevents
212+
* future drift between the JS `LANGUAGE_REGISTRY` and the Rust extractor
213+
* coverage. The existing drift guard above covers
214+
* `NATIVE_SUPPORTED_EXTENSIONS ↔ parser_registry.rs`, but the link from
215+
* `LANGUAGE_REGISTRY` (the source of truth for languages we support at all)
216+
* to `NATIVE_SUPPORTED_EXTENSIONS` (the hand-maintained mirror of the Rust
217+
* enum) had no test — silently adding a WASM-only language would degrade the
218+
* native engine without flagging the regression.
219+
*
220+
* This test closes that gap. Every extension declared in `LANGUAGE_REGISTRY`
221+
* must either:
222+
* 1. Be present in `NATIVE_SUPPORTED_EXTENSIONS` (i.e. a Rust extractor
223+
* exists), or
224+
* 2. Appear in `WASM_ONLY_ALLOWLIST` below, with a comment explaining why
225+
* the language is intentionally WASM-only.
226+
*
227+
* Adding an extension to the allowlist is a deliberate choice: prefer porting
228+
* the extractor to Rust. The allowlist exists so a contributor can land a
229+
* WASM-only grammar (e.g. while a Rust port is in flight) without bypassing
230+
* the gate entirely, but every entry should have a tracking issue.
231+
*/
232+
describe('LANGUAGE_REGISTRY ↔ NATIVE_SUPPORTED_EXTENSIONS parity', () => {
233+
// Extensions intentionally left WASM-only. Currently empty: every language
234+
// in `LANGUAGE_REGISTRY` has a corresponding Rust extractor. If you must
235+
// add an entry, include a comment with the language id and the issue
236+
// tracking the Rust port.
237+
const WASM_ONLY_ALLOWLIST: ReadonlySet<string> = new Set<string>();
238+
239+
it('every LANGUAGE_REGISTRY extension has a Rust extractor or is on the allowlist', () => {
240+
const registryExts = new Set<string>();
241+
for (const entry of LANGUAGE_REGISTRY) {
242+
for (const ext of entry.extensions) {
243+
registryExts.add(ext.toLowerCase());
244+
}
245+
}
246+
const missingFromNative = [...registryExts]
247+
.filter((ext) => !NATIVE_SUPPORTED_EXTENSIONS.has(ext))
248+
.filter((ext) => !WASM_ONLY_ALLOWLIST.has(ext))
249+
.sort();
250+
expect(
251+
missingFromNative,
252+
`LANGUAGE_REGISTRY extensions without a Rust extractor (and not on WASM_ONLY_ALLOWLIST): ${missingFromNative.join(
253+
', ',
254+
)}. Either port the extractor to Rust and add the extension to NATIVE_SUPPORTED_EXTENSIONS, or add it to WASM_ONLY_ALLOWLIST with a justification.`,
255+
).toEqual([]);
256+
});
257+
258+
it('WASM_ONLY_ALLOWLIST does not list extensions that already have a Rust extractor', () => {
259+
// Catches stale allowlist entries: once a language is ported to Rust the
260+
// allowlist line should be deleted, not left behind as dead config.
261+
const stale = [...WASM_ONLY_ALLOWLIST]
262+
.map((ext) => ext.toLowerCase())
263+
.filter((ext) => NATIVE_SUPPORTED_EXTENSIONS.has(ext));
264+
expect(
265+
stale,
266+
`WASM_ONLY_ALLOWLIST entries that already have a Rust extractor — remove them: ${stale.join(', ')}`,
267+
).toEqual([]);
268+
});
269+
270+
it('WASM_ONLY_ALLOWLIST only references extensions that LANGUAGE_REGISTRY declares', () => {
271+
// Catches typos and dead entries: an allowlist line for an extension no
272+
// longer in the registry is silently useless.
273+
const registryExts = new Set<string>();
274+
for (const entry of LANGUAGE_REGISTRY) {
275+
for (const ext of entry.extensions) {
276+
registryExts.add(ext.toLowerCase());
277+
}
278+
}
279+
const orphans = [...WASM_ONLY_ALLOWLIST]
280+
.map((ext) => ext.toLowerCase())
281+
.filter((ext) => !registryExts.has(ext));
282+
expect(
283+
orphans,
284+
`WASM_ONLY_ALLOWLIST entries not declared in LANGUAGE_REGISTRY — likely a typo: ${orphans.join(', ')}`,
285+
).toEqual([]);
286+
});
287+
});

0 commit comments

Comments
 (0)