mirror of
https://github.com/colbymchenry/codegraph.git
synced 2026-10-16 20:53:57 +08:00
fcea0222f9
tree-sitter-kotlin 0.3.8 predates `when` guards (2.1), `..<` (1.9), multi-dollar strings (2.1) and nullable function-type receivers; each made error recovery drop the class around it (Exposed's dialect and query classes came out as loose functions). Offset-preserving preParse rewrites (so the kernel parses the same text): `is X if cond ->` -> `is X, cond ->` (the condition stops short of `->`, so `is X -> if (…)` bodies are untouched), `..<` -> `.. `, the `94189` prefix blanked, `T?.() ->` -> `T.( ) ->`. Parse-error files: Exposed 65 -> 43, kotlinx.coroutines 50 -> 46; koin/okhttp/moshi/ nowinandroid/okio unchanged, none newly broken; kernel parity 0 diffs. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
81 lines
2.4 KiB
TypeScript
81 lines
2.4 KiB
TypeScript
/**
|
|
* Kotlin syntax newer than the vendored grammar — `when` guards (2.1), `..<`
|
|
* ranges (1.9), multi-dollar strings (2.1), nullable function-type
|
|
* receivers — is rewritten to an older equivalent of the same length before
|
|
* the parse; otherwise error recovery dropped the class around it (Exposed's
|
|
* dialect classes came out as loose functions).
|
|
*/
|
|
import { describe, it, expect, afterAll, beforeAll } from 'vitest';
|
|
import * as fs from 'fs';
|
|
import * as os from 'os';
|
|
import * as path from 'path';
|
|
import { CodeGraph } from '../src';
|
|
import { rewriteNewerKotlinSyntax } from '../src/extraction/languages/kotlin';
|
|
|
|
const SOURCE = `package app
|
|
|
|
class Dialect(private val mode: Int) {
|
|
fun sql(value: Any?): String = when (value) {
|
|
is String if mode == 2 -> "text"
|
|
is Int if (
|
|
mode > 0
|
|
) -> "int"
|
|
is Long -> if (mode == 1) "long" else "big"
|
|
else -> "other"
|
|
}
|
|
|
|
fun ranges(n: Int) {
|
|
for (i in 0..<n) println(i)
|
|
}
|
|
|
|
fun path(team: String) = $$"?(@.user.team == $team)"
|
|
|
|
fun adjust(body: Op<Boolean>?.() -> Op<Boolean>): Dialect = this
|
|
|
|
fun after(): Int = 1
|
|
}
|
|
|
|
class Op<T>
|
|
`;
|
|
|
|
let root = '';
|
|
let cg: CodeGraph;
|
|
|
|
beforeAll(async () => {
|
|
root = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-kotlin-newer-'));
|
|
fs.mkdirSync(path.join(root, 'src'), { recursive: true });
|
|
fs.writeFileSync(path.join(root, 'src/Dialect.kt'), SOURCE);
|
|
cg = await CodeGraph.init(root, { index: true });
|
|
});
|
|
|
|
afterAll(() => {
|
|
cg?.close();
|
|
if (root) fs.rmSync(root, { recursive: true, force: true });
|
|
});
|
|
|
|
describe('newer Kotlin syntax', () => {
|
|
it('is rewritten with every offset intact', () => {
|
|
const out = rewriteNewerKotlinSyntax(SOURCE);
|
|
expect(out.length).toBe(SOURCE.length);
|
|
expect(out).toContain('is String, mode == 2 ->');
|
|
expect(out).toContain('is Long -> if (mode == 1)');
|
|
expect(out).toContain('0.. n');
|
|
expect(out).toContain(' "?(@.user.team == $team)"');
|
|
expect(out).toContain('Op<Boolean>.( ) -> Op<Boolean>');
|
|
});
|
|
|
|
it('keeps the class around it and every method', () => {
|
|
const methods = cg.getNodesInFile('src/Dialect.kt')
|
|
.filter((n) => n.kind === 'method')
|
|
.map((n) => n.qualifiedName)
|
|
.sort();
|
|
expect(methods).toEqual([
|
|
'app::Dialect::adjust',
|
|
'app::Dialect::after',
|
|
'app::Dialect::path',
|
|
'app::Dialect::ranges',
|
|
'app::Dialect::sql',
|
|
]);
|
|
});
|
|
});
|