python2ts 1.3.2 → 1.4.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/dist/{chunk-RNRRQS6K.js → chunk-2VKIPKNY.js} +181 -20
- 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);
|
|
@@ -716,6 +791,8 @@ function transformNode(node, ctx) {
|
|
|
716
791
|
return transformExpressionStatement(node, ctx);
|
|
717
792
|
case "AssignStatement":
|
|
718
793
|
return transformAssignStatement(node, ctx);
|
|
794
|
+
case "UpdateStatement":
|
|
795
|
+
return transformUpdateStatement(node, ctx);
|
|
719
796
|
case "BinaryExpression":
|
|
720
797
|
return transformBinaryExpression(node, ctx);
|
|
721
798
|
case "UnaryExpression":
|
|
@@ -732,12 +809,14 @@ function transformNode(node, ctx) {
|
|
|
732
809
|
return transformString(node, ctx);
|
|
733
810
|
case "FormatString":
|
|
734
811
|
return transformFormatString(node, ctx);
|
|
812
|
+
case "ContinuedString":
|
|
813
|
+
return transformContinuedString(node, ctx);
|
|
735
814
|
case "Boolean":
|
|
736
815
|
return transformBoolean(node, ctx);
|
|
737
816
|
case "None":
|
|
738
817
|
return "null";
|
|
739
818
|
case "VariableName":
|
|
740
|
-
return getNodeText(node, ctx.source);
|
|
819
|
+
return escapeReservedKeyword(getNodeText(node, ctx.source));
|
|
741
820
|
case "CallExpression":
|
|
742
821
|
return transformCallExpression(node, ctx);
|
|
743
822
|
case "MemberExpression":
|
|
@@ -802,6 +881,9 @@ function transformNode(node, ctx) {
|
|
|
802
881
|
return transformAssertStatement(node, ctx);
|
|
803
882
|
case "YieldStatement":
|
|
804
883
|
return transformYieldStatement(node, ctx);
|
|
884
|
+
case "Ellipsis":
|
|
885
|
+
ctx.usesRuntime.add("Ellipsis");
|
|
886
|
+
return "Ellipsis";
|
|
805
887
|
/* v8 ignore next 2 -- fallback for unknown AST nodes @preserve */
|
|
806
888
|
default:
|
|
807
889
|
return getNodeText(node, ctx.source);
|
|
@@ -947,6 +1029,23 @@ function extractVariableNames(nodes, source) {
|
|
|
947
1029
|
}
|
|
948
1030
|
return names;
|
|
949
1031
|
}
|
|
1032
|
+
function transformUpdateStatement(node, ctx) {
|
|
1033
|
+
const children = getChildren(node);
|
|
1034
|
+
const target = children.find(
|
|
1035
|
+
(c) => c.name === "VariableName" || c.name === "MemberExpression" || c.name === "Subscript"
|
|
1036
|
+
);
|
|
1037
|
+
const op = children.find((c) => c.name === "UpdateOp");
|
|
1038
|
+
const value = children.find(
|
|
1039
|
+
(c) => c !== target && c.name !== "UpdateOp" && c.name !== "(" && c.name !== ")" && c.name !== "," && c.name !== ":"
|
|
1040
|
+
);
|
|
1041
|
+
if (!target || !op || !value) {
|
|
1042
|
+
return getNodeText(node, ctx.source);
|
|
1043
|
+
}
|
|
1044
|
+
const targetCode = transformNode(target, ctx);
|
|
1045
|
+
const opText = getNodeText(op, ctx.source);
|
|
1046
|
+
const valueCode = transformNode(value, ctx);
|
|
1047
|
+
return `${targetCode} ${opText} ${valueCode}`;
|
|
1048
|
+
}
|
|
950
1049
|
function isSliceExpression(node) {
|
|
951
1050
|
const children = getChildren(node);
|
|
952
1051
|
return children.some((c) => c.name === ":");
|
|
@@ -1239,6 +1338,51 @@ function transformFormatString(node, ctx) {
|
|
|
1239
1338
|
result += "`";
|
|
1240
1339
|
return result;
|
|
1241
1340
|
}
|
|
1341
|
+
function transformContinuedString(node, ctx) {
|
|
1342
|
+
const children = getChildren(node);
|
|
1343
|
+
const hasFormatString = children.some((c) => c.name === "FormatString");
|
|
1344
|
+
if (hasFormatString) {
|
|
1345
|
+
const parts = children.filter((c) => c.name === "String" || c.name === "FormatString").map((c) => {
|
|
1346
|
+
if (c.name === "FormatString") {
|
|
1347
|
+
return transformFormatString(c, ctx);
|
|
1348
|
+
} else {
|
|
1349
|
+
const text = getNodeText(c, ctx.source);
|
|
1350
|
+
let content;
|
|
1351
|
+
if (/^[rR]['"]/.test(text)) {
|
|
1352
|
+
content = text.slice(2, -1);
|
|
1353
|
+
} else if (/^[rR]"""/.test(text) || /^[rR]'''/.test(text)) {
|
|
1354
|
+
content = text.slice(4, -3);
|
|
1355
|
+
} else if (text.startsWith('"""') || text.startsWith("'''")) {
|
|
1356
|
+
content = text.slice(3, -3);
|
|
1357
|
+
} else {
|
|
1358
|
+
content = text.slice(1, -1);
|
|
1359
|
+
}
|
|
1360
|
+
return "`" + content.replace(/`/g, "\\`") + "`";
|
|
1361
|
+
}
|
|
1362
|
+
});
|
|
1363
|
+
return parts.join(" + ");
|
|
1364
|
+
} else {
|
|
1365
|
+
const parts = children.filter((c) => c.name === "String").map((c) => {
|
|
1366
|
+
const text = getNodeText(c, ctx.source);
|
|
1367
|
+
let content;
|
|
1368
|
+
if (/^[rR]['"]/.test(text)) {
|
|
1369
|
+
content = text.slice(2, -1);
|
|
1370
|
+
} else if (/^[rR]"""/.test(text) || /^[rR]'''/.test(text)) {
|
|
1371
|
+
content = text.slice(4, -3);
|
|
1372
|
+
} else if (text.startsWith('"""') || text.startsWith("'''")) {
|
|
1373
|
+
content = text.slice(3, -3);
|
|
1374
|
+
} else {
|
|
1375
|
+
content = text.slice(1, -1);
|
|
1376
|
+
}
|
|
1377
|
+
return content;
|
|
1378
|
+
});
|
|
1379
|
+
const joined = parts.join("");
|
|
1380
|
+
if (joined.includes('"') && !joined.includes("'")) {
|
|
1381
|
+
return "'" + joined + "'";
|
|
1382
|
+
}
|
|
1383
|
+
return '"' + joined + '"';
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1242
1386
|
function transformBoolean(node, ctx) {
|
|
1243
1387
|
const text = getNodeText(node, ctx.source);
|
|
1244
1388
|
return text === "True" ? "true" : "false";
|
|
@@ -1839,7 +1983,11 @@ function transformMethodCall(callee, args, ctx) {
|
|
|
1839
1983
|
case "rjust":
|
|
1840
1984
|
return `${objCode}.padStart(${args})`;
|
|
1841
1985
|
// String split/join - join is special: "sep".join(arr) -> arr.join("sep")
|
|
1986
|
+
// If the argument is a generator expression, convert to array with spread
|
|
1842
1987
|
case "join":
|
|
1988
|
+
if (args.includes("function*")) {
|
|
1989
|
+
return `[...${args}].join(${objCode})`;
|
|
1990
|
+
}
|
|
1843
1991
|
return `(${args}).join(${objCode})`;
|
|
1844
1992
|
case "split":
|
|
1845
1993
|
return args ? `${objCode}.split(${args})` : `${objCode}.split(/\\s+/)`;
|
|
@@ -2040,15 +2188,23 @@ function transformMemberExpression(node, ctx) {
|
|
|
2040
2188
|
if (text.includes(":")) {
|
|
2041
2189
|
return transformSliceFromMember(obj, children, ctx);
|
|
2042
2190
|
}
|
|
2043
|
-
const indexElements = children.filter(
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
if (
|
|
2048
|
-
|
|
2049
|
-
return
|
|
2191
|
+
const indexElements = children.filter(
|
|
2192
|
+
(c) => c.name !== "[" && c.name !== "]" && c.name !== "," && c !== obj
|
|
2193
|
+
);
|
|
2194
|
+
if (indexElements.length === 0) return `${objCode}[]`;
|
|
2195
|
+
if (indexElements.length === 1) {
|
|
2196
|
+
const index = indexElements[0];
|
|
2197
|
+
if (!index) return `${objCode}[]`;
|
|
2198
|
+
const indexCode = transformNode(index, ctx);
|
|
2199
|
+
if (isNegativeIndexLiteral(index, ctx)) {
|
|
2200
|
+
ctx.usesRuntime.add("at");
|
|
2201
|
+
return `at(${objCode}, ${indexCode})`;
|
|
2202
|
+
}
|
|
2203
|
+
return `${objCode}[${indexCode}]`;
|
|
2050
2204
|
}
|
|
2051
|
-
|
|
2205
|
+
ctx.usesRuntime.add("tuple");
|
|
2206
|
+
const indices = indexElements.map((el) => transformNode(el, ctx));
|
|
2207
|
+
return `${objCode}[tuple(${indices.join(", ")})]`;
|
|
2052
2208
|
} else {
|
|
2053
2209
|
const prop = children[children.length - 1];
|
|
2054
2210
|
if (!prop) return getNodeText(node, ctx.source);
|
|
@@ -3050,7 +3206,12 @@ function transformWithStatement(node, ctx) {
|
|
|
3050
3206
|
body = child;
|
|
3051
3207
|
break;
|
|
3052
3208
|
}
|
|
3053
|
-
if (child.name
|
|
3209
|
+
if (child.name === "as" || child.name === ":") {
|
|
3210
|
+
i++;
|
|
3211
|
+
continue;
|
|
3212
|
+
}
|
|
3213
|
+
const isContextManagerExpr = child.name !== "VariableName" || children[i + 1]?.name === "as" || children[i + 1]?.name === "Body" || children[i + 1]?.name === ",";
|
|
3214
|
+
if (isContextManagerExpr) {
|
|
3054
3215
|
const expr = child;
|
|
3055
3216
|
let varName = null;
|
|
3056
3217
|
const nextChild = children[i + 1];
|
|
@@ -3130,7 +3291,7 @@ function extractParamNames(node, source) {
|
|
|
3130
3291
|
if (child.name === "*" || getNodeText(child, source) === "*") {
|
|
3131
3292
|
const nextChild = children[i + 1];
|
|
3132
3293
|
if (nextChild?.name === "VariableName") {
|
|
3133
|
-
names.push(getNodeText(nextChild, source));
|
|
3294
|
+
names.push(escapeReservedKeyword(getNodeText(nextChild, source)));
|
|
3134
3295
|
i += 2;
|
|
3135
3296
|
continue;
|
|
3136
3297
|
}
|
|
@@ -3140,7 +3301,7 @@ function extractParamNames(node, source) {
|
|
|
3140
3301
|
if (child.name === "**" || getNodeText(child, source) === "**") {
|
|
3141
3302
|
const nextChild = children[i + 1];
|
|
3142
3303
|
if (nextChild?.name === "VariableName") {
|
|
3143
|
-
names.push(getNodeText(nextChild, source));
|
|
3304
|
+
names.push(escapeReservedKeyword(getNodeText(nextChild, source)));
|
|
3144
3305
|
i += 2;
|
|
3145
3306
|
continue;
|
|
3146
3307
|
}
|
|
@@ -3148,7 +3309,7 @@ function extractParamNames(node, source) {
|
|
|
3148
3309
|
continue;
|
|
3149
3310
|
}
|
|
3150
3311
|
if (child.name === "VariableName") {
|
|
3151
|
-
names.push(getNodeText(child, source));
|
|
3312
|
+
names.push(escapeReservedKeyword(getNodeText(child, source)));
|
|
3152
3313
|
i++;
|
|
3153
3314
|
continue;
|
|
3154
3315
|
}
|
|
@@ -3156,7 +3317,7 @@ function extractParamNames(node, source) {
|
|
|
3156
3317
|
const paramChildren = getChildren(child);
|
|
3157
3318
|
const name = paramChildren.find((c) => c.name === "VariableName");
|
|
3158
3319
|
if (name) {
|
|
3159
|
-
names.push(getNodeText(name, source));
|
|
3320
|
+
names.push(escapeReservedKeyword(getNodeText(name, source)));
|
|
3160
3321
|
}
|
|
3161
3322
|
i++;
|
|
3162
3323
|
continue;
|
|
@@ -4278,7 +4439,7 @@ function transformParamList(node, ctx) {
|
|
|
4278
4439
|
const parseParam = (startIndex) => {
|
|
4279
4440
|
const child = children[startIndex];
|
|
4280
4441
|
if (child?.name !== "VariableName") return null;
|
|
4281
|
-
const nameCode = getNodeText(child, ctx.source);
|
|
4442
|
+
const nameCode = escapeReservedKeyword(getNodeText(child, ctx.source));
|
|
4282
4443
|
let tsType = null;
|
|
4283
4444
|
let defaultValue = null;
|
|
4284
4445
|
let offset = 1;
|
|
@@ -4320,7 +4481,7 @@ function transformParamList(node, ctx) {
|
|
|
4320
4481
|
if (child.name === "*" || getNodeText(child, ctx.source) === "*") {
|
|
4321
4482
|
const nextChild = children[i + 1];
|
|
4322
4483
|
if (nextChild?.name === "VariableName") {
|
|
4323
|
-
const name = getNodeText(nextChild, ctx.source);
|
|
4484
|
+
const name = escapeReservedKeyword(getNodeText(nextChild, ctx.source));
|
|
4324
4485
|
const typeChild = children[i + 2];
|
|
4325
4486
|
if (typeChild?.name === "TypeDef") {
|
|
4326
4487
|
const tsType = extractTypeAnnotation(typeChild, ctx);
|
|
@@ -4340,7 +4501,7 @@ function transformParamList(node, ctx) {
|
|
|
4340
4501
|
if (child.name === "**" || getNodeText(child, ctx.source) === "**") {
|
|
4341
4502
|
const nextChild = children[i + 1];
|
|
4342
4503
|
if (nextChild?.name === "VariableName") {
|
|
4343
|
-
kwargsParam = getNodeText(nextChild, ctx.source);
|
|
4504
|
+
kwargsParam = escapeReservedKeyword(getNodeText(nextChild, ctx.source));
|
|
4344
4505
|
i += 2;
|
|
4345
4506
|
continue;
|
|
4346
4507
|
}
|
|
@@ -4365,7 +4526,7 @@ function transformParamList(node, ctx) {
|
|
|
4365
4526
|
const typeDef = paramChildren.find((c) => c.name === "TypeDef");
|
|
4366
4527
|
const defaultVal = paramChildren[paramChildren.length - 1];
|
|
4367
4528
|
if (name) {
|
|
4368
|
-
const nameCode = getNodeText(name, ctx.source);
|
|
4529
|
+
const nameCode = escapeReservedKeyword(getNodeText(name, ctx.source));
|
|
4369
4530
|
const tsType = extractTypeAnnotation(typeDef, ctx);
|
|
4370
4531
|
let defaultValue = null;
|
|
4371
4532
|
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
|
+
"version": "1.4.0",
|
|
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",
|