@generaltranslation/python-extractor 0.2.20 → 0.2.21
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/dist/constants.js +22 -17
- package/dist/constants.js.map +1 -0
- package/dist/extractCalls.js +188 -271
- package/dist/extractCalls.js.map +1 -0
- package/dist/extractImports.js +61 -76
- package/dist/extractImports.js.map +1 -0
- package/dist/index.js +50 -52
- package/dist/index.js.map +1 -0
- package/dist/parseStringExpression.js +722 -983
- package/dist/parseStringExpression.js.map +1 -0
- package/dist/parser.js +30 -37
- package/dist/parser.js.map +1 -0
- package/dist/resolveFunctionVariants.js +154 -181
- package/dist/resolveFunctionVariants.js.map +1 -0
- package/dist/resolveImport.js +48 -60
- package/dist/resolveImport.js.map +1 -0
- package/dist/stringNode.js +32 -46
- package/dist/stringNode.js.map +1 -0
- package/package.json +7 -4
package/dist/resolveImport.js
CHANGED
|
@@ -1,68 +1,56 @@
|
|
|
1
|
-
import fs from
|
|
2
|
-
import path from
|
|
3
|
-
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
//#region src/resolveImport.ts
|
|
4
|
+
const resolveCache = /* @__PURE__ */ new Map();
|
|
4
5
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
resolveCache.set(cacheKey, result);
|
|
20
|
-
return result;
|
|
6
|
+
* Resolves a Python import module path to a file path on disk.
|
|
7
|
+
*
|
|
8
|
+
* Handles:
|
|
9
|
+
* - Relative imports: `.helpers` → sibling `helpers.py`
|
|
10
|
+
* - Parent relative imports: `..utils` → parent dir `utils.py`
|
|
11
|
+
* - Absolute imports: `utils` → `utils.py` in same/parent dirs
|
|
12
|
+
* - Dotted paths: `myapp.utils` → `myapp/utils.py`
|
|
13
|
+
*/
|
|
14
|
+
function resolveImportPath(moduleName, currentFilePath) {
|
|
15
|
+
const cacheKey = `${currentFilePath}::${moduleName}`;
|
|
16
|
+
if (resolveCache.has(cacheKey)) return resolveCache.get(cacheKey);
|
|
17
|
+
const result = doResolve(moduleName, currentFilePath);
|
|
18
|
+
resolveCache.set(cacheKey, result);
|
|
19
|
+
return result;
|
|
21
20
|
}
|
|
22
21
|
function doResolve(moduleName, currentFilePath) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// Bare dot import (e.g., "from . import X") — resolve to __init__.py
|
|
39
|
-
const initPath = path.join(baseDir, '__init__.py');
|
|
40
|
-
if (fs.existsSync(initPath))
|
|
41
|
-
return initPath;
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
return resolveModulePath(baseDir, remainder);
|
|
45
|
-
}
|
|
46
|
-
// Absolute import: dotted or simple name
|
|
47
|
-
return resolveModulePath(currentDir, moduleName);
|
|
22
|
+
const currentDir = path.dirname(currentFilePath);
|
|
23
|
+
if (moduleName.startsWith(".")) {
|
|
24
|
+
let dotCount = 0;
|
|
25
|
+
while (dotCount < moduleName.length && moduleName[dotCount] === ".") dotCount++;
|
|
26
|
+
let baseDir = currentDir;
|
|
27
|
+
for (let i = 1; i < dotCount; i++) baseDir = path.dirname(baseDir);
|
|
28
|
+
const remainder = moduleName.slice(dotCount);
|
|
29
|
+
if (!remainder) {
|
|
30
|
+
const initPath = path.join(baseDir, "__init__.py");
|
|
31
|
+
if (fs.existsSync(initPath)) return initPath;
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return resolveModulePath(baseDir, remainder);
|
|
35
|
+
}
|
|
36
|
+
return resolveModulePath(currentDir, moduleName);
|
|
48
37
|
}
|
|
49
38
|
/**
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
39
|
+
* Resolves a dotted module name (e.g. "myapp.utils") relative to a base dir.
|
|
40
|
+
* Tries: baseDir/myapp/utils.py, then baseDir/myapp/utils/__init__.py
|
|
41
|
+
*/
|
|
53
42
|
function resolveModulePath(baseDir, moduleName) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const initPath = path.join(baseDir, ...parts, '__init__.py');
|
|
61
|
-
if (fs.existsSync(initPath)) {
|
|
62
|
-
return initPath;
|
|
63
|
-
}
|
|
64
|
-
return null;
|
|
43
|
+
const parts = moduleName.split(".");
|
|
44
|
+
const filePath = path.join(baseDir, ...parts) + ".py";
|
|
45
|
+
if (fs.existsSync(filePath)) return filePath;
|
|
46
|
+
const initPath = path.join(baseDir, ...parts, "__init__.py");
|
|
47
|
+
if (fs.existsSync(initPath)) return initPath;
|
|
48
|
+
return null;
|
|
65
49
|
}
|
|
66
|
-
|
|
67
|
-
|
|
50
|
+
function clearResolveCache() {
|
|
51
|
+
resolveCache.clear();
|
|
68
52
|
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { clearResolveCache, resolveImportPath };
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=resolveImport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveImport.js","names":[],"sources":["../src/resolveImport.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nconst resolveCache = new Map<string, string | null>();\n\n/**\n * Resolves a Python import module path to a file path on disk.\n *\n * Handles:\n * - Relative imports: `.helpers` → sibling `helpers.py`\n * - Parent relative imports: `..utils` → parent dir `utils.py`\n * - Absolute imports: `utils` → `utils.py` in same/parent dirs\n * - Dotted paths: `myapp.utils` → `myapp/utils.py`\n */\nexport function resolveImportPath(\n moduleName: string,\n currentFilePath: string\n): string | null {\n const cacheKey = `${currentFilePath}::${moduleName}`;\n if (resolveCache.has(cacheKey)) {\n return resolveCache.get(cacheKey)!;\n }\n\n const result = doResolve(moduleName, currentFilePath);\n resolveCache.set(cacheKey, result);\n return result;\n}\n\nfunction doResolve(moduleName: string, currentFilePath: string): string | null {\n const currentDir = path.dirname(currentFilePath);\n\n // Relative import: starts with dots\n if (moduleName.startsWith('.')) {\n // Count leading dots\n let dotCount = 0;\n while (dotCount < moduleName.length && moduleName[dotCount] === '.') {\n dotCount++;\n }\n\n // Go up (dotCount - 1) directories from current dir\n let baseDir = currentDir;\n for (let i = 1; i < dotCount; i++) {\n baseDir = path.dirname(baseDir);\n }\n\n const remainder = moduleName.slice(dotCount);\n if (!remainder) {\n // Bare dot import (e.g., \"from . import X\") — resolve to __init__.py\n const initPath = path.join(baseDir, '__init__.py');\n if (fs.existsSync(initPath)) return initPath;\n return null;\n }\n\n return resolveModulePath(baseDir, remainder);\n }\n\n // Absolute import: dotted or simple name\n return resolveModulePath(currentDir, moduleName);\n}\n\n/**\n * Resolves a dotted module name (e.g. \"myapp.utils\") relative to a base dir.\n * Tries: baseDir/myapp/utils.py, then baseDir/myapp/utils/__init__.py\n */\nfunction resolveModulePath(baseDir: string, moduleName: string): string | null {\n const parts = moduleName.split('.');\n const filePath = path.join(baseDir, ...parts) + '.py';\n\n if (fs.existsSync(filePath)) {\n return filePath;\n }\n\n // Try as package: moduleName/__init__.py\n const initPath = path.join(baseDir, ...parts, '__init__.py');\n if (fs.existsSync(initPath)) {\n return initPath;\n }\n\n return null;\n}\n\nexport function clearResolveCache(): void {\n resolveCache.clear();\n}\n"],"mappings":";;;AAGA,MAAM,+BAAe,IAAI,KAA4B;;;;;;;;;;AAWrD,SAAgB,kBACd,YACA,iBACe;CACf,MAAM,WAAW,GAAG,gBAAgB,IAAI;AACxC,KAAI,aAAa,IAAI,SAAS,CAC5B,QAAO,aAAa,IAAI,SAAS;CAGnC,MAAM,SAAS,UAAU,YAAY,gBAAgB;AACrD,cAAa,IAAI,UAAU,OAAO;AAClC,QAAO;;AAGT,SAAS,UAAU,YAAoB,iBAAwC;CAC7E,MAAM,aAAa,KAAK,QAAQ,gBAAgB;AAGhD,KAAI,WAAW,WAAW,IAAI,EAAE;EAE9B,IAAI,WAAW;AACf,SAAO,WAAW,WAAW,UAAU,WAAW,cAAc,IAC9D;EAIF,IAAI,UAAU;AACd,OAAK,IAAI,IAAI,GAAG,IAAI,UAAU,IAC5B,WAAU,KAAK,QAAQ,QAAQ;EAGjC,MAAM,YAAY,WAAW,MAAM,SAAS;AAC5C,MAAI,CAAC,WAAW;GAEd,MAAM,WAAW,KAAK,KAAK,SAAS,cAAc;AAClD,OAAI,GAAG,WAAW,SAAS,CAAE,QAAO;AACpC,UAAO;;AAGT,SAAO,kBAAkB,SAAS,UAAU;;AAI9C,QAAO,kBAAkB,YAAY,WAAW;;;;;;AAOlD,SAAS,kBAAkB,SAAiB,YAAmC;CAC7E,MAAM,QAAQ,WAAW,MAAM,IAAI;CACnC,MAAM,WAAW,KAAK,KAAK,SAAS,GAAG,MAAM,GAAG;AAEhD,KAAI,GAAG,WAAW,SAAS,CACzB,QAAO;CAIT,MAAM,WAAW,KAAK,KAAK,SAAS,GAAG,OAAO,cAAc;AAC5D,KAAI,GAAG,WAAW,SAAS,CACzB,QAAO;AAGT,QAAO;;AAGT,SAAgB,oBAA0B;AACxC,cAAa,OAAO"}
|
package/dist/stringNode.js
CHANGED
|
@@ -1,51 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
// Used for derive / declare_var parsing
|
|
1
|
+
//#region src/stringNode.ts
|
|
3
2
|
/**
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
if (node.type === 'choice') {
|
|
21
|
-
const allStrings = [];
|
|
22
|
-
for (const branch of node.nodes) {
|
|
23
|
-
allStrings.push(...nodeToStrings(branch));
|
|
24
|
-
}
|
|
25
|
-
return [...new Set(allStrings)]; // Deduplicate
|
|
26
|
-
}
|
|
27
|
-
return [];
|
|
3
|
+
* Converts a StringNode tree into all possible string variants.
|
|
4
|
+
* - TextNode → single string
|
|
5
|
+
* - SequenceNode → cartesian product of all parts
|
|
6
|
+
* - ChoiceNode → flattened branches (deduplicated)
|
|
7
|
+
*/
|
|
8
|
+
function nodeToStrings(node) {
|
|
9
|
+
if (node === null) return [];
|
|
10
|
+
if (node.type === "text") return [node.text];
|
|
11
|
+
if (node.type === "sequence") return cartesianProduct(node.nodes.map((n) => nodeToStrings(n)));
|
|
12
|
+
if (node.type === "choice") {
|
|
13
|
+
const allStrings = [];
|
|
14
|
+
for (const branch of node.nodes) allStrings.push(...nodeToStrings(branch));
|
|
15
|
+
return [...new Set(allStrings)];
|
|
16
|
+
}
|
|
17
|
+
return [];
|
|
28
18
|
}
|
|
29
19
|
/**
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
20
|
+
* Creates cartesian product of string arrays and concatenates them.
|
|
21
|
+
* @example cartesianProduct([["Hello "], ["day", "night"]]) → ["Hello day", "Hello night"]
|
|
22
|
+
*/
|
|
33
23
|
function cartesianProduct(arrays) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
for (const prev of result) {
|
|
44
|
-
for (const curr of arrays[i]) {
|
|
45
|
-
newResult.push(prev + curr);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
result = newResult;
|
|
49
|
-
}
|
|
50
|
-
return result;
|
|
24
|
+
if (arrays.length === 0) return [];
|
|
25
|
+
if (arrays.length === 1) return arrays[0];
|
|
26
|
+
let result = arrays[0];
|
|
27
|
+
for (let i = 1; i < arrays.length; i++) {
|
|
28
|
+
const newResult = [];
|
|
29
|
+
for (const prev of result) for (const curr of arrays[i]) newResult.push(prev + curr);
|
|
30
|
+
result = newResult;
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
51
33
|
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { nodeToStrings };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=stringNode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stringNode.js","names":[],"sources":["../src/stringNode.ts"],"sourcesContent":["// ===== Tree Construction ===== //\n// Used for derive / declare_var parsing\n\ntype StringNode = StringTextNode | StringSequenceNode | StringChoiceNode;\n\ntype StringTextNode = {\n type: 'text';\n text: string;\n};\n\ntype StringSequenceNode = {\n type: 'sequence';\n nodes: StringNode[];\n};\n\ntype StringChoiceNode = {\n type: 'choice';\n nodes: StringNode[];\n};\n\nexport type {\n StringNode,\n StringTextNode,\n StringSequenceNode,\n StringChoiceNode,\n};\n\n/**\n * Converts a StringNode tree into all possible string variants.\n * - TextNode → single string\n * - SequenceNode → cartesian product of all parts\n * - ChoiceNode → flattened branches (deduplicated)\n */\nexport function nodeToStrings(node: StringNode | null): string[] {\n if (node === null) {\n return [];\n }\n\n if (node.type === 'text') {\n return [node.text];\n }\n\n if (node.type === 'sequence') {\n const partResults: string[][] = node.nodes.map((n) => nodeToStrings(n));\n return cartesianProduct(partResults);\n }\n\n if (node.type === 'choice') {\n const allStrings: string[] = [];\n for (const branch of node.nodes) {\n allStrings.push(...nodeToStrings(branch));\n }\n return [...new Set(allStrings)]; // Deduplicate\n }\n\n return [];\n}\n\n/**\n * Creates cartesian product of string arrays and concatenates them.\n * @example cartesianProduct([[\"Hello \"], [\"day\", \"night\"]]) → [\"Hello day\", \"Hello night\"]\n */\nfunction cartesianProduct(arrays: string[][]): string[] {\n if (arrays.length === 0) {\n return [];\n }\n\n if (arrays.length === 1) {\n return arrays[0];\n }\n\n let result = arrays[0];\n\n for (let i = 1; i < arrays.length; i++) {\n const newResult: string[] = [];\n for (const prev of result) {\n for (const curr of arrays[i]) {\n newResult.push(prev + curr);\n }\n }\n result = newResult;\n }\n\n return result;\n}\n"],"mappings":";;;;;;;AAiCA,SAAgB,cAAc,MAAmC;AAC/D,KAAI,SAAS,KACX,QAAO,EAAE;AAGX,KAAI,KAAK,SAAS,OAChB,QAAO,CAAC,KAAK,KAAK;AAGpB,KAAI,KAAK,SAAS,WAEhB,QAAO,iBADyB,KAAK,MAAM,KAAK,MAAM,cAAc,EAAE,CACnC,CAAC;AAGtC,KAAI,KAAK,SAAS,UAAU;EAC1B,MAAM,aAAuB,EAAE;AAC/B,OAAK,MAAM,UAAU,KAAK,MACxB,YAAW,KAAK,GAAG,cAAc,OAAO,CAAC;AAE3C,SAAO,CAAC,GAAG,IAAI,IAAI,WAAW,CAAC;;AAGjC,QAAO,EAAE;;;;;;AAOX,SAAS,iBAAiB,QAA8B;AACtD,KAAI,OAAO,WAAW,EACpB,QAAO,EAAE;AAGX,KAAI,OAAO,WAAW,EACpB,QAAO,OAAO;CAGhB,IAAI,SAAS,OAAO;AAEpB,MAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACtC,MAAM,YAAsB,EAAE;AAC9B,OAAK,MAAM,QAAQ,OACjB,MAAK,MAAM,QAAQ,OAAO,GACxB,WAAU,KAAK,OAAO,KAAK;AAG/B,WAAS;;AAGX,QAAO"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@generaltranslation/python-extractor",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.21",
|
|
4
4
|
"description": "Python source code extraction for General Translation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
],
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^22.13.5",
|
|
41
|
+
"tsdown": "^0.21.10",
|
|
41
42
|
"typescript": "^5.9.2",
|
|
42
43
|
"vitest": "^3.2.4"
|
|
43
44
|
},
|
|
@@ -47,11 +48,13 @@
|
|
|
47
48
|
"dependencies": {
|
|
48
49
|
"tree-sitter-python": "^0.25.0",
|
|
49
50
|
"web-tree-sitter": "^0.26.6",
|
|
50
|
-
"generaltranslation": "8.2.
|
|
51
|
+
"generaltranslation": "8.2.15"
|
|
51
52
|
},
|
|
52
53
|
"scripts": {
|
|
53
|
-
"
|
|
54
|
-
"
|
|
54
|
+
"emit-types": "sh ../../scripts/emit-types.sh",
|
|
55
|
+
"transpile": "tsdown && pnpm run emit-types",
|
|
56
|
+
"build": "pnpm run transpile",
|
|
57
|
+
"build:watch": "tsdown --watch",
|
|
55
58
|
"build:clean": "sh ../../scripts/clean.sh && pnpm run build",
|
|
56
59
|
"build:release": "pnpm run build:clean",
|
|
57
60
|
"format": "oxfmt src",
|