|
| 1 | +import fs from 'node:fs'; |
| 2 | +import path from 'node:path'; |
| 3 | +import { fileURLToPath } from 'node:url'; |
1 | 4 | import { beforeAll, describe, expect, it } from 'vitest'; |
2 | 5 | import { createParsers, extractLuaSymbols } from '../../src/domain/parser.js'; |
| 6 | +import { LUA_BUILTIN_GLOBALS } from '../../src/extractors/lua.js'; |
3 | 7 |
|
4 | 8 | describe('Lua parser', () => { |
5 | 9 | let parsers: any; |
@@ -145,3 +149,36 @@ string.format("%s", name)`); |
145 | 149 | }); |
146 | 150 | }); |
147 | 151 | }); |
| 152 | + |
| 153 | +describe('LUA_BUILTIN_GLOBALS cross-engine parity', () => { |
| 154 | + // Greptile follow-up (#1912): the allowlist is duplicated in lua.rs and |
| 155 | + // lua.ts with only a prose comment linking them. If one drifts, native and |
| 156 | + // WASM silently disagree on which reassignments produce a value-ref edge. |
| 157 | + // This reads the Rust list as text (it can't be imported into a JS test) |
| 158 | + // and diffs it against the real TS Set, so any future one-sided edit fails |
| 159 | + // CI instead of shipping a silent engine divergence. |
| 160 | + it('matches the Rust extractor allowlist exactly', () => { |
| 161 | + const __filename = fileURLToPath(import.meta.url); |
| 162 | + const __dirname = path.dirname(__filename); |
| 163 | + const rustSource = fs.readFileSync( |
| 164 | + path.join(__dirname, '../../crates/codegraph-core/src/extractors/lua.rs'), |
| 165 | + 'utf8', |
| 166 | + ); |
| 167 | + const match = /const LUA_BUILTIN_GLOBALS: &\[&str\] = &\[([\s\S]*?)\];/.exec(rustSource); |
| 168 | + expect(match, 'LUA_BUILTIN_GLOBALS array not found in lua.rs').not.toBeNull(); |
| 169 | + |
| 170 | + const rustNames = [...match![1].matchAll(/"([a-zA-Z0-9_]+)"/g)].map((m) => m[1]); |
| 171 | + expect( |
| 172 | + rustNames.length, |
| 173 | + 'regex extracted zero names from lua.rs — pattern likely stale', |
| 174 | + ).toBeGreaterThan(0); |
| 175 | + |
| 176 | + const rustSet = new Set(rustNames); |
| 177 | + expect(rustSet.size, 'lua.rs has duplicate entries').toBe(rustNames.length); |
| 178 | + |
| 179 | + const missingFromRust = [...LUA_BUILTIN_GLOBALS].filter((n) => !rustSet.has(n)); |
| 180 | + const missingFromTs = rustNames.filter((n) => !LUA_BUILTIN_GLOBALS.has(n)); |
| 181 | + expect(missingFromRust, 'present in lua.ts but missing from lua.rs').toEqual([]); |
| 182 | + expect(missingFromTs, 'present in lua.rs but missing from lua.ts').toEqual([]); |
| 183 | + }); |
| 184 | +}); |
0 commit comments