python2ts 1.3.1 → 1.3.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/dist/{chunk-LNOL3BMB.js → chunk-TBFKEIAB.js} +152 -23
- package/dist/cli/index.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
|
@@ -262,6 +262,71 @@ function toJsName(pythonName) {
|
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
// src/transformer/index.ts
|
|
265
|
+
var JS_RESERVED_KEYWORDS = /* @__PURE__ */ new Set([
|
|
266
|
+
// ECMAScript reserved words
|
|
267
|
+
"break",
|
|
268
|
+
"case",
|
|
269
|
+
"catch",
|
|
270
|
+
"continue",
|
|
271
|
+
"debugger",
|
|
272
|
+
"default",
|
|
273
|
+
"delete",
|
|
274
|
+
"do",
|
|
275
|
+
"else",
|
|
276
|
+
"finally",
|
|
277
|
+
"for",
|
|
278
|
+
"function",
|
|
279
|
+
"if",
|
|
280
|
+
"in",
|
|
281
|
+
"instanceof",
|
|
282
|
+
"new",
|
|
283
|
+
"return",
|
|
284
|
+
"switch",
|
|
285
|
+
"this",
|
|
286
|
+
"throw",
|
|
287
|
+
"try",
|
|
288
|
+
"typeof",
|
|
289
|
+
"var",
|
|
290
|
+
"void",
|
|
291
|
+
"while",
|
|
292
|
+
"with",
|
|
293
|
+
// ECMAScript 6+ reserved words
|
|
294
|
+
"class",
|
|
295
|
+
"const",
|
|
296
|
+
"enum",
|
|
297
|
+
"export",
|
|
298
|
+
"extends",
|
|
299
|
+
"import",
|
|
300
|
+
// Note: 'super' is intentionally NOT in this list as it's valid in JS class contexts
|
|
301
|
+
// Strict mode reserved words
|
|
302
|
+
"implements",
|
|
303
|
+
"interface",
|
|
304
|
+
"let",
|
|
305
|
+
"package",
|
|
306
|
+
"private",
|
|
307
|
+
"protected",
|
|
308
|
+
"public",
|
|
309
|
+
"static",
|
|
310
|
+
"yield",
|
|
311
|
+
// TypeScript reserved words
|
|
312
|
+
"abstract",
|
|
313
|
+
"as",
|
|
314
|
+
"async",
|
|
315
|
+
"await",
|
|
316
|
+
"declare",
|
|
317
|
+
"from",
|
|
318
|
+
"get",
|
|
319
|
+
"is",
|
|
320
|
+
"module",
|
|
321
|
+
"namespace",
|
|
322
|
+
"of",
|
|
323
|
+
"require",
|
|
324
|
+
"set",
|
|
325
|
+
"type"
|
|
326
|
+
]);
|
|
327
|
+
function escapeReservedKeyword(name) {
|
|
328
|
+
return JS_RESERVED_KEYWORDS.has(name) ? `_${name}` : name;
|
|
329
|
+
}
|
|
265
330
|
function createContext(source) {
|
|
266
331
|
return {
|
|
267
332
|
source,
|
|
@@ -521,13 +586,23 @@ function isDocstringNode(node, ctx) {
|
|
|
521
586
|
const firstChild = children[0];
|
|
522
587
|
if (firstChild?.name !== "String") return false;
|
|
523
588
|
const text = getNodeText(firstChild, ctx.source);
|
|
524
|
-
return
|
|
589
|
+
return isTripleQuotedString(text);
|
|
590
|
+
}
|
|
591
|
+
function isTripleQuotedString(text) {
|
|
592
|
+
let stripped = text;
|
|
593
|
+
if (/^[rRuU]/.test(text)) {
|
|
594
|
+
stripped = text.slice(1);
|
|
595
|
+
}
|
|
596
|
+
return stripped.startsWith('"""') || stripped.startsWith("'''");
|
|
525
597
|
}
|
|
526
598
|
function extractDocstringContent(node, ctx) {
|
|
527
599
|
const children = getChildren(node);
|
|
528
600
|
const stringNode = children[0];
|
|
529
601
|
if (!stringNode) return "";
|
|
530
|
-
|
|
602
|
+
let text = getNodeText(stringNode, ctx.source);
|
|
603
|
+
if (/^[rRuU]/.test(text)) {
|
|
604
|
+
text = text.slice(1);
|
|
605
|
+
}
|
|
531
606
|
let content = text;
|
|
532
607
|
if (content.startsWith('"""')) {
|
|
533
608
|
content = content.slice(3, -3);
|
|
@@ -737,7 +812,7 @@ function transformNode(node, ctx) {
|
|
|
737
812
|
case "None":
|
|
738
813
|
return "null";
|
|
739
814
|
case "VariableName":
|
|
740
|
-
return getNodeText(node, ctx.source);
|
|
815
|
+
return escapeReservedKeyword(getNodeText(node, ctx.source));
|
|
741
816
|
case "CallExpression":
|
|
742
817
|
return transformCallExpression(node, ctx);
|
|
743
818
|
case "MemberExpression":
|
|
@@ -802,6 +877,9 @@ function transformNode(node, ctx) {
|
|
|
802
877
|
return transformAssertStatement(node, ctx);
|
|
803
878
|
case "YieldStatement":
|
|
804
879
|
return transformYieldStatement(node, ctx);
|
|
880
|
+
case "Ellipsis":
|
|
881
|
+
ctx.usesRuntime.add("Ellipsis");
|
|
882
|
+
return "Ellipsis";
|
|
805
883
|
/* v8 ignore next 2 -- fallback for unknown AST nodes @preserve */
|
|
806
884
|
default:
|
|
807
885
|
return getNodeText(node, ctx.source);
|
|
@@ -809,7 +887,22 @@ function transformNode(node, ctx) {
|
|
|
809
887
|
}
|
|
810
888
|
function transformScript(node, ctx) {
|
|
811
889
|
const children = getChildren(node);
|
|
812
|
-
|
|
890
|
+
let moduleDocstring = "";
|
|
891
|
+
let startIndex = 0;
|
|
892
|
+
const filteredChildren = children.filter(
|
|
893
|
+
(child) => child.name !== "Comment" || getNodeText(child, ctx.source).trim() !== ""
|
|
894
|
+
);
|
|
895
|
+
if (filteredChildren.length > 1) {
|
|
896
|
+
const firstChild = filteredChildren[0];
|
|
897
|
+
if (firstChild && isDocstringNode(firstChild, ctx)) {
|
|
898
|
+
const content = extractDocstringContent(firstChild, ctx);
|
|
899
|
+
const parsed = parseDocstring(content);
|
|
900
|
+
const jsdoc = toJSDoc(parsed, "");
|
|
901
|
+
moduleDocstring = jsdoc.replace(" */", " * @module\n */");
|
|
902
|
+
startIndex = 1;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
const statements = filteredChildren.slice(startIndex).map((child) => {
|
|
813
906
|
const transformed = transformNode(child, ctx);
|
|
814
907
|
if (transformed === "") {
|
|
815
908
|
return "";
|
|
@@ -819,6 +912,9 @@ function transformScript(node, ctx) {
|
|
|
819
912
|
}
|
|
820
913
|
return transformed;
|
|
821
914
|
}).filter((s) => s.trim() !== "");
|
|
915
|
+
if (moduleDocstring) {
|
|
916
|
+
return moduleDocstring + "\n" + statements.join("\n");
|
|
917
|
+
}
|
|
822
918
|
return statements.join("\n");
|
|
823
919
|
}
|
|
824
920
|
function transformExpressionStatement(node, ctx) {
|
|
@@ -1302,9 +1398,26 @@ function transformCallExpression(node, ctx) {
|
|
|
1302
1398
|
case "reversed":
|
|
1303
1399
|
ctx.usesRuntime.add("reversed");
|
|
1304
1400
|
return `reversed(${args})`;
|
|
1305
|
-
case "isinstance":
|
|
1401
|
+
case "isinstance": {
|
|
1306
1402
|
ctx.usesRuntime.add("isinstance");
|
|
1403
|
+
if (argList) {
|
|
1404
|
+
const argChildren = getChildren(argList).filter(
|
|
1405
|
+
(c) => c.name !== "(" && c.name !== ")" && c.name !== ","
|
|
1406
|
+
);
|
|
1407
|
+
if (argChildren.length >= 2) {
|
|
1408
|
+
const firstArg = argChildren[0];
|
|
1409
|
+
const secondArg = argChildren[1];
|
|
1410
|
+
if (firstArg && secondArg?.name === "TupleExpression") {
|
|
1411
|
+
const tupleChildren = getChildren(secondArg).filter(
|
|
1412
|
+
(c) => c.name !== "(" && c.name !== ")" && c.name !== ","
|
|
1413
|
+
);
|
|
1414
|
+
const typesCodes = tupleChildren.map((el) => transformNode(el, ctx));
|
|
1415
|
+
return `isinstance(${transformNode(firstArg, ctx)}, [${typesCodes.join(", ")}])`;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1307
1419
|
return `isinstance(${args})`;
|
|
1420
|
+
}
|
|
1308
1421
|
case "type":
|
|
1309
1422
|
ctx.usesRuntime.add("type");
|
|
1310
1423
|
return `type(${args})`;
|
|
@@ -1804,7 +1917,11 @@ function transformMethodCall(callee, args, ctx) {
|
|
|
1804
1917
|
case "rjust":
|
|
1805
1918
|
return `${objCode}.padStart(${args})`;
|
|
1806
1919
|
// String split/join - join is special: "sep".join(arr) -> arr.join("sep")
|
|
1920
|
+
// If the argument is a generator expression, convert to array with spread
|
|
1807
1921
|
case "join":
|
|
1922
|
+
if (args.includes("function*")) {
|
|
1923
|
+
return `[...${args}].join(${objCode})`;
|
|
1924
|
+
}
|
|
1808
1925
|
return `(${args}).join(${objCode})`;
|
|
1809
1926
|
case "split":
|
|
1810
1927
|
return args ? `${objCode}.split(${args})` : `${objCode}.split(/\\s+/)`;
|
|
@@ -2005,15 +2122,23 @@ function transformMemberExpression(node, ctx) {
|
|
|
2005
2122
|
if (text.includes(":")) {
|
|
2006
2123
|
return transformSliceFromMember(obj, children, ctx);
|
|
2007
2124
|
}
|
|
2008
|
-
const indexElements = children.filter(
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
if (
|
|
2013
|
-
|
|
2014
|
-
return
|
|
2125
|
+
const indexElements = children.filter(
|
|
2126
|
+
(c) => c.name !== "[" && c.name !== "]" && c.name !== "," && c !== obj
|
|
2127
|
+
);
|
|
2128
|
+
if (indexElements.length === 0) return `${objCode}[]`;
|
|
2129
|
+
if (indexElements.length === 1) {
|
|
2130
|
+
const index = indexElements[0];
|
|
2131
|
+
if (!index) return `${objCode}[]`;
|
|
2132
|
+
const indexCode = transformNode(index, ctx);
|
|
2133
|
+
if (isNegativeIndexLiteral(index, ctx)) {
|
|
2134
|
+
ctx.usesRuntime.add("at");
|
|
2135
|
+
return `at(${objCode}, ${indexCode})`;
|
|
2136
|
+
}
|
|
2137
|
+
return `${objCode}[${indexCode}]`;
|
|
2015
2138
|
}
|
|
2016
|
-
|
|
2139
|
+
ctx.usesRuntime.add("tuple");
|
|
2140
|
+
const indices = indexElements.map((el) => transformNode(el, ctx));
|
|
2141
|
+
return `${objCode}[tuple(${indices.join(", ")})]`;
|
|
2017
2142
|
} else {
|
|
2018
2143
|
const prop = children[children.length - 1];
|
|
2019
2144
|
if (!prop) return getNodeText(node, ctx.source);
|
|
@@ -3095,7 +3220,7 @@ function extractParamNames(node, source) {
|
|
|
3095
3220
|
if (child.name === "*" || getNodeText(child, source) === "*") {
|
|
3096
3221
|
const nextChild = children[i + 1];
|
|
3097
3222
|
if (nextChild?.name === "VariableName") {
|
|
3098
|
-
names.push(getNodeText(nextChild, source));
|
|
3223
|
+
names.push(escapeReservedKeyword(getNodeText(nextChild, source)));
|
|
3099
3224
|
i += 2;
|
|
3100
3225
|
continue;
|
|
3101
3226
|
}
|
|
@@ -3105,7 +3230,7 @@ function extractParamNames(node, source) {
|
|
|
3105
3230
|
if (child.name === "**" || getNodeText(child, source) === "**") {
|
|
3106
3231
|
const nextChild = children[i + 1];
|
|
3107
3232
|
if (nextChild?.name === "VariableName") {
|
|
3108
|
-
names.push(getNodeText(nextChild, source));
|
|
3233
|
+
names.push(escapeReservedKeyword(getNodeText(nextChild, source)));
|
|
3109
3234
|
i += 2;
|
|
3110
3235
|
continue;
|
|
3111
3236
|
}
|
|
@@ -3113,7 +3238,7 @@ function extractParamNames(node, source) {
|
|
|
3113
3238
|
continue;
|
|
3114
3239
|
}
|
|
3115
3240
|
if (child.name === "VariableName") {
|
|
3116
|
-
names.push(getNodeText(child, source));
|
|
3241
|
+
names.push(escapeReservedKeyword(getNodeText(child, source)));
|
|
3117
3242
|
i++;
|
|
3118
3243
|
continue;
|
|
3119
3244
|
}
|
|
@@ -3121,7 +3246,7 @@ function extractParamNames(node, source) {
|
|
|
3121
3246
|
const paramChildren = getChildren(child);
|
|
3122
3247
|
const name = paramChildren.find((c) => c.name === "VariableName");
|
|
3123
3248
|
if (name) {
|
|
3124
|
-
names.push(getNodeText(name, source));
|
|
3249
|
+
names.push(escapeReservedKeyword(getNodeText(name, source)));
|
|
3125
3250
|
}
|
|
3126
3251
|
i++;
|
|
3127
3252
|
continue;
|
|
@@ -3673,8 +3798,10 @@ function transformDecoratedStatement(node, ctx) {
|
|
|
3673
3798
|
const returnTypeStr = returnType ? `: ${returnType === "null" ? "void" : returnType}` : "";
|
|
3674
3799
|
return `function ${funcName}(${params})${returnTypeStr}`;
|
|
3675
3800
|
}
|
|
3801
|
+
const indent = " ".repeat(ctx.indentLevel);
|
|
3802
|
+
const { jsdoc, skipFirstStatement } = body ? extractDocstringFromBody(body, ctx, indent) : { jsdoc: null, skipFirstStatement: false };
|
|
3676
3803
|
ctx.insideFunctionBody++;
|
|
3677
|
-
const bodyCode = body ? transformBody(body, ctx,
|
|
3804
|
+
const bodyCode = body ? transformBody(body, ctx, skipFirstStatement, paramNames) : "";
|
|
3678
3805
|
ctx.insideFunctionBody--;
|
|
3679
3806
|
let funcExpr = `function ${funcName}(${params}) {
|
|
3680
3807
|
${bodyCode}
|
|
@@ -3688,7 +3815,9 @@ ${bodyCode}
|
|
|
3688
3815
|
funcExpr = `${dec.name}(${funcExpr})`;
|
|
3689
3816
|
}
|
|
3690
3817
|
}
|
|
3691
|
-
|
|
3818
|
+
const declaration = `const ${funcName} = ${funcExpr}`;
|
|
3819
|
+
return jsdoc ? `${jsdoc}
|
|
3820
|
+
${declaration}` : declaration;
|
|
3692
3821
|
}
|
|
3693
3822
|
function transformDecoratedClass(classDef, decorators, ctx) {
|
|
3694
3823
|
const dataclassDecorator = decorators.find(
|
|
@@ -4239,7 +4368,7 @@ function transformParamList(node, ctx) {
|
|
|
4239
4368
|
const parseParam = (startIndex) => {
|
|
4240
4369
|
const child = children[startIndex];
|
|
4241
4370
|
if (child?.name !== "VariableName") return null;
|
|
4242
|
-
const nameCode = getNodeText(child, ctx.source);
|
|
4371
|
+
const nameCode = escapeReservedKeyword(getNodeText(child, ctx.source));
|
|
4243
4372
|
let tsType = null;
|
|
4244
4373
|
let defaultValue = null;
|
|
4245
4374
|
let offset = 1;
|
|
@@ -4281,7 +4410,7 @@ function transformParamList(node, ctx) {
|
|
|
4281
4410
|
if (child.name === "*" || getNodeText(child, ctx.source) === "*") {
|
|
4282
4411
|
const nextChild = children[i + 1];
|
|
4283
4412
|
if (nextChild?.name === "VariableName") {
|
|
4284
|
-
const name = getNodeText(nextChild, ctx.source);
|
|
4413
|
+
const name = escapeReservedKeyword(getNodeText(nextChild, ctx.source));
|
|
4285
4414
|
const typeChild = children[i + 2];
|
|
4286
4415
|
if (typeChild?.name === "TypeDef") {
|
|
4287
4416
|
const tsType = extractTypeAnnotation(typeChild, ctx);
|
|
@@ -4301,7 +4430,7 @@ function transformParamList(node, ctx) {
|
|
|
4301
4430
|
if (child.name === "**" || getNodeText(child, ctx.source) === "**") {
|
|
4302
4431
|
const nextChild = children[i + 1];
|
|
4303
4432
|
if (nextChild?.name === "VariableName") {
|
|
4304
|
-
kwargsParam = getNodeText(nextChild, ctx.source);
|
|
4433
|
+
kwargsParam = escapeReservedKeyword(getNodeText(nextChild, ctx.source));
|
|
4305
4434
|
i += 2;
|
|
4306
4435
|
continue;
|
|
4307
4436
|
}
|
|
@@ -4326,7 +4455,7 @@ function transformParamList(node, ctx) {
|
|
|
4326
4455
|
const typeDef = paramChildren.find((c) => c.name === "TypeDef");
|
|
4327
4456
|
const defaultVal = paramChildren[paramChildren.length - 1];
|
|
4328
4457
|
if (name) {
|
|
4329
|
-
const nameCode = getNodeText(name, ctx.source);
|
|
4458
|
+
const nameCode = escapeReservedKeyword(getNodeText(name, ctx.source));
|
|
4330
4459
|
const tsType = extractTypeAnnotation(typeDef, ctx);
|
|
4331
4460
|
let defaultValue = null;
|
|
4332
4461
|
if (defaultVal && name !== defaultVal && defaultVal.name !== "TypeDef") {
|
package/dist/cli/index.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "python2ts",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.3",
|
|
4
4
|
"description": "AST-based Python to TypeScript transpiler. Convert Python code to clean, idiomatic TypeScript with full type preservation.",
|
|
5
5
|
"homepage": "https://sebastian-software.github.io/python2ts/",
|
|
6
6
|
"repository": {
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"eslint": "^9.39.2",
|
|
54
54
|
"prettier": "^3.8.0",
|
|
55
55
|
"typescript-eslint": "^8.53.1",
|
|
56
|
-
"pythonlib": "2.0.
|
|
56
|
+
"pythonlib": "2.0.3"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"tsup": "^8.5.1",
|