ast-search-python 1.0.2 → 1.0.4

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ast-search-python
2
2
 
3
- Python language plugin for [ast-search](../../README.md). Adds `.py` / `.pyw` file support using [tree-sitter](https://tree-sitter.github.io/tree-sitter/) S-expression queries.
3
+ Python language plugin for [ast-search-js](../ast-search-js/README.md). Adds `.py` / `.pyw` file support using [tree-sitter](https://tree-sitter.github.io/tree-sitter/) S-expression queries.
4
4
 
5
5
  ## Table of Contents
6
6
 
@@ -15,10 +15,12 @@ Python language plugin for [ast-search](../../README.md). Adds `.py` / `.pyw` fi
15
15
  ## Installation
16
16
 
17
17
  ```bash
18
- npm install -g ast-search
18
+ npm install -g ast-search-js
19
19
  npm install -g ast-search-python
20
20
  ```
21
21
 
22
+ > **pnpm users:** `tree-sitter` requires compiling a native addon. pnpm blocks build scripts by default, so the binary won't be built without extra steps. Either run `pnpm approve-builds -g` (select `tree-sitter` and `tree-sitter-python`), then reinstall — or use `npm install -g` instead.
23
+
22
24
  ## Usage
23
25
 
24
26
  Pass `--plugin ast-search-python` to enable Python file support:
@@ -108,10 +110,10 @@ Raw S-expression queries must include at least one `@capture_name` — tree-sitt
108
110
 
109
111
  ## Plugin API
110
112
 
111
- This package implements the `LanguageBackend` interface from `ast-search/plugin`. It registers the `python` language backend automatically when loaded via `--plugin ast-search-python`, or programmatically:
113
+ This package implements the `LanguageBackend` interface from `ast-search-js/plugin`. It registers the `python` language backend automatically when loaded via `--plugin ast-search-python`, or programmatically:
112
114
 
113
115
  ```typescript
114
- import { defaultRegistry } from 'ast-search/plugin';
116
+ import { defaultRegistry } from 'ast-search-js/plugin';
115
117
  const { register } = await import('ast-search-python');
116
118
  register(defaultRegistry);
117
119
  ```
package/build/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import type { LanguageBackend, LanguageRegistry, Match } from "ast-search/plugin";
1
+ import type { LanguageBackend, LanguageRegistry, Match } from "ast-search-js/plugin";
2
2
  export declare class PythonLanguageBackend implements LanguageBackend {
3
3
  readonly langId = "python";
4
4
  readonly name = "Python";
5
5
  readonly extensions: Set<string>;
6
- parse(source: string, _filePath: string): unknown;
7
- query(ast: unknown, selector: string, source: string, filePath: string): Match[];
8
- validateSelector(selector: string): void;
6
+ parse(source: string, _filePath: string): Promise<unknown>;
7
+ query(ast: unknown, selector: string, source: string, filePath: string): Promise<Match[]>;
8
+ validateSelector(selector: string): Promise<void>;
9
9
  }
10
10
  /**
11
11
  * Register the Python backend with an ast-search LanguageRegistry.
package/build/index.js CHANGED
@@ -1,28 +1,36 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  import { createRequire } from "module";
11
+ import path from "path";
2
12
  import { expandShorthands } from "./shorthands.js";
3
13
  import { runTreeSitterQuery, validateTreeSitterQuery } from "./query.js";
4
- // tree-sitter is a CommonJS module; use createRequire for ESM compat.
5
14
  const _require = createRequire(import.meta.url);
6
- // Lazy-initialize the parser so the native addon is only loaded when
7
- // a Python file is actually parsed (not at module import time).
8
- let _parser;
9
- let _language;
10
- let _QueryClass;
15
+ let _runtimePromise = null;
11
16
  function getRuntime() {
12
- if (!_parser) {
13
- const Parser = _require("tree-sitter");
14
- const pythonModule = _require("tree-sitter-python");
15
- _language = pythonModule.language;
16
- _QueryClass = Parser.Query;
17
- const p = new Parser();
18
- p.setLanguage(pythonModule);
19
- _parser = p;
20
- }
21
- return {
22
- parser: _parser,
23
- language: _language,
24
- QueryClass: _QueryClass,
25
- };
17
+ return __awaiter(this, void 0, void 0, function* () {
18
+ if (_runtimePromise)
19
+ return _runtimePromise;
20
+ _runtimePromise = (() => __awaiter(this, void 0, void 0, function* () {
21
+ const { default: Parser } = yield import("web-tree-sitter");
22
+ const wasmDir = path.dirname(_require.resolve("web-tree-sitter"));
23
+ yield Parser.init({
24
+ locateFile: (_name) => path.join(wasmDir, "tree-sitter.wasm"),
25
+ });
26
+ const wasmPath = path.join(path.dirname(_require.resolve("tree-sitter-wasms/package.json")), "out", "tree-sitter-python.wasm");
27
+ const Python = yield Parser.Language.load(wasmPath);
28
+ const parser = new Parser();
29
+ parser.setLanguage(Python);
30
+ return { parser: parser, language: Python };
31
+ }))();
32
+ return _runtimePromise;
33
+ });
26
34
  }
27
35
  export class PythonLanguageBackend {
28
36
  constructor() {
@@ -31,17 +39,23 @@ export class PythonLanguageBackend {
31
39
  this.extensions = new Set([".py", ".pyw"]);
32
40
  }
33
41
  parse(source, _filePath) {
34
- const { parser } = getRuntime();
35
- return parser.parse(source);
42
+ return __awaiter(this, void 0, void 0, function* () {
43
+ const { parser } = yield getRuntime();
44
+ return parser.parse(source);
45
+ });
36
46
  }
37
47
  query(ast, selector, source, filePath) {
38
- const { language, QueryClass } = getRuntime();
39
- const expanded = expandShorthands(selector);
40
- return runTreeSitterQuery(ast, expanded, source, filePath, language, QueryClass);
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ const { language } = yield getRuntime();
50
+ const expanded = expandShorthands(selector);
51
+ return runTreeSitterQuery(ast, expanded, source, filePath, language);
52
+ });
41
53
  }
42
54
  validateSelector(selector) {
43
- const { language, QueryClass } = getRuntime();
44
- validateTreeSitterQuery(expandShorthands(selector), language, QueryClass);
55
+ return __awaiter(this, void 0, void 0, function* () {
56
+ const { language } = yield getRuntime();
57
+ validateTreeSitterQuery(expandShorthands(selector), language);
58
+ });
45
59
  }
46
60
  }
47
61
  /**
package/build/query.d.ts CHANGED
@@ -1,23 +1,3 @@
1
- import type { Match } from "ast-search/plugin";
2
- interface TSNode {
3
- startPosition: {
4
- row: number;
5
- column: number;
6
- };
7
- startIndex: number;
8
- endIndex: number;
9
- type: string;
10
- }
11
- interface TSCapture {
12
- node: TSNode;
13
- name: string;
14
- }
15
- interface TSQueryConstructor {
16
- new (language: unknown, pattern: string): TSQuery;
17
- }
18
- interface TSQuery {
19
- captures(node: TSNode): TSCapture[];
20
- }
21
- export declare function runTreeSitterQuery(ast: unknown, pattern: string, source: string, filePath: string, language: unknown, QueryClass: TSQueryConstructor): Match[];
22
- export declare function validateTreeSitterQuery(pattern: string, language: unknown, QueryClass: TSQueryConstructor): void;
23
- export {};
1
+ import type { Match } from "ast-search-js/plugin";
2
+ export declare function runTreeSitterQuery(ast: unknown, pattern: string, source: string, filePath: string, language: unknown): Match[];
3
+ export declare function validateTreeSitterQuery(pattern: string, language: unknown): void;
package/build/query.js CHANGED
@@ -7,18 +7,21 @@ function assertValidPattern(pattern) {
7
7
  `Use a shorthand (e.g. "fn", "call") or write a full S-expression (e.g. "(function_definition) @fn").`);
8
8
  }
9
9
  }
10
- export function runTreeSitterQuery(ast, pattern, source, filePath, language, QueryClass) {
10
+ export function runTreeSitterQuery(ast, pattern, source, filePath, language) {
11
11
  assertValidPattern(pattern);
12
12
  const tree = ast;
13
- const q = new QueryClass(language, pattern);
13
+ const q = language.query(pattern);
14
14
  const captures = q.captures(tree.rootNode);
15
+ // web-tree-sitter may return different JS objects for the same node when
16
+ // multiple capture names match it, so deduplicate by position instead of identity.
15
17
  const seen = new Set();
16
18
  const results = [];
17
19
  for (const capture of captures) {
18
20
  const node = capture.node;
19
- if (seen.has(node))
21
+ const key = `${node.startIndex}:${node.endIndex}`;
22
+ if (seen.has(key))
20
23
  continue;
21
- seen.add(node);
24
+ seen.add(key);
22
25
  const text = source.slice(node.startIndex, node.endIndex);
23
26
  const firstLine = text.split("\n")[0].trimEnd();
24
27
  results.push({
@@ -30,10 +33,10 @@ export function runTreeSitterQuery(ast, pattern, source, filePath, language, Que
30
33
  }
31
34
  return results;
32
35
  }
33
- export function validateTreeSitterQuery(pattern, language, QueryClass) {
36
+ export function validateTreeSitterQuery(pattern, language) {
34
37
  try {
35
38
  assertValidPattern(pattern);
36
- new QueryClass(language, pattern);
39
+ language.query(pattern);
37
40
  }
38
41
  catch (e) {
39
42
  throw new Error(`Invalid tree-sitter query: ${e instanceof Error ? e.message : String(e)}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ast-search-python",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Python language plugin for ast-search",
5
5
  "type": "module",
6
6
  "main": "./build/index.js",
@@ -32,19 +32,19 @@
32
32
  "provenance": true
33
33
  },
34
34
  "dependencies": {
35
- "tree-sitter": "^0.21.1",
36
- "tree-sitter-python": "^0.21.0"
35
+ "web-tree-sitter": "^0.24.0",
36
+ "tree-sitter-wasms": "^0.1.12"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@jest/globals": "^29.7.0",
40
40
  "@types/jest": "^29.5.12",
41
41
  "@types/node": "^20.12.7",
42
- "ast-search": "workspace:*",
42
+ "ast-search-js": "1.0.1",
43
43
  "jest": "^29.7.0",
44
44
  "ts-jest": "^29.1.2",
45
45
  "typescript": "^5.4.5"
46
46
  },
47
47
  "peerDependencies": {
48
- "ast-search": ">=0.3.0"
48
+ "ast-search-js": "1.0.1"
49
49
  }
50
50
  }