@opensip-cli/lang-rust 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +31 -0
- package/dist/__tests__/adapter.test.d.ts +2 -0
- package/dist/__tests__/adapter.test.d.ts.map +1 -0
- package/dist/__tests__/adapter.test.js +97 -0
- package/dist/__tests__/adapter.test.js.map +1 -0
- package/dist/__tests__/index.test.d.ts +9 -0
- package/dist/__tests__/index.test.d.ts.map +1 -0
- package/dist/__tests__/index.test.js +27 -0
- package/dist/__tests__/index.test.js.map +1 -0
- package/dist/__tests__/strip.test.d.ts +15 -0
- package/dist/__tests__/strip.test.d.ts.map +1 -0
- package/dist/__tests__/strip.test.js +183 -0
- package/dist/__tests__/strip.test.js.map +1 -0
- package/dist/__tests__/substrate.test.d.ts +2 -0
- package/dist/__tests__/substrate.test.d.ts.map +1 -0
- package/dist/__tests__/substrate.test.js +79 -0
- package/dist/__tests__/substrate.test.js.map +1 -0
- package/dist/adapter.d.ts +6 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +13 -0
- package/dist/adapter.js.map +1 -0
- package/dist/enclosing.d.ts +16 -0
- package/dist/enclosing.d.ts.map +1 -0
- package/dist/enclosing.js +28 -0
- package/dist/enclosing.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/parse.d.ts +17 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +21 -0
- package/dist/parse.js.map +1 -0
- package/dist/predicates.d.ts +24 -0
- package/dist/predicates.d.ts.map +1 -0
- package/dist/predicates.js +26 -0
- package/dist/predicates.js.map +1 -0
- package/dist/shared-tree.d.ts +10 -0
- package/dist/shared-tree.d.ts.map +1 -0
- package/dist/shared-tree.js +14 -0
- package/dist/shared-tree.js.map +1 -0
- package/dist/strip.d.ts +5 -0
- package/dist/strip.d.ts.map +1 -0
- package/dist/strip.js +157 -0
- package/dist/strip.js.map +1 -0
- package/package.json +50 -0
- package/wasm/tree-sitter-rust.wasm +0 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { RunScope, runWithScopeSync } from '@opensip-cli/core';
|
|
2
|
+
import { initParseCache, clearParseCache } from '@opensip-cli/core/languages/parse-cache.js';
|
|
3
|
+
import { nameOf, walkNodes } from '@opensip-cli/tree-sitter';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { findEnclosingFunction, getEnclosingFunctionName, isMethod } from '../enclosing.js';
|
|
6
|
+
import { parseRust } from '../parse.js';
|
|
7
|
+
import { isComment, isConditional, isFunction, isImpl, isLoop, isString, isStruct, } from '../predicates.js';
|
|
8
|
+
import { getSharedTree } from '../shared-tree.js';
|
|
9
|
+
const SRC = [
|
|
10
|
+
'// c',
|
|
11
|
+
'struct S { x: i32 }',
|
|
12
|
+
'impl S {',
|
|
13
|
+
' fn m(&self) -> i32 {',
|
|
14
|
+
' let s = "h";',
|
|
15
|
+
' if true { return 1; }',
|
|
16
|
+
' for _i in 0..3 {}',
|
|
17
|
+
' 2',
|
|
18
|
+
' }',
|
|
19
|
+
'}',
|
|
20
|
+
'fn free() -> i32 { 0 }',
|
|
21
|
+
'',
|
|
22
|
+
].join('\n');
|
|
23
|
+
function root() {
|
|
24
|
+
const tree = parseRust(SRC, 's.rs');
|
|
25
|
+
if (!tree)
|
|
26
|
+
throw new Error('no tree');
|
|
27
|
+
return tree.tree.rootNode;
|
|
28
|
+
}
|
|
29
|
+
function count(pred) {
|
|
30
|
+
let n = 0;
|
|
31
|
+
walkNodes(root(), (node) => {
|
|
32
|
+
if (pred(node))
|
|
33
|
+
n++;
|
|
34
|
+
});
|
|
35
|
+
return n;
|
|
36
|
+
}
|
|
37
|
+
describe('rust substrate', () => {
|
|
38
|
+
it('predicates match the tree-sitter-rust node types', () => {
|
|
39
|
+
expect(count(isFunction)).toBe(2);
|
|
40
|
+
expect(count(isStruct)).toBe(1);
|
|
41
|
+
expect(count(isImpl)).toBe(1);
|
|
42
|
+
expect(count(isComment)).toBe(1);
|
|
43
|
+
expect(count(isString)).toBeGreaterThanOrEqual(1);
|
|
44
|
+
expect(count(isConditional)).toBe(1);
|
|
45
|
+
expect(count(isLoop)).toBe(1);
|
|
46
|
+
});
|
|
47
|
+
it('isMethod: a fn in an impl is true, a free fn is false', () => {
|
|
48
|
+
const seen = [];
|
|
49
|
+
walkNodes(root(), (n) => {
|
|
50
|
+
if (isFunction(n))
|
|
51
|
+
seen.push({ name: nameOf(n), method: isMethod(n) });
|
|
52
|
+
});
|
|
53
|
+
expect(seen).toContainEqual({ name: 'm', method: true });
|
|
54
|
+
expect(seen).toContainEqual({ name: 'free', method: false });
|
|
55
|
+
});
|
|
56
|
+
it('getSharedTree caches within an active parse cache', () => {
|
|
57
|
+
runWithScopeSync(new RunScope(), () => {
|
|
58
|
+
initParseCache();
|
|
59
|
+
try {
|
|
60
|
+
const a = getSharedTree('x.rs', 'fn x() {}');
|
|
61
|
+
const b = getSharedTree('x.rs', 'fn x() {}');
|
|
62
|
+
expect(a).toBe(b);
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
clearParseCache();
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
it('findEnclosingFunction resolves the nearest fn', () => {
|
|
70
|
+
const strings = [];
|
|
71
|
+
walkNodes(root(), (n) => {
|
|
72
|
+
if (n.type === 'string_literal')
|
|
73
|
+
strings.push(n);
|
|
74
|
+
});
|
|
75
|
+
expect(getEnclosingFunctionName(strings[0])).toBe('m');
|
|
76
|
+
expect(findEnclosingFunction(strings[0])?.type).toBe('function_item');
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
//# sourceMappingURL=substrate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"substrate.test.js","sourceRoot":"","sources":["../../src/__tests__/substrate.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type RustTree } from './parse.js';
|
|
2
|
+
import type { LanguageAdapter } from '@opensip-cli/core';
|
|
3
|
+
export declare const rustAdapter: LanguageAdapter<RustTree>;
|
|
4
|
+
/** Plugin contract — exported as the lang plugin's `adapters` array. */
|
|
5
|
+
export declare const adapters: readonly [LanguageAdapter<import("@opensip-cli/tree-sitter").ParsedFile, unknown>];
|
|
6
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,eAAO,MAAM,WAAW,EAAE,eAAe,CAAC,QAAQ,CAOjD,CAAC;AAEF,wEAAwE;AACxE,eAAO,MAAM,QAAQ,oFAAyB,CAAC"}
|
package/dist/adapter.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { parseRust } from './parse.js';
|
|
2
|
+
import { stripComments, stripStrings } from './strip.js';
|
|
3
|
+
export const rustAdapter = {
|
|
4
|
+
id: 'rust',
|
|
5
|
+
fileExtensions: ['.rs'],
|
|
6
|
+
aliases: ['rs'],
|
|
7
|
+
parse: parseRust,
|
|
8
|
+
stripStrings,
|
|
9
|
+
stripComments,
|
|
10
|
+
};
|
|
11
|
+
/** Plugin contract — exported as the lang plugin's `adapters` array. */
|
|
12
|
+
export const adapters = [rustAdapter];
|
|
13
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAiB,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAIzD,MAAM,CAAC,MAAM,WAAW,GAA8B;IACpD,EAAE,EAAE,MAAM;IACV,cAAc,EAAE,CAAC,KAAK,CAAC;IACvB,OAAO,EAAE,CAAC,IAAI,CAAC;IACf,KAAK,EAAE,SAAS;IAChB,YAAY;IACZ,aAAa;CACd,CAAC;AAEF,wEAAwE;AACxE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,WAAW,CAAU,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composed enclosing-scope helpers for Rust (ADR-0010) — the per-language layer
|
|
3
|
+
* over the generic `findEnclosing`/`nameOf` from `@opensip-cli/tree-sitter`.
|
|
4
|
+
*/
|
|
5
|
+
import { type Node } from '@opensip-cli/tree-sitter';
|
|
6
|
+
/** The nearest enclosing `fn` of `node`, or `null` at module scope. */
|
|
7
|
+
export declare function findEnclosingFunction(node: Node): Node | null;
|
|
8
|
+
/** The name of the nearest enclosing `fn`, or `null`. */
|
|
9
|
+
export declare function getEnclosingFunctionName(node: Node): string | null;
|
|
10
|
+
/**
|
|
11
|
+
* True when `node` is a method — a `fn` item whose nearest enclosing
|
|
12
|
+
* function-or-impl is an `impl` block. A free function (or a `fn` nested in
|
|
13
|
+
* another `fn`) is therefore not a method.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isMethod(node: Node): boolean;
|
|
16
|
+
//# sourceMappingURL=enclosing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enclosing.d.ts","sourceRoot":"","sources":["../src/enclosing.ts"],"names":[],"mappings":"AACA;;;GAGG;AAEH,OAAO,EAAyB,KAAK,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAI5E,uEAAuE;AACvE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAE7D;AAED,yDAAyD;AACzD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAGlE;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAI5C"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// @fitness-ignore-file duplicate-utility-functions -- ADR-0010: the per-language tree-sitter vocabulary intentionally shares helper names across lang-* with grammar-specific implementations; consolidating would defeat the substrate design.
|
|
2
|
+
/**
|
|
3
|
+
* Composed enclosing-scope helpers for Rust (ADR-0010) — the per-language layer
|
|
4
|
+
* over the generic `findEnclosing`/`nameOf` from `@opensip-cli/tree-sitter`.
|
|
5
|
+
*/
|
|
6
|
+
import { findEnclosing, nameOf } from '@opensip-cli/tree-sitter';
|
|
7
|
+
import { isFunction, isImpl } from './predicates.js';
|
|
8
|
+
/** The nearest enclosing `fn` of `node`, or `null` at module scope. */
|
|
9
|
+
export function findEnclosingFunction(node) {
|
|
10
|
+
return findEnclosing(node, isFunction);
|
|
11
|
+
}
|
|
12
|
+
/** The name of the nearest enclosing `fn`, or `null`. */
|
|
13
|
+
export function getEnclosingFunctionName(node) {
|
|
14
|
+
const fn = findEnclosingFunction(node);
|
|
15
|
+
return fn ? nameOf(fn) : null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* True when `node` is a method — a `fn` item whose nearest enclosing
|
|
19
|
+
* function-or-impl is an `impl` block. A free function (or a `fn` nested in
|
|
20
|
+
* another `fn`) is therefore not a method.
|
|
21
|
+
*/
|
|
22
|
+
export function isMethod(node) {
|
|
23
|
+
if (!isFunction(node))
|
|
24
|
+
return false;
|
|
25
|
+
const enclosing = findEnclosing(node, (n) => isFunction(n) || isImpl(n));
|
|
26
|
+
return enclosing !== null && isImpl(enclosing);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=enclosing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enclosing.js","sourceRoot":"","sources":["../src/enclosing.ts"],"names":[],"mappings":"AAAA,gPAAgP;AAChP;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,EAAa,MAAM,0BAA0B,CAAC;AAE5E,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAErD,uEAAuE;AACvE,MAAM,UAAU,qBAAqB,CAAC,IAAU;IAC9C,OAAO,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;AACzC,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,wBAAwB,CAAC,IAAU;IACjD,MAAM,EAAE,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAU;IACjC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,OAAO,SAAS,KAAK,IAAI,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC;AACjD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { rustAdapter, adapters } from './adapter.js';
|
|
2
|
+
export { parseRust, type RustTree } from './parse.js';
|
|
3
|
+
export { getSharedTree } from './shared-tree.js';
|
|
4
|
+
export { stripStrings, stripComments } from './strip.js';
|
|
5
|
+
export { isFunction, isStruct, isImpl, isComment, isString, isConditional, isLoop, } from './predicates.js';
|
|
6
|
+
export { findEnclosingFunction, getEnclosingFunctionName, isMethod } from './enclosing.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EACL,UAAU,EACV,QAAQ,EACR,MAAM,EACN,SAAS,EACT,QAAQ,EACR,aAAa,EACb,MAAM,GACP,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { rustAdapter, adapters } from './adapter.js';
|
|
2
|
+
export { parseRust } from './parse.js';
|
|
3
|
+
export { getSharedTree } from './shared-tree.js';
|
|
4
|
+
export { stripStrings, stripComments } from './strip.js';
|
|
5
|
+
export { isFunction, isStruct, isImpl, isComment, isString, isConditional, isLoop, } from './predicates.js';
|
|
6
|
+
export { findEnclosingFunction, getEnclosingFunctionName, isMethod } from './enclosing.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,SAAS,EAAiB,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EACL,UAAU,EACV,QAAQ,EACR,MAAM,EACN,SAAS,EACT,QAAQ,EACR,aAAa,EACb,MAAM,GACP,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/parse.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Rust parse — web-tree-sitter + vendored tree-sitter-rust.wasm.
|
|
3
|
+
*
|
|
4
|
+
* ADR-0010: `lang-rust` is the canonical Rust parse substrate — fitness checks
|
|
5
|
+
* parse via the adapter (`getSharedTree`) and the graph Rust adapter consumes
|
|
6
|
+
* this too. The grammar loads once at module top level (the WASM runtime is
|
|
7
|
+
* initialized by `@opensip-cli/tree-sitter`'s top-level `Parser.init()`); a
|
|
8
|
+
* single reused parser keeps `parse()` synchronous. Tree-sitter recovers from
|
|
9
|
+
* syntax errors with MISSING nodes, so a malformed file yields a partial tree
|
|
10
|
+
* (non-null) rather than throwing.
|
|
11
|
+
*/
|
|
12
|
+
import { type ParsedFile } from '@opensip-cli/tree-sitter';
|
|
13
|
+
/** Parsed Rust source: tree-sitter parse tree plus the original source text. */
|
|
14
|
+
export type RustTree = ParsedFile;
|
|
15
|
+
/** Parses Rust source into a {@link RustTree}, or null when no tree is produced. */
|
|
16
|
+
export declare function parseRust(content: string, _filePath: string): RustTree | null;
|
|
17
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAA0C,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAOnG,gFAAgF;AAChF,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAC;AAElC,oFAAoF;AACpF,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAG7E"}
|
package/dist/parse.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Rust parse — web-tree-sitter + vendored tree-sitter-rust.wasm.
|
|
3
|
+
*
|
|
4
|
+
* ADR-0010: `lang-rust` is the canonical Rust parse substrate — fitness checks
|
|
5
|
+
* parse via the adapter (`getSharedTree`) and the graph Rust adapter consumes
|
|
6
|
+
* this too. The grammar loads once at module top level (the WASM runtime is
|
|
7
|
+
* initialized by `@opensip-cli/tree-sitter`'s top-level `Parser.init()`); a
|
|
8
|
+
* single reused parser keeps `parse()` synchronous. Tree-sitter recovers from
|
|
9
|
+
* syntax errors with MISSING nodes, so a malformed file yields a partial tree
|
|
10
|
+
* (non-null) rather than throwing.
|
|
11
|
+
*/
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
import { loadGrammar, createParser, parseToTree } from '@opensip-cli/tree-sitter';
|
|
14
|
+
const grammar = await loadGrammar(fileURLToPath(new URL('../wasm/tree-sitter-rust.wasm', import.meta.url)));
|
|
15
|
+
const parser = createParser(grammar);
|
|
16
|
+
/** Parses Rust source into a {@link RustTree}, or null when no tree is produced. */
|
|
17
|
+
export function parseRust(content, _filePath) {
|
|
18
|
+
const tree = parseToTree(parser, content);
|
|
19
|
+
return tree ? { tree, source: content } : null;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAmB,MAAM,0BAA0B,CAAC;AAEnG,MAAM,OAAO,GAAG,MAAM,WAAW,CAC/B,aAAa,CAAC,IAAI,GAAG,CAAC,+BAA+B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CACzE,CAAC;AACF,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;AAKrC,oFAAoF;AACpF,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,SAAiB;IAC1D,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1 per-language node-kind predicates for Rust (ADR-0010). The generic
|
|
3
|
+
* traversal/position helpers live in `@opensip-cli/tree-sitter`; only the
|
|
4
|
+
* grammar-specific node `type` strings differ per language. Node types are from
|
|
5
|
+
* the tree-sitter-rust grammar. Rust has no class or try/catch — methods are
|
|
6
|
+
* `fn` items inside an `impl` block (see `isMethod` in enclosing.ts), and error
|
|
7
|
+
* handling is `Result`/`?` rather than exceptions.
|
|
8
|
+
*/
|
|
9
|
+
import type { Node } from '@opensip-cli/tree-sitter';
|
|
10
|
+
/** A `fn` item — free functions and methods are both `function_item`. */
|
|
11
|
+
export declare const isFunction: (node: Node) => boolean;
|
|
12
|
+
/** A `struct` declaration. */
|
|
13
|
+
export declare const isStruct: (node: Node) => boolean;
|
|
14
|
+
/** An `impl` block. */
|
|
15
|
+
export declare const isImpl: (node: Node) => boolean;
|
|
16
|
+
/** A line comment or a block comment. */
|
|
17
|
+
export declare const isComment: (node: Node) => boolean;
|
|
18
|
+
/** A string literal. */
|
|
19
|
+
export declare const isString: (node: Node) => boolean;
|
|
20
|
+
/** An `if` expression. */
|
|
21
|
+
export declare const isConditional: (node: Node) => boolean;
|
|
22
|
+
/** A `for`, `while`, or `loop` expression. */
|
|
23
|
+
export declare const isLoop: (node: Node) => boolean;
|
|
24
|
+
//# sourceMappingURL=predicates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predicates.d.ts","sourceRoot":"","sources":["../src/predicates.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAErD,yEAAyE;AACzE,eAAO,MAAM,UAAU,GAAI,MAAM,IAAI,KAAG,OAAwC,CAAC;AAEjF,8BAA8B;AAC9B,eAAO,MAAM,QAAQ,GAAI,MAAM,IAAI,KAAG,OAAsC,CAAC;AAE7E,uBAAuB;AACvB,eAAO,MAAM,MAAM,GAAI,MAAM,IAAI,KAAG,OAAoC,CAAC;AAEzE,yCAAyC;AACzC,eAAO,MAAM,SAAS,GAAI,MAAM,IAAI,KAAG,OACwB,CAAC;AAEhE,wBAAwB;AACxB,eAAO,MAAM,QAAQ,GAAI,MAAM,IAAI,KAAG,OAAyC,CAAC;AAEhF,0BAA0B;AAC1B,eAAO,MAAM,aAAa,GAAI,MAAM,IAAI,KAAG,OAAwC,CAAC;AAEpF,8CAA8C;AAC9C,eAAO,MAAM,MAAM,GAAI,MAAM,IAAI,KAAG,OAGH,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// @fitness-ignore-file duplicate-utility-functions -- ADR-0010: the per-language tree-sitter vocabulary intentionally shares helper names across lang-* with grammar-specific implementations; consolidating would defeat the substrate design.
|
|
2
|
+
/**
|
|
3
|
+
* v1 per-language node-kind predicates for Rust (ADR-0010). The generic
|
|
4
|
+
* traversal/position helpers live in `@opensip-cli/tree-sitter`; only the
|
|
5
|
+
* grammar-specific node `type` strings differ per language. Node types are from
|
|
6
|
+
* the tree-sitter-rust grammar. Rust has no class or try/catch — methods are
|
|
7
|
+
* `fn` items inside an `impl` block (see `isMethod` in enclosing.ts), and error
|
|
8
|
+
* handling is `Result`/`?` rather than exceptions.
|
|
9
|
+
*/
|
|
10
|
+
/** A `fn` item — free functions and methods are both `function_item`. */
|
|
11
|
+
export const isFunction = (node) => node.type === 'function_item';
|
|
12
|
+
/** A `struct` declaration. */
|
|
13
|
+
export const isStruct = (node) => node.type === 'struct_item';
|
|
14
|
+
/** An `impl` block. */
|
|
15
|
+
export const isImpl = (node) => node.type === 'impl_item';
|
|
16
|
+
/** A line comment or a block comment. */
|
|
17
|
+
export const isComment = (node) => node.type === 'line_comment' || node.type === 'block_comment';
|
|
18
|
+
/** A string literal. */
|
|
19
|
+
export const isString = (node) => node.type === 'string_literal';
|
|
20
|
+
/** An `if` expression. */
|
|
21
|
+
export const isConditional = (node) => node.type === 'if_expression';
|
|
22
|
+
/** A `for`, `while`, or `loop` expression. */
|
|
23
|
+
export const isLoop = (node) => node.type === 'for_expression' ||
|
|
24
|
+
node.type === 'while_expression' ||
|
|
25
|
+
node.type === 'loop_expression';
|
|
26
|
+
//# sourceMappingURL=predicates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predicates.js","sourceRoot":"","sources":["../src/predicates.ts"],"names":[],"mappings":"AAAA,gPAAgP;AAChP;;;;;;;GAOG;AAIH,yEAAyE;AACzE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAU,EAAW,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe,CAAC;AAEjF,8BAA8B;AAC9B,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAU,EAAW,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,aAAa,CAAC;AAE7E,uBAAuB;AACvB,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,IAAU,EAAW,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AAEzE,yCAAyC;AACzC,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAU,EAAW,EAAE,CAC/C,IAAI,CAAC,IAAI,KAAK,cAAc,IAAI,IAAI,CAAC,IAAI,KAAK,eAAe,CAAC;AAEhE,wBAAwB;AACxB,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAU,EAAW,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,gBAAgB,CAAC;AAEhF,0BAA0B;AAC1B,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAU,EAAW,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe,CAAC;AAEpF,8CAA8C;AAC9C,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,IAAU,EAAW,EAAE,CAC5C,IAAI,CAAC,IAAI,KAAK,gBAAgB;IAC9B,IAAI,CAAC,IAAI,KAAK,kBAAkB;IAChC,IAAI,CAAC,IAAI,KAAK,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cached Rust parse entry point — the analog of `lang-typescript`'s
|
|
3
|
+
* `getSharedSourceFile`. Routes through `core`'s active `LanguageParseCache`
|
|
4
|
+
* so a file parsed by a fitness check and by the graph adapter in the same run
|
|
5
|
+
* is parsed once; falls back to a direct parse when no cache is active.
|
|
6
|
+
*/
|
|
7
|
+
import type { RustTree } from './parse.js';
|
|
8
|
+
/** Returns the shared (cached) Rust parse tree for `filePath`, or null when unparseable. */
|
|
9
|
+
export declare function getSharedTree(filePath: string, content: string): RustTree | null;
|
|
10
|
+
//# sourceMappingURL=shared-tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-tree.d.ts","sourceRoot":"","sources":["../src/shared-tree.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,4FAA4F;AAC5F,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAEhF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @fitness-ignore-file duplicate-utility-functions -- ADR-0010: the per-language tree-sitter vocabulary intentionally shares helper names across lang-* with grammar-specific implementations; consolidating would defeat the substrate design.
|
|
2
|
+
/**
|
|
3
|
+
* Cached Rust parse entry point — the analog of `lang-typescript`'s
|
|
4
|
+
* `getSharedSourceFile`. Routes through `core`'s active `LanguageParseCache`
|
|
5
|
+
* so a file parsed by a fitness check and by the graph adapter in the same run
|
|
6
|
+
* is parsed once; falls back to a direct parse when no cache is active.
|
|
7
|
+
*/
|
|
8
|
+
import { getParseTree } from '@opensip-cli/core/languages/parse-cache.js';
|
|
9
|
+
import { rustAdapter } from './adapter.js';
|
|
10
|
+
/** Returns the shared (cached) Rust parse tree for `filePath`, or null when unparseable. */
|
|
11
|
+
export function getSharedTree(filePath, content) {
|
|
12
|
+
return getParseTree(rustAdapter, filePath, content);
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=shared-tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared-tree.js","sourceRoot":"","sources":["../src/shared-tree.ts"],"names":[],"mappings":"AAAA,gPAAgP;AAChP;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAC;AAE1E,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAI3C,4FAA4F;AAC5F,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,OAAe;IAC7D,OAAO,YAAY,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AACtD,CAAC"}
|
package/dist/strip.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Replace string literal content with whitespace; preserves length. */
|
|
2
|
+
export declare const stripStrings: (content: string) => string;
|
|
3
|
+
/** Replace string literals AND comments with whitespace; preserves length. */
|
|
4
|
+
export declare const stripComments: (content: string) => string;
|
|
5
|
+
//# sourceMappingURL=strip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strip.d.ts","sourceRoot":"","sources":["../src/strip.ts"],"names":[],"mappings":"AA2KA,wEAAwE;AACxE,eAAO,MAAM,YAAY,6BAAwB,CAAC;AAClD,8EAA8E;AAC9E,eAAO,MAAM,aAAa,6BAAyB,CAAC"}
|
package/dist/strip.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// Rust string and comment stripping.
|
|
2
|
+
//
|
|
3
|
+
// Hand-written lexer that recognizes:
|
|
4
|
+
// - Line comments (//) and nested block comments (slash-star ... star-slash)
|
|
5
|
+
// - Regular strings ("...") with escape handling — Rust regular strings
|
|
6
|
+
// may span multiple lines (unlike Java/Go/C++), so we pass
|
|
7
|
+
// `allowMultiline: true` to core's shared scanner.
|
|
8
|
+
// - Raw strings (r"...", r#"..."#, ..., r####"..."####)
|
|
9
|
+
// - Byte strings (b"...") and byte-raw strings (br#"..."#) — note that
|
|
10
|
+
// byte-string content is treated as opaque bytes; this layer does NOT
|
|
11
|
+
// enforce the ASCII-only / valid-escape rules of `b"..."`. A future
|
|
12
|
+
// check that wants to flag invalid byte literals will have to layer
|
|
13
|
+
// that validation on top of the region scan.
|
|
14
|
+
// - Char literals ('a', '\n', '\u{1234}') — preserved as-is, with the
|
|
15
|
+
// lifetime-vs-literal disambiguation done at the call site here.
|
|
16
|
+
//
|
|
17
|
+
// Both strip functions preserve byte length: replacement is whitespace
|
|
18
|
+
// (newlines preserved) so line/column positions remain stable.
|
|
19
|
+
import { makeStripper, scanBlockCommentNesting, scanLineComment, scanRegularString, } from '@opensip-cli/core';
|
|
20
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity -- token-state-machine: cyclomatic complexity is inherent to lexer-style scanners; splitting hurts readability
|
|
21
|
+
function scan(src) {
|
|
22
|
+
const stringRegions = [];
|
|
23
|
+
const commentRegions = [];
|
|
24
|
+
const len = src.length;
|
|
25
|
+
let i = 0;
|
|
26
|
+
while (i < len) {
|
|
27
|
+
const c = src[i];
|
|
28
|
+
const next = src[i + 1];
|
|
29
|
+
// Line comment: // ... \n
|
|
30
|
+
if (c === '/' && next === '/') {
|
|
31
|
+
const start = i;
|
|
32
|
+
const lc = scanLineComment(src, i);
|
|
33
|
+
i = lc.end;
|
|
34
|
+
commentRegions.push({ start, end: i });
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
// Block comment: /* ... */ with nesting
|
|
38
|
+
if (c === '/' && next === '*') {
|
|
39
|
+
const start = i;
|
|
40
|
+
const bc = scanBlockCommentNesting(src, i);
|
|
41
|
+
i = bc.end;
|
|
42
|
+
commentRegions.push({ start, end: i });
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
// Raw string: r"..." or r#"..."# or r##"..."## (any number of #)
|
|
46
|
+
// Byte-raw string: br"..." or br#"..."#
|
|
47
|
+
if ((c === 'r' && (next === '"' || next === '#')) ||
|
|
48
|
+
(c === 'b' && src[i + 1] === 'r' && (src[i + 2] === '"' || src[i + 2] === '#'))) {
|
|
49
|
+
const prefixLen = c === 'b' ? 2 : 1; // br vs r
|
|
50
|
+
let j = i + prefixLen;
|
|
51
|
+
let hashes = 0;
|
|
52
|
+
while (j < len && src[j] === '#') {
|
|
53
|
+
hashes++;
|
|
54
|
+
j++;
|
|
55
|
+
}
|
|
56
|
+
if (j < len && src[j] === '"') {
|
|
57
|
+
const contentStart = j + 1;
|
|
58
|
+
j++;
|
|
59
|
+
// Find closing " followed by `hashes` # characters
|
|
60
|
+
while (j < len) {
|
|
61
|
+
if (src[j] === '"') {
|
|
62
|
+
let k = 0;
|
|
63
|
+
while (k < hashes && src[j + 1 + k] === '#')
|
|
64
|
+
k++;
|
|
65
|
+
if (k === hashes) {
|
|
66
|
+
const contentEnd = j;
|
|
67
|
+
stringRegions.push({ start: contentStart, end: contentEnd });
|
|
68
|
+
j += 1 + hashes;
|
|
69
|
+
i = j;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
j++;
|
|
74
|
+
}
|
|
75
|
+
if (j >= len) {
|
|
76
|
+
// Unterminated raw string — record what we have
|
|
77
|
+
stringRegions.push({ start: contentStart, end: len });
|
|
78
|
+
i = len;
|
|
79
|
+
}
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
// Not actually a raw string (e.g. `r` is just an identifier)
|
|
83
|
+
i++;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
// Byte string: b"..." — Rust strings may span multiple lines.
|
|
87
|
+
if (c === 'b' && next === '"') {
|
|
88
|
+
i++;
|
|
89
|
+
const result = scanRegularString(src, i, { allowMultiline: true });
|
|
90
|
+
stringRegions.push({ start: i + 1, end: result.contentEnd });
|
|
91
|
+
i = result.next;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
// Regular string: "..." — Rust strings may span multiple lines.
|
|
95
|
+
if (c === '"') {
|
|
96
|
+
const result = scanRegularString(src, i, { allowMultiline: true });
|
|
97
|
+
stringRegions.push({ start: i + 1, end: result.contentEnd });
|
|
98
|
+
i = result.next;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
// Char literal: '...' — skip without recording (char literals are single chars)
|
|
102
|
+
// Use a heuristic: if we see ' followed by content that closes within ~6 chars, treat as char.
|
|
103
|
+
// Otherwise it's a lifetime annotation ('a, 'static, etc.).
|
|
104
|
+
if (c === "'") {
|
|
105
|
+
// Lifetime: 'identifier (no closing quote)
|
|
106
|
+
const after = src[i + 1];
|
|
107
|
+
if (after === undefined) {
|
|
108
|
+
i++;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
// Look ahead to see if there's a closing quote within ~8 chars.
|
|
112
|
+
// (Same heuristic the previous inline scanner used.) Core's
|
|
113
|
+
// scanCharLiteral helper *does* distinguish overflow from success
|
|
114
|
+
// (overflow returns `end === start + 1`, success returns
|
|
115
|
+
// `end > start + 1`), so a migration to that helper with a
|
|
116
|
+
// `result.end === i + 1` lifetime branch is feasible. We keep
|
|
117
|
+
// this look-ahead inline because it makes the lifetime branch
|
|
118
|
+
// decision local to the lexer state machine and the explicit
|
|
119
|
+
// `escape`/`foundClose` variables are easier to follow for the
|
|
120
|
+
// Rust-specific edge cases the test suite exercises.
|
|
121
|
+
const maxScan = Math.min(i + 8, len);
|
|
122
|
+
let foundClose = -1;
|
|
123
|
+
let escape = false;
|
|
124
|
+
for (let k = i + 1; k < maxScan; k++) {
|
|
125
|
+
if (escape) {
|
|
126
|
+
escape = false;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (src[k] === '\\') {
|
|
130
|
+
escape = true;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (src[k] === "'") {
|
|
134
|
+
foundClose = k;
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (foundClose >= 0) {
|
|
139
|
+
// Char literal — preserve as code (don't strip)
|
|
140
|
+
i = foundClose + 1;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
// Lifetime — skip the apostrophe and continue
|
|
144
|
+
i++;
|
|
145
|
+
}
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
i++;
|
|
149
|
+
}
|
|
150
|
+
return { stringRegions, commentRegions };
|
|
151
|
+
}
|
|
152
|
+
const stripper = makeStripper(scan);
|
|
153
|
+
/** Replace string literal content with whitespace; preserves length. */
|
|
154
|
+
export const stripStrings = stripper.stripStrings;
|
|
155
|
+
/** Replace string literals AND comments with whitespace; preserves length. */
|
|
156
|
+
export const stripComments = stripper.stripComments;
|
|
157
|
+
//# sourceMappingURL=strip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strip.js","sourceRoot":"","sources":["../src/strip.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@opensip-cli/lang-rust",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "Apache-2.0",
|
|
5
|
+
"description": "Rust language adapter for opensip-cli",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"opensip-cli",
|
|
8
|
+
"static-analysis",
|
|
9
|
+
"code-quality",
|
|
10
|
+
"parser",
|
|
11
|
+
"ast",
|
|
12
|
+
"tree-sitter",
|
|
13
|
+
"rust"
|
|
14
|
+
],
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/opensip-ai/opensip-cli.git",
|
|
18
|
+
"directory": "packages/languages/lang-rust"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/opensip-ai/opensip-cli",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/opensip-ai/opensip-cli/issues"
|
|
23
|
+
},
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": "./dist/index.js"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"wasm",
|
|
33
|
+
"LICENSE",
|
|
34
|
+
"NOTICE"
|
|
35
|
+
],
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@opensip-cli/core": "0.1.0",
|
|
38
|
+
"@opensip-cli/tree-sitter": "0.1.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^24.13.2",
|
|
42
|
+
"vitest": "^4.1.8"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc",
|
|
46
|
+
"test": "vitest run --passWithNoTests",
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"clean": "rm -rf dist"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
Binary file
|