@opensip-cli/lang-python 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 +251 -0
- package/dist/__tests__/adapter.test.js.map +1 -0
- package/dist/__tests__/enclosing.test.d.ts +2 -0
- package/dist/__tests__/enclosing.test.d.ts.map +1 -0
- package/dist/__tests__/enclosing.test.js +42 -0
- package/dist/__tests__/enclosing.test.js.map +1 -0
- package/dist/__tests__/predicates.test.d.ts +2 -0
- package/dist/__tests__/predicates.test.d.ts.map +1 -0
- package/dist/__tests__/predicates.test.js +44 -0
- package/dist/__tests__/predicates.test.js.map +1 -0
- package/dist/__tests__/strip.test.d.ts +2 -0
- package/dist/__tests__/strip.test.d.ts.map +1 -0
- package/dist/__tests__/strip.test.js +77 -0
- package/dist/__tests__/strip.test.js.map +1 -0
- package/dist/__tests__/tree.test.d.ts +2 -0
- package/dist/__tests__/tree.test.d.ts.map +1 -0
- package/dist/__tests__/tree.test.js +36 -0
- package/dist/__tests__/tree.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 +18 -0
- package/dist/enclosing.d.ts.map +1 -0
- package/dist/enclosing.js +30 -0
- package/dist/enclosing.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/parse.d.ts +18 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +22 -0
- package/dist/parse.js.map +1 -0
- package/dist/predicates.d.ts +22 -0
- package/dist/predicates.d.ts.map +1 -0
- package/dist/predicates.js +22 -0
- package/dist/predicates.js.map +1 -0
- package/dist/shared-tree.d.ts +11 -0
- package/dist/shared-tree.d.ts.map +1 -0
- package/dist/shared-tree.js +15 -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 +196 -0
- package/dist/strip.js.map +1 -0
- package/package.json +50 -0
- package/wasm/tree-sitter-python.wasm +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { stripStrings, stripComments } from '../strip.js';
|
|
3
|
+
describe('stripStrings', () => {
|
|
4
|
+
it('strips single-quoted string contents (replacing with whitespace)', () => {
|
|
5
|
+
const out = stripStrings(`x = 'hello'`);
|
|
6
|
+
expect(out).not.toContain('hello');
|
|
7
|
+
expect(out.startsWith(`x = '`)).toBe(true);
|
|
8
|
+
expect(out.endsWith(`'`)).toBe(true);
|
|
9
|
+
});
|
|
10
|
+
it('strips double-quoted strings', () => {
|
|
11
|
+
const out = stripStrings(`x = "hello"`);
|
|
12
|
+
expect(out).not.toContain('hello');
|
|
13
|
+
});
|
|
14
|
+
it('strips triple-single strings (multi-line)', () => {
|
|
15
|
+
const out = stripStrings("x = '''line1\nline2'''");
|
|
16
|
+
expect(out).not.toContain('line1');
|
|
17
|
+
expect(out).not.toContain('line2');
|
|
18
|
+
});
|
|
19
|
+
it('strips triple-double strings (multi-line)', () => {
|
|
20
|
+
const out = stripStrings('x = """line1\nline2"""');
|
|
21
|
+
expect(out).not.toContain('line1');
|
|
22
|
+
expect(out).not.toContain('line2');
|
|
23
|
+
});
|
|
24
|
+
it('handles escape sequences', () => {
|
|
25
|
+
const out = stripStrings(String.raw `x = 'a\'b'`);
|
|
26
|
+
expect(out).not.toContain('a');
|
|
27
|
+
});
|
|
28
|
+
it('handles raw strings (no escape processing)', () => {
|
|
29
|
+
const out = stripStrings(`x = r'abc'`);
|
|
30
|
+
expect(out).not.toContain('abc');
|
|
31
|
+
});
|
|
32
|
+
it('terminates non-triple string at newline (malformed input)', () => {
|
|
33
|
+
const out = stripStrings("x = 'unclosed\n");
|
|
34
|
+
expect(out).toContain('x = ');
|
|
35
|
+
});
|
|
36
|
+
it('passes through code with no strings unchanged', () => {
|
|
37
|
+
const code = 'def foo():\n return 1';
|
|
38
|
+
expect(stripStrings(code)).toBe(code);
|
|
39
|
+
});
|
|
40
|
+
it('handles triple string with escaped quotes', () => {
|
|
41
|
+
const out = stripStrings(String.raw `x = '''line1\'still in string'''`);
|
|
42
|
+
expect(out).not.toContain('line1');
|
|
43
|
+
});
|
|
44
|
+
it('handles unterminated triple string', () => {
|
|
45
|
+
const out = stripStrings(`x = '''unterminated`);
|
|
46
|
+
expect(out).toContain('x = ');
|
|
47
|
+
expect(out).not.toContain('unterminated');
|
|
48
|
+
});
|
|
49
|
+
it('handles unterminated single-line string at EOF', () => {
|
|
50
|
+
const out = stripStrings(`x = "unterminated`);
|
|
51
|
+
expect(out).toContain('x = ');
|
|
52
|
+
expect(out).not.toContain('unterminated');
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
describe('stripComments', () => {
|
|
56
|
+
it('strips line comments', () => {
|
|
57
|
+
const out = stripComments('x = 1 # comment');
|
|
58
|
+
expect(out).not.toContain('comment');
|
|
59
|
+
expect(out).toContain('x = 1');
|
|
60
|
+
});
|
|
61
|
+
it('does not treat # inside a string as a comment marker', () => {
|
|
62
|
+
// The implementation may also blank string contents — what matters
|
|
63
|
+
// is that the structure ('x = "..."') survives without the # being
|
|
64
|
+
// misinterpreted as a comment delimiter that swallows the rest.
|
|
65
|
+
const out = stripComments('x = "# not a comment"\ny = 2');
|
|
66
|
+
expect(out).toContain('x = "');
|
|
67
|
+
expect(out).toContain('y = 2');
|
|
68
|
+
});
|
|
69
|
+
it('strips multiple comment lines', () => {
|
|
70
|
+
const src = '# top\nx = 1 # mid\ny = 2 # end';
|
|
71
|
+
const out = stripComments(src);
|
|
72
|
+
expect(out).not.toContain('top');
|
|
73
|
+
expect(out).not.toContain('mid');
|
|
74
|
+
expect(out).not.toContain('end');
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=strip.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strip.test.js","sourceRoot":"","sources":["../../src/__tests__/strip.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/tree.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { RunScope, runWithScopeSync } from '@opensip-cli/core';
|
|
2
|
+
import { initParseCache } from '@opensip-cli/core/languages/parse-cache.js';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
import { parsePython } from '../parse.js';
|
|
5
|
+
import { getSharedTree } from '../shared-tree.js';
|
|
6
|
+
describe('parsePython', () => {
|
|
7
|
+
it('produces a real tree-sitter tree + source', () => {
|
|
8
|
+
const src = 'def f():\n return 1\n';
|
|
9
|
+
const tree = parsePython(src, 'f.py');
|
|
10
|
+
expect(tree).not.toBeNull();
|
|
11
|
+
expect(tree?.source).toBe(src);
|
|
12
|
+
expect(tree?.tree.rootNode.type).toBe('module');
|
|
13
|
+
});
|
|
14
|
+
it('returns a partial (non-null) tree with hasError for malformed source', () => {
|
|
15
|
+
const tree = parsePython('def (:\n', 'bad.py');
|
|
16
|
+
expect(tree).not.toBeNull();
|
|
17
|
+
expect(tree?.tree.rootNode.hasError).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
describe('getSharedTree', () => {
|
|
21
|
+
it('returns a tree without an active cache (direct parse)', () => {
|
|
22
|
+
const tree = getSharedTree('x.py', 'x = 1\n');
|
|
23
|
+
expect(tree?.tree.rootNode.type).toBe('module');
|
|
24
|
+
});
|
|
25
|
+
describe('with an active parse cache', () => {
|
|
26
|
+
it('returns the same cached tree identity on repeat calls', () => {
|
|
27
|
+
runWithScopeSync(new RunScope(), () => {
|
|
28
|
+
initParseCache();
|
|
29
|
+
const a = getSharedTree('x.py', 'x = 1\n');
|
|
30
|
+
const b = getSharedTree('x.py', 'x = 1\n');
|
|
31
|
+
expect(a).toBe(b);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=tree.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.test.js","sourceRoot":"","sources":["../../src/__tests__/tree.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,4CAA4C,CAAC;AAC5E,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACnD,MAAM,GAAG,GAAG,0BAA0B,CAAC;QACvC,MAAM,IAAI,GAAG,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,IAAI,GAAG,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC/C,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAC9C,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;QAC1C,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;YAC/D,gBAAgB,CAAC,IAAI,QAAQ,EAAE,EAAE,GAAG,EAAE;gBACpC,cAAc,EAAE,CAAC;gBACjB,MAAM,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;gBAC3C,MAAM,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;gBAC3C,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type PythonTree } from './parse.js';
|
|
2
|
+
import type { LanguageAdapter } from '@opensip-cli/core';
|
|
3
|
+
export declare const pythonAdapter: LanguageAdapter<PythonTree>;
|
|
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,EAAe,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAG1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,eAAO,MAAM,aAAa,EAAE,eAAe,CAAC,UAAU,CAOrD,CAAC;AAEF,wEAAwE;AACxE,eAAO,MAAM,QAAQ,oFAA2B,CAAC"}
|
package/dist/adapter.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { parsePython } from './parse.js';
|
|
2
|
+
import { stripComments, stripStrings } from './strip.js';
|
|
3
|
+
export const pythonAdapter = {
|
|
4
|
+
id: 'python',
|
|
5
|
+
fileExtensions: ['.py', '.pyi'],
|
|
6
|
+
aliases: ['py'],
|
|
7
|
+
parse: parsePython,
|
|
8
|
+
stripStrings,
|
|
9
|
+
stripComments,
|
|
10
|
+
};
|
|
11
|
+
/** Plugin contract — exported as the lang plugin's `adapters` array. */
|
|
12
|
+
export const adapters = [pythonAdapter];
|
|
13
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAmB,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAIzD,MAAM,CAAC,MAAM,aAAa,GAAgC;IACxD,EAAE,EAAE,QAAQ;IACZ,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC;IAC/B,OAAO,EAAE,CAAC,IAAI,CAAC;IACf,KAAK,EAAE,WAAW;IAClB,YAAY;IACZ,aAAa;CACd,CAAC;AAEF,wEAAwE;AACxE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,aAAa,CAAU,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composed enclosing-scope helpers for Python (ADR-0010) — the per-language
|
|
3
|
+
* layer over the generic `findEnclosing`/`nameOf` from
|
|
4
|
+
* `@opensip-cli/tree-sitter`. Mirrors `lang-typescript`'s
|
|
5
|
+
* `findEnclosingFunction` / `getEnclosingFunctionName`.
|
|
6
|
+
*/
|
|
7
|
+
import { type Node } from '@opensip-cli/tree-sitter';
|
|
8
|
+
/** The nearest enclosing `def` of `node`, or `null` at module scope. */
|
|
9
|
+
export declare function findEnclosingFunction(node: Node): Node | null;
|
|
10
|
+
/** The name of the nearest enclosing `def`, or `null`. */
|
|
11
|
+
export declare function getEnclosingFunctionName(node: Node): string | null;
|
|
12
|
+
/**
|
|
13
|
+
* True when `node` is a method — a `function_definition` whose *nearest*
|
|
14
|
+
* enclosing function-or-class is a class. A function nested inside another
|
|
15
|
+
* function is therefore not a method (its nearest enclosing scope is a `def`).
|
|
16
|
+
*/
|
|
17
|
+
export declare function isMethod(node: Node): boolean;
|
|
18
|
+
//# sourceMappingURL=enclosing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enclosing.d.ts","sourceRoot":"","sources":["../src/enclosing.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAEH,OAAO,EAAyB,KAAK,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAI5E,wEAAwE;AACxE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAE7D;AAED,0DAA0D;AAC1D,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,30 @@
|
|
|
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 Python (ADR-0010) — the per-language
|
|
4
|
+
* layer over the generic `findEnclosing`/`nameOf` from
|
|
5
|
+
* `@opensip-cli/tree-sitter`. Mirrors `lang-typescript`'s
|
|
6
|
+
* `findEnclosingFunction` / `getEnclosingFunctionName`.
|
|
7
|
+
*/
|
|
8
|
+
import { findEnclosing, nameOf } from '@opensip-cli/tree-sitter';
|
|
9
|
+
import { isClass, isFunction } from './predicates.js';
|
|
10
|
+
/** The nearest enclosing `def` of `node`, or `null` at module scope. */
|
|
11
|
+
export function findEnclosingFunction(node) {
|
|
12
|
+
return findEnclosing(node, isFunction);
|
|
13
|
+
}
|
|
14
|
+
/** The name of the nearest enclosing `def`, or `null`. */
|
|
15
|
+
export function getEnclosingFunctionName(node) {
|
|
16
|
+
const fn = findEnclosingFunction(node);
|
|
17
|
+
return fn ? nameOf(fn) : null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* True when `node` is a method — a `function_definition` whose *nearest*
|
|
21
|
+
* enclosing function-or-class is a class. A function nested inside another
|
|
22
|
+
* function is therefore not a method (its nearest enclosing scope is a `def`).
|
|
23
|
+
*/
|
|
24
|
+
export function isMethod(node) {
|
|
25
|
+
if (!isFunction(node))
|
|
26
|
+
return false;
|
|
27
|
+
const enclosing = findEnclosing(node, (n) => isFunction(n) || isClass(n));
|
|
28
|
+
return enclosing !== null && isClass(enclosing);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=enclosing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enclosing.js","sourceRoot":"","sources":["../src/enclosing.ts"],"names":[],"mappings":"AAAA,gPAAgP;AAChP;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,EAAa,MAAM,0BAA0B,CAAC;AAE5E,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEtD,wEAAwE;AACxE,MAAM,UAAU,qBAAqB,CAAC,IAAU;IAC9C,OAAO,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;AACzC,CAAC;AAED,0DAA0D;AAC1D,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,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1E,OAAO,SAAS,KAAK,IAAI,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;AAClD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { pythonAdapter, adapters } from './adapter.js';
|
|
2
|
+
export { parsePython, type PythonTree } from './parse.js';
|
|
3
|
+
export { getSharedTree } from './shared-tree.js';
|
|
4
|
+
export { stripStrings, stripComments } from './strip.js';
|
|
5
|
+
export { isFunction, isClass, isComment, isString, isExcept, isConditional, isLoop, } from './predicates.js';
|
|
6
|
+
export { findEnclosingFunction, getEnclosingFunctionName, isMethod } from './enclosing.js';
|
|
7
|
+
export { childrenOf, findEnclosing, getColumn, getLineNumber, nameOf, namedChildrenOf, nodeText, walkNodes, type Node, } from '@opensip-cli/tree-sitter';
|
|
8
|
+
//# 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,aAAa,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EACL,UAAU,EACV,OAAO,EACP,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,MAAM,GACP,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAO3F,OAAO,EACL,UAAU,EACV,aAAa,EACb,SAAS,EACT,aAAa,EACb,MAAM,EACN,eAAe,EACf,QAAQ,EACR,SAAS,EACT,KAAK,IAAI,GACV,MAAM,0BAA0B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { pythonAdapter, adapters } from './adapter.js';
|
|
2
|
+
export { parsePython } from './parse.js';
|
|
3
|
+
export { getSharedTree } from './shared-tree.js';
|
|
4
|
+
export { stripStrings, stripComments } from './strip.js';
|
|
5
|
+
export { isFunction, isClass, isComment, isString, isExcept, isConditional, isLoop, } from './predicates.js';
|
|
6
|
+
export { findEnclosingFunction, getEnclosingFunctionName, isMethod } from './enclosing.js';
|
|
7
|
+
// Generic tree-sitter traversal/position vocabulary, re-exported so check
|
|
8
|
+
// packs reach the parser substrate THROUGH the language adapter (ADR-0039):
|
|
9
|
+
// the adapter owns the parser boundary; check packs depend on lang-python +
|
|
10
|
+
// fitness only, never on @opensip-cli/tree-sitter directly (enforced by
|
|
11
|
+
// dependency-cruiser).
|
|
12
|
+
export { childrenOf, findEnclosing, getColumn, getLineNumber, nameOf, namedChildrenOf, nodeText, walkNodes, } from '@opensip-cli/tree-sitter';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,WAAW,EAAmB,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EACL,UAAU,EACV,OAAO,EACP,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,MAAM,GACP,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE3F,0EAA0E;AAC1E,4EAA4E;AAC5E,4EAA4E;AAC5E,wEAAwE;AACxE,uBAAuB;AACvB,OAAO,EACL,UAAU,EACV,aAAa,EACb,SAAS,EACT,aAAa,EACb,MAAM,EACN,eAAe,EACf,QAAQ,EACR,SAAS,GAEV,MAAM,0BAA0B,CAAC"}
|
package/dist/parse.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Python parse — web-tree-sitter + vendored tree-sitter-python.wasm.
|
|
3
|
+
*
|
|
4
|
+
* ADR-0010: `lang-python` is the canonical Python parse substrate for the whole
|
|
5
|
+
* platform — fitness checks parse via the adapter (`getSharedTree`) and the
|
|
6
|
+
* graph Python adapter consumes this too. The grammar is loaded once at module
|
|
7
|
+
* top level (the WASM runtime is initialized by `@opensip-cli/tree-sitter`'s
|
|
8
|
+
* own top-level `Parser.init()`, statically imported here); a single reused
|
|
9
|
+
* parser keeps `parse()` synchronous and allocation-free. Tree-sitter recovers
|
|
10
|
+
* from syntax errors with MISSING nodes, so a malformed file yields a partial
|
|
11
|
+
* tree (non-null) rather than throwing — callers can inspect `rootNode.hasError`.
|
|
12
|
+
*/
|
|
13
|
+
import { type ParsedFile } from '@opensip-cli/tree-sitter';
|
|
14
|
+
/** Parsed Python source: tree-sitter parse tree plus the original source text. */
|
|
15
|
+
export type PythonTree = ParsedFile;
|
|
16
|
+
/** Parses Python source into a {@link PythonTree}, or null when no tree is produced. */
|
|
17
|
+
export declare function parsePython(content: string, _filePath: string): PythonTree | null;
|
|
18
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAA0C,KAAK,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAOnG,kFAAkF;AAClF,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC;AAEpC,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAGjF"}
|
package/dist/parse.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Python parse — web-tree-sitter + vendored tree-sitter-python.wasm.
|
|
3
|
+
*
|
|
4
|
+
* ADR-0010: `lang-python` is the canonical Python parse substrate for the whole
|
|
5
|
+
* platform — fitness checks parse via the adapter (`getSharedTree`) and the
|
|
6
|
+
* graph Python adapter consumes this too. The grammar is loaded once at module
|
|
7
|
+
* top level (the WASM runtime is initialized by `@opensip-cli/tree-sitter`'s
|
|
8
|
+
* own top-level `Parser.init()`, statically imported here); a single reused
|
|
9
|
+
* parser keeps `parse()` synchronous and allocation-free. Tree-sitter recovers
|
|
10
|
+
* from syntax errors with MISSING nodes, so a malformed file yields a partial
|
|
11
|
+
* tree (non-null) rather than throwing — callers can inspect `rootNode.hasError`.
|
|
12
|
+
*/
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
14
|
+
import { loadGrammar, createParser, parseToTree } from '@opensip-cli/tree-sitter';
|
|
15
|
+
const grammar = await loadGrammar(fileURLToPath(new URL('../wasm/tree-sitter-python.wasm', import.meta.url)));
|
|
16
|
+
const parser = createParser(grammar);
|
|
17
|
+
/** Parses Python source into a {@link PythonTree}, or null when no tree is produced. */
|
|
18
|
+
export function parsePython(content, _filePath) {
|
|
19
|
+
const tree = parseToTree(parser, content);
|
|
20
|
+
return tree ? { tree, source: content } : null;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;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,iCAAiC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAC3E,CAAC;AACF,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;AAKrC,wFAAwF;AACxF,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,SAAiB;IAC5D,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,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v1 per-language node-kind predicates for Python (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, and they live here.
|
|
5
|
+
* Node types are from the tree-sitter-python grammar.
|
|
6
|
+
*/
|
|
7
|
+
import type { Node } from '@opensip-cli/tree-sitter';
|
|
8
|
+
/** A `def` — both top-level functions and methods are `function_definition`. */
|
|
9
|
+
export declare const isFunction: (node: Node) => boolean;
|
|
10
|
+
/** A `class` declaration. */
|
|
11
|
+
export declare const isClass: (node: Node) => boolean;
|
|
12
|
+
/** A `#` comment. */
|
|
13
|
+
export declare const isComment: (node: Node) => boolean;
|
|
14
|
+
/** A string literal (also covers f-strings / docstrings at the node level). */
|
|
15
|
+
export declare const isString: (node: Node) => boolean;
|
|
16
|
+
/** An `except[ … ]:` clause — Python's error-handling node. */
|
|
17
|
+
export declare const isExcept: (node: Node) => boolean;
|
|
18
|
+
/** An `if` statement. */
|
|
19
|
+
export declare const isConditional: (node: Node) => boolean;
|
|
20
|
+
/** A `for` or `while` loop. */
|
|
21
|
+
export declare const isLoop: (node: Node) => boolean;
|
|
22
|
+
//# sourceMappingURL=predicates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predicates.d.ts","sourceRoot":"","sources":["../src/predicates.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAErD,gFAAgF;AAChF,eAAO,MAAM,UAAU,GAAI,MAAM,IAAI,KAAG,OAA8C,CAAC;AAEvF,6BAA6B;AAC7B,eAAO,MAAM,OAAO,GAAI,MAAM,IAAI,KAAG,OAA2C,CAAC;AAEjF,qBAAqB;AACrB,eAAO,MAAM,SAAS,GAAI,MAAM,IAAI,KAAG,OAAkC,CAAC;AAE1E,+EAA+E;AAC/E,eAAO,MAAM,QAAQ,GAAI,MAAM,IAAI,KAAG,OAAiC,CAAC;AAExE,+DAA+D;AAC/D,eAAO,MAAM,QAAQ,GAAI,MAAM,IAAI,KAAG,OAAwC,CAAC;AAE/E,yBAAyB;AACzB,eAAO,MAAM,aAAa,GAAI,MAAM,IAAI,KAAG,OAAuC,CAAC;AAEnF,+BAA+B;AAC/B,eAAO,MAAM,MAAM,GAAI,MAAM,IAAI,KAAG,OAC8B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
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 Python (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, and they live here.
|
|
6
|
+
* Node types are from the tree-sitter-python grammar.
|
|
7
|
+
*/
|
|
8
|
+
/** A `def` — both top-level functions and methods are `function_definition`. */
|
|
9
|
+
export const isFunction = (node) => node.type === 'function_definition';
|
|
10
|
+
/** A `class` declaration. */
|
|
11
|
+
export const isClass = (node) => node.type === 'class_definition';
|
|
12
|
+
/** A `#` comment. */
|
|
13
|
+
export const isComment = (node) => node.type === 'comment';
|
|
14
|
+
/** A string literal (also covers f-strings / docstrings at the node level). */
|
|
15
|
+
export const isString = (node) => node.type === 'string';
|
|
16
|
+
/** An `except[ … ]:` clause — Python's error-handling node. */
|
|
17
|
+
export const isExcept = (node) => node.type === 'except_clause';
|
|
18
|
+
/** An `if` statement. */
|
|
19
|
+
export const isConditional = (node) => node.type === 'if_statement';
|
|
20
|
+
/** A `for` or `while` loop. */
|
|
21
|
+
export const isLoop = (node) => node.type === 'for_statement' || node.type === 'while_statement';
|
|
22
|
+
//# sourceMappingURL=predicates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predicates.js","sourceRoot":"","sources":["../src/predicates.ts"],"names":[],"mappings":"AAAA,gPAAgP;AAChP;;;;;GAKG;AAIH,gFAAgF;AAChF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAU,EAAW,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,qBAAqB,CAAC;AAEvF,6BAA6B;AAC7B,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAU,EAAW,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,kBAAkB,CAAC;AAEjF,qBAAqB;AACrB,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAU,EAAW,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC;AAE1E,+EAA+E;AAC/E,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAU,EAAW,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC;AAExE,+DAA+D;AAC/D,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,IAAU,EAAW,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe,CAAC;AAE/E,yBAAyB;AACzB,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAU,EAAW,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,cAAc,CAAC;AAEnF,+BAA+B;AAC/B,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,IAAU,EAAW,EAAE,CAC5C,IAAI,CAAC,IAAI,KAAK,eAAe,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cached Python parse entry point — the analog of `lang-typescript`'s
|
|
3
|
+
* `getSharedSourceFile`. Routes through `core`'s active `LanguageParseCache`
|
|
4
|
+
* (key `python:filePath:fingerprint`) so a file parsed by a fitness check and
|
|
5
|
+
* by the graph adapter in the same run is parsed once. Falls back to a direct
|
|
6
|
+
* `adapter.parse` when no cache is active (single-check mode).
|
|
7
|
+
*/
|
|
8
|
+
import type { PythonTree } from './parse.js';
|
|
9
|
+
/** Returns the shared (cached) Python parse tree for `filePath`, or null when unparseable. */
|
|
10
|
+
export declare function getSharedTree(filePath: string, content: string): PythonTree | null;
|
|
11
|
+
//# 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;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,8FAA8F;AAC9F,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAElF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
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 Python parse entry point — the analog of `lang-typescript`'s
|
|
4
|
+
* `getSharedSourceFile`. Routes through `core`'s active `LanguageParseCache`
|
|
5
|
+
* (key `python:filePath:fingerprint`) so a file parsed by a fitness check and
|
|
6
|
+
* by the graph adapter in the same run is parsed once. Falls back to a direct
|
|
7
|
+
* `adapter.parse` when no cache is active (single-check mode).
|
|
8
|
+
*/
|
|
9
|
+
import { getParseTree } from '@opensip-cli/core/languages/parse-cache.js';
|
|
10
|
+
import { pythonAdapter } from './adapter.js';
|
|
11
|
+
/** Returns the shared (cached) Python parse tree for `filePath`, or null when unparseable. */
|
|
12
|
+
export function getSharedTree(filePath, content) {
|
|
13
|
+
return getParseTree(pythonAdapter, filePath, content);
|
|
14
|
+
}
|
|
15
|
+
//# 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;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,4CAA4C,CAAC;AAE1E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAI7C,8FAA8F;AAC9F,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,OAAe;IAC7D,OAAO,YAAY,CAAC,aAAa,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AACxD,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":"AAiNA,wEAAwE;AACxE,eAAO,MAAM,YAAY,6BAAwB,CAAC;AAClD,8EAA8E;AAC9E,eAAO,MAAM,aAAa,6BAAyB,CAAC"}
|
package/dist/strip.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// Python string and comment stripping.
|
|
2
|
+
//
|
|
3
|
+
// Hand-written lexer that recognizes:
|
|
4
|
+
// - Line comments (# ... end-of-line)
|
|
5
|
+
// - Single-quoted strings ('...') and double-quoted strings ("...")
|
|
6
|
+
// - Triple-quoted strings ('''...''' and """...""") — multi-line
|
|
7
|
+
// - String prefixes (case-insensitive): r, b, u, f, rb, br, rf, fr
|
|
8
|
+
// e.g. r'raw', b"bytes", f"hello {x}", rb'raw-bytes'
|
|
9
|
+
// - Raw strings (prefix r/rb/br/rf/fr): backslash is an ordinary
|
|
10
|
+
// character EXCEPT before a quote (`\"` / `\'`), where it does NOT
|
|
11
|
+
// terminate the literal — matches CPython's tokenizer rule
|
|
12
|
+
// - F-string expression interpolation is intentionally NOT preserved —
|
|
13
|
+
// the entire body is treated as string content. This is a documented
|
|
14
|
+
// MVP limitation; checks that need to see f-string expressions should
|
|
15
|
+
// wait for tree-sitter integration.
|
|
16
|
+
//
|
|
17
|
+
// Both strip functions preserve byte length: replacement is whitespace
|
|
18
|
+
// (newlines preserved) so line/column positions remain stable.
|
|
19
|
+
//
|
|
20
|
+
// NOTE: this pack deliberately does NOT consume the C-family scanners
|
|
21
|
+
// from `@opensip-cli/core/languages/strip-utils.ts`
|
|
22
|
+
// (`scanRegularString`, `scanLineComment`, `scanBlockCommentNonNesting`,
|
|
23
|
+
// `scanCharLiteral`). Python's quote rules are the family outlier —
|
|
24
|
+
// strings open with either `'` or `"`, support eight ASCII prefix
|
|
25
|
+
// forms, and use `#` line comments — and the C-family helpers'
|
|
26
|
+
// signatures don't fit. If a second adopter (Ruby, Bash, Swift)
|
|
27
|
+
// appears, the right move is to lift a parameterized
|
|
28
|
+
// `scanQuotedString(quoteChar)` into core; with one consumer it stays
|
|
29
|
+
// here.
|
|
30
|
+
import { isIdentChar, makeStripper } from '@opensip-cli/core';
|
|
31
|
+
// Allowed Python string prefixes (lowercase). Case-insensitivity is
|
|
32
|
+
// handled at match time by lowercasing the candidate. Two-letter
|
|
33
|
+
// combinations come first so a longer prefix wins over a shorter one.
|
|
34
|
+
const TWO_CHAR_PREFIXES = new Set(['rb', 'br', 'rf', 'fr']);
|
|
35
|
+
const ONE_CHAR_PREFIXES = new Set(['r', 'b', 'u', 'f']);
|
|
36
|
+
function isAsciiLetter(ch) {
|
|
37
|
+
if (!ch)
|
|
38
|
+
return false;
|
|
39
|
+
const code = ch.codePointAt(0) ?? 0;
|
|
40
|
+
return (code >= 0x41 && code <= 0x5a) || (code >= 0x61 && code <= 0x7a);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* If position `i` looks like the start of a Python string literal
|
|
44
|
+
* (optionally with prefix), return the index of the opening quote.
|
|
45
|
+
* Otherwise return null.
|
|
46
|
+
*
|
|
47
|
+
* The check is conservative: a prefix only counts if the character
|
|
48
|
+
* BEFORE it isn't an identifier character, so identifiers like
|
|
49
|
+
* `myvar = foo` or `bar` aren't mistaken for prefixes.
|
|
50
|
+
*
|
|
51
|
+
* Note: we deliberately do NOT distinguish raw from non-raw here.
|
|
52
|
+
* For *tokenization-bound* (which is all the strip pass needs), the
|
|
53
|
+
* two cases are identical: backslash always pairs with the next char.
|
|
54
|
+
* The raw/non-raw distinction only matters for value extraction —
|
|
55
|
+
* something the strip pass never does. See the scanner functions
|
|
56
|
+
* for the CPython-spec citation.
|
|
57
|
+
*/
|
|
58
|
+
function matchStringStart(src, i) {
|
|
59
|
+
const c = src[i];
|
|
60
|
+
if (c === '"' || c === "'") {
|
|
61
|
+
return { quoteIndex: i };
|
|
62
|
+
}
|
|
63
|
+
if (!isAsciiLetter(c))
|
|
64
|
+
return null;
|
|
65
|
+
// Reject if the previous character is part of an identifier — then
|
|
66
|
+
// this is the middle/end of an identifier, not a string prefix.
|
|
67
|
+
if (i > 0 && isIdentChar(src[i - 1]))
|
|
68
|
+
return null;
|
|
69
|
+
// Try two-character prefix first.
|
|
70
|
+
const c1 = src[i];
|
|
71
|
+
const c2 = src[i + 1];
|
|
72
|
+
if (c1 && c2) {
|
|
73
|
+
const two = (c1 + c2).toLowerCase();
|
|
74
|
+
if (TWO_CHAR_PREFIXES.has(two)) {
|
|
75
|
+
const after = src[i + 2];
|
|
76
|
+
if (after === '"' || after === "'") {
|
|
77
|
+
return { quoteIndex: i + 2 };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Single-character prefix.
|
|
82
|
+
const one = c1?.toLowerCase();
|
|
83
|
+
if (one && ONE_CHAR_PREFIXES.has(one)) {
|
|
84
|
+
const after = src[i + 1];
|
|
85
|
+
if (after === '"' || after === "'") {
|
|
86
|
+
return { quoteIndex: i + 1 };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
function scanTripleString(src, contentStart, quote) {
|
|
92
|
+
const len = src.length;
|
|
93
|
+
let i = contentStart;
|
|
94
|
+
while (i < len) {
|
|
95
|
+
const ch = src[i];
|
|
96
|
+
if (ch === '\\') {
|
|
97
|
+
// Backslash always pairs with the following character for
|
|
98
|
+
// tokenization purposes, in BOTH non-raw and raw strings. In
|
|
99
|
+
// non-raw, this is escape-sequence handling. In raw, escape
|
|
100
|
+
// sequences are not interpreted, but per CPython:
|
|
101
|
+
// "Even in a raw literal, quotes can be escaped with a
|
|
102
|
+
// backslash, but the backslash remains in the result."
|
|
103
|
+
// So `r"\""` is the 2-char string `\"`, terminated by the
|
|
104
|
+
// third `"`. We must therefore skip past `\<anything>` in raw
|
|
105
|
+
// mode too, otherwise the next quote is mis-read as terminator.
|
|
106
|
+
// Newlines are preserved because we never replace them.
|
|
107
|
+
i += 2;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (ch === quote && src[i + 1] === quote && src[i + 2] === quote) {
|
|
111
|
+
return { contentStart, contentEnd: i, next: i + 3 };
|
|
112
|
+
}
|
|
113
|
+
i++;
|
|
114
|
+
}
|
|
115
|
+
// Unterminated — record what we have.
|
|
116
|
+
return { contentStart, contentEnd: len, next: len };
|
|
117
|
+
}
|
|
118
|
+
function scanSingleString(src, contentStart, quote) {
|
|
119
|
+
const len = src.length;
|
|
120
|
+
let i = contentStart;
|
|
121
|
+
while (i < len) {
|
|
122
|
+
const ch = src[i];
|
|
123
|
+
// Newline terminates a non-triple string in Python (it's a syntax
|
|
124
|
+
// error to span lines without explicit continuation, but for
|
|
125
|
+
// strip purposes treat newline as a terminator to avoid eating
|
|
126
|
+
// the rest of the file on malformed input).
|
|
127
|
+
if (ch === '\n') {
|
|
128
|
+
return { contentStart, contentEnd: i, next: i };
|
|
129
|
+
}
|
|
130
|
+
if (ch === '\\') {
|
|
131
|
+
// Backslash always pairs with the following character for
|
|
132
|
+
// tokenization purposes, in BOTH non-raw and raw strings. In
|
|
133
|
+
// non-raw, this is escape-sequence handling (and `\\\n` is line
|
|
134
|
+
// continuation). In raw, escape sequences are not interpreted,
|
|
135
|
+
// but per CPython:
|
|
136
|
+
// "Even in a raw literal, quotes can be escaped with a
|
|
137
|
+
// backslash, but the backslash remains in the result."
|
|
138
|
+
// So `r"\""` is the 2-char string `\"`, terminated by the
|
|
139
|
+
// third `"`. We must therefore skip past `\<anything>` in raw
|
|
140
|
+
// mode too, otherwise the next quote is mis-read as terminator.
|
|
141
|
+
i += 2;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (ch === quote) {
|
|
145
|
+
return { contentStart, contentEnd: i, next: i + 1 };
|
|
146
|
+
}
|
|
147
|
+
i++;
|
|
148
|
+
}
|
|
149
|
+
return { contentStart, contentEnd: len, next: len };
|
|
150
|
+
}
|
|
151
|
+
function scan(src) {
|
|
152
|
+
const stringRegions = [];
|
|
153
|
+
const commentRegions = [];
|
|
154
|
+
const len = src.length;
|
|
155
|
+
let i = 0;
|
|
156
|
+
while (i < len) {
|
|
157
|
+
const c = src[i];
|
|
158
|
+
// Line comment: # ... \n
|
|
159
|
+
if (c === '#') {
|
|
160
|
+
const start = i;
|
|
161
|
+
i++;
|
|
162
|
+
while (i < len && src[i] !== '\n')
|
|
163
|
+
i++;
|
|
164
|
+
commentRegions.push({ start, end: i });
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
// String literal (with optional prefix).
|
|
168
|
+
const stringStart = matchStringStart(src, i);
|
|
169
|
+
if (stringStart) {
|
|
170
|
+
const { quoteIndex } = stringStart;
|
|
171
|
+
const quote = src[quoteIndex];
|
|
172
|
+
// Triple-quoted?
|
|
173
|
+
if (src[quoteIndex + 1] === quote && src[quoteIndex + 2] === quote) {
|
|
174
|
+
const contentStart = quoteIndex + 3;
|
|
175
|
+
const result = scanTripleString(src, contentStart, quote);
|
|
176
|
+
stringRegions.push({ start: result.contentStart, end: result.contentEnd });
|
|
177
|
+
i = result.next;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
const contentStart = quoteIndex + 1;
|
|
181
|
+
const result = scanSingleString(src, contentStart, quote);
|
|
182
|
+
stringRegions.push({ start: result.contentStart, end: result.contentEnd });
|
|
183
|
+
i = result.next;
|
|
184
|
+
}
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
i++;
|
|
188
|
+
}
|
|
189
|
+
return { stringRegions, commentRegions };
|
|
190
|
+
}
|
|
191
|
+
const stripper = makeStripper(scan);
|
|
192
|
+
/** Replace string literal content with whitespace; preserves length. */
|
|
193
|
+
export const stripStrings = stripper.stripStrings;
|
|
194
|
+
/** Replace string literals AND comments with whitespace; preserves length. */
|
|
195
|
+
export const stripComments = stripper.stripComments;
|
|
196
|
+
//# sourceMappingURL=strip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strip.js","sourceRoot":"","sources":["../src/strip.ts"],"names":[],"mappings":"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"}
|