@letant/python 0.0.3

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Juun
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @letant/python
2
+
3
+ Python grammar provider plugin for letant core library.
@@ -0,0 +1,27 @@
1
+ import * as letant from 'letant';
2
+
3
+ type QueryConfig = {
4
+ "module.binding": {
5
+ required: "source";
6
+ optional: "alias" | "name";
7
+ };
8
+ variable: {
9
+ required: "node" | "name";
10
+ optional: never;
11
+ };
12
+ class: {
13
+ required: "node" | "name" | "body";
14
+ optional: "extends";
15
+ };
16
+ function: {
17
+ required: "node" | "name" | "body";
18
+ optional: never;
19
+ };
20
+ };
21
+ type NodeKind = letant.Head<keyof QueryConfig> | "parameter";
22
+ type Node = letant.Node<NodeKind>;
23
+ type Descriptor = letant.Plugin.Descriptor<QueryConfig, Node>;
24
+
25
+ declare const descriptor: Descriptor;
26
+
27
+ export { descriptor as default, descriptor };
@@ -0,0 +1,27 @@
1
+ import * as letant from 'letant';
2
+
3
+ type QueryConfig = {
4
+ "module.binding": {
5
+ required: "source";
6
+ optional: "alias" | "name";
7
+ };
8
+ variable: {
9
+ required: "node" | "name";
10
+ optional: never;
11
+ };
12
+ class: {
13
+ required: "node" | "name" | "body";
14
+ optional: "extends";
15
+ };
16
+ function: {
17
+ required: "node" | "name" | "body";
18
+ optional: never;
19
+ };
20
+ };
21
+ type NodeKind = letant.Head<keyof QueryConfig> | "parameter";
22
+ type Node = letant.Node<NodeKind>;
23
+ type Descriptor = letant.Plugin.Descriptor<QueryConfig, Node>;
24
+
25
+ declare const descriptor: Descriptor;
26
+
27
+ export { descriptor as default, descriptor };
package/dist/index.js ADDED
@@ -0,0 +1,335 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ default: () => index_default,
34
+ descriptor: () => descriptor
35
+ });
36
+ module.exports = __toCommonJS(index_exports);
37
+
38
+ // src/query.ts
39
+ var import_query = require("letant/query");
40
+ var import_tree_sitter_python = __toESM(require("tree-sitter-python"));
41
+
42
+ // src/queries/binding/module.scm
43
+ var module_default = "(import_statement name: (dotted_name) @source @name) (import_statement name: (aliased_import name: (dotted_name) @source alias: (identifier) @alias)) (import_from_statement module_name: [ (dotted_name) (relative_import) ] @source name: (dotted_name) @name) (import_from_statement module_name: [ (dotted_name) (relative_import) ] @source name: (aliased_import name: (dotted_name) @name alias: (identifier) @alias))";
44
+
45
+ // src/queries/binding/variable.scm
46
+ var variable_default = "(expression_statement (assignment left: [ (identifier) (pattern_list) (tuple_pattern) ] @name) ) @node (for_statement left: [ (identifier) (pattern_list) (tuple_pattern) ] @name ) @node";
47
+
48
+ // src/queries/scope/class.scm
49
+ var class_default = "(class_definition name: (identifier) @name superclasses: (argument_list)? @extends body: (block) @body ) @node";
50
+
51
+ // src/queries/scope/function.scm
52
+ var function_default = "(function_definition name: (identifier) @name body: (block) @body ) @node";
53
+
54
+ // src/queries/utility/reference.scm
55
+ var reference_default = "(identifier) @reference";
56
+
57
+ // src/query.ts
58
+ var language = import_tree_sitter_python.default;
59
+ var query = new import_query.QueryMap(language).set("module.binding", module_default).set("variable", variable_default).set("class", class_default).set("function", function_default);
60
+ var utility = new import_query.QueryMap(language).set(
61
+ "reference",
62
+ reference_default
63
+ );
64
+
65
+ // src/handlers/bypass/compound.ts
66
+ var COMPOUND = /* @__PURE__ */ new Set([
67
+ "if_statement",
68
+ "elif_clause",
69
+ "else_clause",
70
+ "for_statement",
71
+ "while_statement",
72
+ "try_statement",
73
+ "except_clause",
74
+ "finally_clause",
75
+ "with_statement",
76
+ "match_statement",
77
+ "case_clause"
78
+ ]);
79
+ function bypassCompound(queryKey) {
80
+ const blocks = (node) => node.namedChildren.flatMap((child) => {
81
+ if (child.type === "block") return [child];
82
+ if (COMPOUND.has(child.type)) return blocks(child);
83
+ return [];
84
+ });
85
+ const run = (node) => {
86
+ const matches = [];
87
+ for (const child of node.namedChildren) {
88
+ if (child.type === "decorated_definition") {
89
+ const definition = child.childForFieldName("definition");
90
+ if (definition) {
91
+ matches.push(
92
+ ...query.match(queryKey, definition, { maxStartDepth: 0 })
93
+ );
94
+ }
95
+ continue;
96
+ }
97
+ if (!COMPOUND.has(child.type)) continue;
98
+ for (const block of blocks(child)) {
99
+ matches.push(...query.match(queryKey, block, { maxStartDepth: 1 }));
100
+ matches.push(...run(block));
101
+ }
102
+ }
103
+ return matches;
104
+ };
105
+ return run;
106
+ }
107
+ var compound_default = bypassCompound;
108
+
109
+ // src/capture.ts
110
+ var captureConfig = {
111
+ "module.binding": {
112
+ bypass: compound_default("module.binding")
113
+ },
114
+ variable: {
115
+ bypass: compound_default("variable")
116
+ },
117
+ class: {
118
+ bypass: compound_default("class")
119
+ },
120
+ function: {
121
+ bypass: compound_default("function")
122
+ }
123
+ };
124
+
125
+ // src/handlers/binding/module.ts
126
+ var import_utils = require("letant/utils");
127
+ var import_utils2 = require("letant/utils");
128
+
129
+ // src/handlers/utility/module-path.ts
130
+ function toModulePath(source) {
131
+ if (!source.startsWith(".")) return source;
132
+ const dots = /^\.+/.exec(source)[0].length;
133
+ const rest = source.slice(dots).replace(/\./g, "/");
134
+ const prefix = dots === 1 ? "./" : "../".repeat(dots - 1);
135
+ return rest ? prefix + rest : prefix;
136
+ }
137
+ var module_path_default = toModulePath;
138
+
139
+ // src/handlers/binding/module.ts
140
+ var moduleBindingHandler = (captures, parent) => {
141
+ const result = (0, import_utils2.createConvertResult)();
142
+ for (const c of captures) {
143
+ const { source, name, alias } = c;
144
+ const plain = !!name && !alias && source.text === name.text;
145
+ const representative = alias?.text ?? (plain ? source.text.split(".")[0] : name?.text);
146
+ if (!representative) continue;
147
+ let modulePath = module_path_default(plain ? representative : source.text);
148
+ if (modulePath.endsWith("/") && name) {
149
+ modulePath += name.text;
150
+ }
151
+ result.nodes.push({
152
+ path: (0, import_utils2.createChildPath)(parent, representative),
153
+ type: "binding",
154
+ kind: "module",
155
+ at: (0, import_utils.NodeSource)(modulePath),
156
+ props: alias ? { alias_of: (name ?? source).text } : void 0
157
+ });
158
+ }
159
+ return result;
160
+ };
161
+ var module_default2 = moduleBindingHandler;
162
+
163
+ // src/handlers/binding/variable.ts
164
+ var import_utils3 = require("letant/utils");
165
+
166
+ // src/handlers/utility/pattern.ts
167
+ var dispatcher = {
168
+ // terminate condition of recursion
169
+ identifier: (node) => [{ name: node.text, node }],
170
+ // recurse over single element
171
+ list_splat_pattern: (node) => flatPattern(node.firstNamedChild),
172
+ // recurse over multiple elements
173
+ pattern_list: (node) => node.namedChildren.flatMap((c) => flatPattern(c)),
174
+ tuple_pattern: (node) => node.namedChildren.flatMap((c) => flatPattern(c)),
175
+ list_pattern: (node) => node.namedChildren.flatMap((c) => flatPattern(c))
176
+ };
177
+ function flatPattern(node) {
178
+ if (!dispatcher[node.type]) {
179
+ return [];
180
+ }
181
+ return dispatcher[node.type](node);
182
+ }
183
+ var pattern_default = flatPattern;
184
+
185
+ // src/handlers/binding/variable.ts
186
+ var variableHandler = (captures, parent) => {
187
+ const result = (0, import_utils3.createConvertResult)();
188
+ for (const c of captures) {
189
+ const { node, name } = c;
190
+ for (const { name: nm, node: n } of pattern_default(name)) {
191
+ const path = (0, import_utils3.createChildPath)(parent, nm);
192
+ result.nodes.push({
193
+ path,
194
+ type: "binding",
195
+ kind: "variable",
196
+ at: (0, import_utils3.getRange)(name.type === "identifier" ? node : n)
197
+ });
198
+ }
199
+ }
200
+ return result;
201
+ };
202
+ var variable_default2 = variableHandler;
203
+
204
+ // src/handlers/scope/class.ts
205
+ var import_utils4 = require("letant/utils");
206
+ var classHandler = (captures, parent, { capture, convert }) => {
207
+ const result = (0, import_utils4.createConvertResult)();
208
+ for (const c of captures) {
209
+ const { node, name, extends: ext, body } = c;
210
+ const path = (0, import_utils4.createChildPath)(parent, name.text);
211
+ result.nodes.push({
212
+ path,
213
+ type: "scope",
214
+ kind: "class",
215
+ at: (0, import_utils4.getRange)(node),
216
+ blockStartIndex: body.startIndex,
217
+ props: {
218
+ extends: ext?.text
219
+ }
220
+ });
221
+ result.push(convert(capture(body), path));
222
+ }
223
+ return result;
224
+ };
225
+ var class_default2 = classHandler;
226
+
227
+ // src/handlers/scope/function.ts
228
+ var import_utils5 = require("letant/utils");
229
+
230
+ // src/handlers/utility/parameter.ts
231
+ function flatParameters(parameters) {
232
+ const result = [];
233
+ for (const child of parameters.namedChildren) {
234
+ switch (child.type) {
235
+ case "identifier":
236
+ result.push({ name: child.text, node: child, has_default: false });
237
+ break;
238
+ case "typed_parameter": {
239
+ const inner = child.firstNamedChild;
240
+ if (inner?.type === "identifier") {
241
+ result.push({ name: inner.text, node: child, has_default: false });
242
+ }
243
+ break;
244
+ }
245
+ case "default_parameter":
246
+ case "typed_default_parameter": {
247
+ const name = child.childForFieldName("name");
248
+ if (name?.type === "identifier") {
249
+ result.push({ name: name.text, node: child, has_default: true });
250
+ }
251
+ break;
252
+ }
253
+ case "list_splat_pattern":
254
+ case "dictionary_splat_pattern": {
255
+ const inner = child.firstNamedChild;
256
+ if (inner?.type === "identifier") {
257
+ result.push({ name: inner.text, node: child, has_default: false });
258
+ }
259
+ break;
260
+ }
261
+ default:
262
+ break;
263
+ }
264
+ }
265
+ return result;
266
+ }
267
+ var parameter_default = flatParameters;
268
+
269
+ // src/handlers/scope/function.ts
270
+ var functionHandler = (captures, parent, { capture, convert }) => {
271
+ const result = (0, import_utils5.createConvertResult)();
272
+ for (const c of captures) {
273
+ const { node, name, body } = c;
274
+ const path = (0, import_utils5.createChildPath)(parent, name.text);
275
+ result.nodes.push({
276
+ path,
277
+ type: "scope",
278
+ kind: "function",
279
+ at: (0, import_utils5.getRange)(node),
280
+ blockStartIndex: body.startIndex,
281
+ props: {
282
+ is_async: node.children.some((child) => child.type === "async")
283
+ }
284
+ });
285
+ const parameters = node.childForFieldName("parameters");
286
+ if (parameters) {
287
+ for (const { name: nm, node: n, has_default } of parameter_default(
288
+ parameters
289
+ )) {
290
+ result.nodes.push({
291
+ path: (0, import_utils5.createChildPath)(path, nm),
292
+ type: "binding",
293
+ kind: "parameter",
294
+ at: (0, import_utils5.getRange)(n),
295
+ props: { has_default }
296
+ });
297
+ }
298
+ }
299
+ result.push(convert(capture(body), path));
300
+ }
301
+ return result;
302
+ };
303
+ var function_default2 = functionHandler;
304
+
305
+ // src/convert.ts
306
+ var convertConfig = {
307
+ // binding
308
+ "module.binding": module_default2,
309
+ variable: variable_default2,
310
+ // scope
311
+ class: class_default2,
312
+ function: function_default2
313
+ };
314
+
315
+ // src/handlers/utility/reference.ts
316
+ function referenceHandler(node) {
317
+ const captured = utility.get("reference").captures(node, { startIndex: node.startIndex, endIndex: node.endIndex }).flatMap((c) => c.node);
318
+ return captured;
319
+ }
320
+ var reference_default2 = referenceHandler;
321
+
322
+ // src/index.ts
323
+ var descriptor = {
324
+ language,
325
+ extensions: [".py", "/__init__.py"],
326
+ query,
327
+ captureConfig,
328
+ convertConfig,
329
+ references: reference_default2
330
+ };
331
+ var index_default = descriptor;
332
+ // Annotate the CommonJS export names for ESM import in node:
333
+ 0 && (module.exports = {
334
+ descriptor
335
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,298 @@
1
+ // src/query.ts
2
+ import { QueryMap } from "letant/query";
3
+ import Python from "tree-sitter-python";
4
+
5
+ // src/queries/binding/module.scm
6
+ var module_default = "(import_statement name: (dotted_name) @source @name) (import_statement name: (aliased_import name: (dotted_name) @source alias: (identifier) @alias)) (import_from_statement module_name: [ (dotted_name) (relative_import) ] @source name: (dotted_name) @name) (import_from_statement module_name: [ (dotted_name) (relative_import) ] @source name: (aliased_import name: (dotted_name) @name alias: (identifier) @alias))";
7
+
8
+ // src/queries/binding/variable.scm
9
+ var variable_default = "(expression_statement (assignment left: [ (identifier) (pattern_list) (tuple_pattern) ] @name) ) @node (for_statement left: [ (identifier) (pattern_list) (tuple_pattern) ] @name ) @node";
10
+
11
+ // src/queries/scope/class.scm
12
+ var class_default = "(class_definition name: (identifier) @name superclasses: (argument_list)? @extends body: (block) @body ) @node";
13
+
14
+ // src/queries/scope/function.scm
15
+ var function_default = "(function_definition name: (identifier) @name body: (block) @body ) @node";
16
+
17
+ // src/queries/utility/reference.scm
18
+ var reference_default = "(identifier) @reference";
19
+
20
+ // src/query.ts
21
+ var language = Python;
22
+ var query = new QueryMap(language).set("module.binding", module_default).set("variable", variable_default).set("class", class_default).set("function", function_default);
23
+ var utility = new QueryMap(language).set(
24
+ "reference",
25
+ reference_default
26
+ );
27
+
28
+ // src/handlers/bypass/compound.ts
29
+ var COMPOUND = /* @__PURE__ */ new Set([
30
+ "if_statement",
31
+ "elif_clause",
32
+ "else_clause",
33
+ "for_statement",
34
+ "while_statement",
35
+ "try_statement",
36
+ "except_clause",
37
+ "finally_clause",
38
+ "with_statement",
39
+ "match_statement",
40
+ "case_clause"
41
+ ]);
42
+ function bypassCompound(queryKey) {
43
+ const blocks = (node) => node.namedChildren.flatMap((child) => {
44
+ if (child.type === "block") return [child];
45
+ if (COMPOUND.has(child.type)) return blocks(child);
46
+ return [];
47
+ });
48
+ const run = (node) => {
49
+ const matches = [];
50
+ for (const child of node.namedChildren) {
51
+ if (child.type === "decorated_definition") {
52
+ const definition = child.childForFieldName("definition");
53
+ if (definition) {
54
+ matches.push(
55
+ ...query.match(queryKey, definition, { maxStartDepth: 0 })
56
+ );
57
+ }
58
+ continue;
59
+ }
60
+ if (!COMPOUND.has(child.type)) continue;
61
+ for (const block of blocks(child)) {
62
+ matches.push(...query.match(queryKey, block, { maxStartDepth: 1 }));
63
+ matches.push(...run(block));
64
+ }
65
+ }
66
+ return matches;
67
+ };
68
+ return run;
69
+ }
70
+ var compound_default = bypassCompound;
71
+
72
+ // src/capture.ts
73
+ var captureConfig = {
74
+ "module.binding": {
75
+ bypass: compound_default("module.binding")
76
+ },
77
+ variable: {
78
+ bypass: compound_default("variable")
79
+ },
80
+ class: {
81
+ bypass: compound_default("class")
82
+ },
83
+ function: {
84
+ bypass: compound_default("function")
85
+ }
86
+ };
87
+
88
+ // src/handlers/binding/module.ts
89
+ import { NodeSource } from "letant/utils";
90
+ import { createChildPath, createConvertResult } from "letant/utils";
91
+
92
+ // src/handlers/utility/module-path.ts
93
+ function toModulePath(source) {
94
+ if (!source.startsWith(".")) return source;
95
+ const dots = /^\.+/.exec(source)[0].length;
96
+ const rest = source.slice(dots).replace(/\./g, "/");
97
+ const prefix = dots === 1 ? "./" : "../".repeat(dots - 1);
98
+ return rest ? prefix + rest : prefix;
99
+ }
100
+ var module_path_default = toModulePath;
101
+
102
+ // src/handlers/binding/module.ts
103
+ var moduleBindingHandler = (captures, parent) => {
104
+ const result = createConvertResult();
105
+ for (const c of captures) {
106
+ const { source, name, alias } = c;
107
+ const plain = !!name && !alias && source.text === name.text;
108
+ const representative = alias?.text ?? (plain ? source.text.split(".")[0] : name?.text);
109
+ if (!representative) continue;
110
+ let modulePath = module_path_default(plain ? representative : source.text);
111
+ if (modulePath.endsWith("/") && name) {
112
+ modulePath += name.text;
113
+ }
114
+ result.nodes.push({
115
+ path: createChildPath(parent, representative),
116
+ type: "binding",
117
+ kind: "module",
118
+ at: NodeSource(modulePath),
119
+ props: alias ? { alias_of: (name ?? source).text } : void 0
120
+ });
121
+ }
122
+ return result;
123
+ };
124
+ var module_default2 = moduleBindingHandler;
125
+
126
+ // src/handlers/binding/variable.ts
127
+ import { createChildPath as createChildPath2, createConvertResult as createConvertResult2, getRange } from "letant/utils";
128
+
129
+ // src/handlers/utility/pattern.ts
130
+ var dispatcher = {
131
+ // terminate condition of recursion
132
+ identifier: (node) => [{ name: node.text, node }],
133
+ // recurse over single element
134
+ list_splat_pattern: (node) => flatPattern(node.firstNamedChild),
135
+ // recurse over multiple elements
136
+ pattern_list: (node) => node.namedChildren.flatMap((c) => flatPattern(c)),
137
+ tuple_pattern: (node) => node.namedChildren.flatMap((c) => flatPattern(c)),
138
+ list_pattern: (node) => node.namedChildren.flatMap((c) => flatPattern(c))
139
+ };
140
+ function flatPattern(node) {
141
+ if (!dispatcher[node.type]) {
142
+ return [];
143
+ }
144
+ return dispatcher[node.type](node);
145
+ }
146
+ var pattern_default = flatPattern;
147
+
148
+ // src/handlers/binding/variable.ts
149
+ var variableHandler = (captures, parent) => {
150
+ const result = createConvertResult2();
151
+ for (const c of captures) {
152
+ const { node, name } = c;
153
+ for (const { name: nm, node: n } of pattern_default(name)) {
154
+ const path = createChildPath2(parent, nm);
155
+ result.nodes.push({
156
+ path,
157
+ type: "binding",
158
+ kind: "variable",
159
+ at: getRange(name.type === "identifier" ? node : n)
160
+ });
161
+ }
162
+ }
163
+ return result;
164
+ };
165
+ var variable_default2 = variableHandler;
166
+
167
+ // src/handlers/scope/class.ts
168
+ import { createChildPath as createChildPath3, createConvertResult as createConvertResult3, getRange as getRange2 } from "letant/utils";
169
+ var classHandler = (captures, parent, { capture, convert }) => {
170
+ const result = createConvertResult3();
171
+ for (const c of captures) {
172
+ const { node, name, extends: ext, body } = c;
173
+ const path = createChildPath3(parent, name.text);
174
+ result.nodes.push({
175
+ path,
176
+ type: "scope",
177
+ kind: "class",
178
+ at: getRange2(node),
179
+ blockStartIndex: body.startIndex,
180
+ props: {
181
+ extends: ext?.text
182
+ }
183
+ });
184
+ result.push(convert(capture(body), path));
185
+ }
186
+ return result;
187
+ };
188
+ var class_default2 = classHandler;
189
+
190
+ // src/handlers/scope/function.ts
191
+ import { createChildPath as createChildPath4, createConvertResult as createConvertResult4, getRange as getRange3 } from "letant/utils";
192
+
193
+ // src/handlers/utility/parameter.ts
194
+ function flatParameters(parameters) {
195
+ const result = [];
196
+ for (const child of parameters.namedChildren) {
197
+ switch (child.type) {
198
+ case "identifier":
199
+ result.push({ name: child.text, node: child, has_default: false });
200
+ break;
201
+ case "typed_parameter": {
202
+ const inner = child.firstNamedChild;
203
+ if (inner?.type === "identifier") {
204
+ result.push({ name: inner.text, node: child, has_default: false });
205
+ }
206
+ break;
207
+ }
208
+ case "default_parameter":
209
+ case "typed_default_parameter": {
210
+ const name = child.childForFieldName("name");
211
+ if (name?.type === "identifier") {
212
+ result.push({ name: name.text, node: child, has_default: true });
213
+ }
214
+ break;
215
+ }
216
+ case "list_splat_pattern":
217
+ case "dictionary_splat_pattern": {
218
+ const inner = child.firstNamedChild;
219
+ if (inner?.type === "identifier") {
220
+ result.push({ name: inner.text, node: child, has_default: false });
221
+ }
222
+ break;
223
+ }
224
+ default:
225
+ break;
226
+ }
227
+ }
228
+ return result;
229
+ }
230
+ var parameter_default = flatParameters;
231
+
232
+ // src/handlers/scope/function.ts
233
+ var functionHandler = (captures, parent, { capture, convert }) => {
234
+ const result = createConvertResult4();
235
+ for (const c of captures) {
236
+ const { node, name, body } = c;
237
+ const path = createChildPath4(parent, name.text);
238
+ result.nodes.push({
239
+ path,
240
+ type: "scope",
241
+ kind: "function",
242
+ at: getRange3(node),
243
+ blockStartIndex: body.startIndex,
244
+ props: {
245
+ is_async: node.children.some((child) => child.type === "async")
246
+ }
247
+ });
248
+ const parameters = node.childForFieldName("parameters");
249
+ if (parameters) {
250
+ for (const { name: nm, node: n, has_default } of parameter_default(
251
+ parameters
252
+ )) {
253
+ result.nodes.push({
254
+ path: createChildPath4(path, nm),
255
+ type: "binding",
256
+ kind: "parameter",
257
+ at: getRange3(n),
258
+ props: { has_default }
259
+ });
260
+ }
261
+ }
262
+ result.push(convert(capture(body), path));
263
+ }
264
+ return result;
265
+ };
266
+ var function_default2 = functionHandler;
267
+
268
+ // src/convert.ts
269
+ var convertConfig = {
270
+ // binding
271
+ "module.binding": module_default2,
272
+ variable: variable_default2,
273
+ // scope
274
+ class: class_default2,
275
+ function: function_default2
276
+ };
277
+
278
+ // src/handlers/utility/reference.ts
279
+ function referenceHandler(node) {
280
+ const captured = utility.get("reference").captures(node, { startIndex: node.startIndex, endIndex: node.endIndex }).flatMap((c) => c.node);
281
+ return captured;
282
+ }
283
+ var reference_default2 = referenceHandler;
284
+
285
+ // src/index.ts
286
+ var descriptor = {
287
+ language,
288
+ extensions: [".py", "/__init__.py"],
289
+ query,
290
+ captureConfig,
291
+ convertConfig,
292
+ references: reference_default2
293
+ };
294
+ var index_default = descriptor;
295
+ export {
296
+ index_default as default,
297
+ descriptor
298
+ };
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@letant/python",
3
+ "version": "0.0.3",
4
+ "description": "Python plugin for letant",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "exports": {
12
+ ".": {
13
+ "import": {
14
+ "types": "./dist/index.d.mts",
15
+ "default": "./dist/index.mjs"
16
+ },
17
+ "require": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ }
21
+ }
22
+ },
23
+ "keywords": [],
24
+ "author": "Juun",
25
+ "license": "MIT",
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "engines": {
30
+ "node": "^22.13.0 || >=24"
31
+ },
32
+ "peerDependencies": {
33
+ "letant": "^0.0.5",
34
+ "tree-sitter-python": "^0.25.0"
35
+ },
36
+ "devDependencies": {
37
+ "@arethetypeswrong/cli": "^0.18.5",
38
+ "@types/node": "^26.1.1",
39
+ "letant": "0.0.5",
40
+ "tree-sitter-python": "^0.25.0",
41
+ "tsup": "^8.5.1",
42
+ "typescript": "^6.0.3"
43
+ },
44
+ "scripts": {
45
+ "attw": "attw --pack --ignore-rules 'no-resolution'",
46
+ "attw:quiet": "attw --pack --quiet --ignore-rules 'no-resolution'",
47
+ "build": "tsup",
48
+ "check-types": "tsc -p ./tsconfig.json --noEmit",
49
+ "dev": "tsup --watch",
50
+ "dev:query": "pnpm letant query --grammar tree-sitter-python"
51
+ }
52
+ }