python2ts 1.1.0 → 1.2.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.
@@ -253,6 +253,23 @@ function declareVariable(ctx, name) {
253
253
  currentScope.add(name);
254
254
  }
255
255
  }
256
+ function stripOuterParens(code) {
257
+ const trimmed = code.trim();
258
+ if (trimmed.startsWith("(") && trimmed.endsWith(")")) {
259
+ const inner = trimmed.slice(1, -1);
260
+ if (/(?<![!=<>])=(?!=)/.test(inner)) {
261
+ return code;
262
+ }
263
+ let depth = 0;
264
+ for (let i = 0; i < trimmed.length; i++) {
265
+ if (trimmed[i] === "(") depth++;
266
+ else if (trimmed[i] === ")") depth--;
267
+ if (depth === 0 && i < trimmed.length - 1) return code;
268
+ }
269
+ return inner;
270
+ }
271
+ return code;
272
+ }
256
273
  function containsYield(node) {
257
274
  if (node.name === "YieldStatement" || node.name === "YieldExpression") {
258
275
  return true;
@@ -1076,7 +1093,7 @@ function transformConditionalExpression(node, ctx) {
1076
1093
  const condition = exprs[1];
1077
1094
  const falseExpr = exprs[2];
1078
1095
  if (trueExpr && condition && falseExpr) {
1079
- const condCode = transformNode(condition, ctx);
1096
+ const condCode = stripOuterParens(transformNode(condition, ctx));
1080
1097
  const trueCode = transformNode(trueExpr, ctx);
1081
1098
  const falseCode = transformNode(falseExpr, ctx);
1082
1099
  return `(${condCode} ? ${trueCode} : ${falseCode})`;
@@ -1931,7 +1948,7 @@ function transformIfStatement(node, ctx) {
1931
1948
  const condition = children[i + 1];
1932
1949
  const body = children.find((c, idx) => idx > i && c.name === "Body");
1933
1950
  if (condition && body) {
1934
- const condCode = transformNode(condition, ctx);
1951
+ const condCode = stripOuterParens(transformNode(condition, ctx));
1935
1952
  const bodyCode = transformBody(body, ctx);
1936
1953
  parts.push(`if (${condCode}) {
1937
1954
  ${bodyCode}
@@ -1941,7 +1958,7 @@ ${bodyCode}
1941
1958
  const condition = children[i + 1];
1942
1959
  const body = children.find((c, idx) => idx > i + 1 && c.name === "Body");
1943
1960
  if (condition && body) {
1944
- const condCode = transformNode(condition, ctx);
1961
+ const condCode = stripOuterParens(transformNode(condition, ctx));
1945
1962
  const bodyCode = transformBody(body, ctx);
1946
1963
  parts.push(` else if (${condCode}) {
1947
1964
  ${bodyCode}
@@ -1967,7 +1984,7 @@ function transformWhileStatement(node, ctx) {
1967
1984
  );
1968
1985
  const body = children.find((c) => c.name === "Body");
1969
1986
  if (!condition || !body) return getNodeText(node, ctx.source);
1970
- const condCode = transformNode(condition, ctx);
1987
+ const condCode = stripOuterParens(transformNode(condition, ctx));
1971
1988
  const bodyCode = transformBody(body, ctx);
1972
1989
  return `while (${condCode}) {
1973
1990
  ${bodyCode}
@@ -2437,13 +2454,20 @@ ${baseIndent}}`;
2437
2454
  const firstExcept = exceptBodies[0];
2438
2455
  if (firstExcept) {
2439
2456
  const catchVar = firstExcept.varName || "e";
2440
- const catchBody = transformBody(firstExcept.body, ctx);
2457
+ let catchBody = transformBody(firstExcept.body, ctx);
2458
+ const isEmpty = !catchBody.trim();
2459
+ if (isEmpty) {
2460
+ const innerIndent = " ".repeat(ctx.indentLevel + 1);
2461
+ const exceptionComment = firstExcept.type ? ` - ${firstExcept.type} expected` : "";
2462
+ catchBody = `${innerIndent}// Intentionally empty${exceptionComment}`;
2463
+ }
2464
+ const catchClause = isEmpty && !firstExcept.varName ? "catch" : `catch (${catchVar})`;
2441
2465
  if (exceptBodies.length === 1 && !firstExcept.type) {
2442
- result += ` catch (${catchVar}) {
2466
+ result += ` ${catchClause} {
2443
2467
  ${catchBody}
2444
2468
  ${baseIndent}}`;
2445
2469
  } else if (exceptBodies.length === 1) {
2446
- result += ` catch (${catchVar}) {
2470
+ result += ` ${catchClause} {
2447
2471
  ${catchBody}
2448
2472
  ${baseIndent}}`;
2449
2473
  } else {
@@ -4511,6 +4535,11 @@ function transformYieldStatement(node, ctx) {
4511
4535
 
4512
4536
  // src/generator/index.ts
4513
4537
  import * as prettier from "prettier";
4538
+ import { ESLint } from "eslint";
4539
+ import tseslint from "typescript-eslint";
4540
+ import { writeFileSync, readFileSync, mkdtempSync, rmSync } from "fs";
4541
+ import { join } from "path";
4542
+ import { tmpdir } from "os";
4514
4543
  var defaultOptions = {
4515
4544
  includeRuntime: true,
4516
4545
  runtimeImportPath: "pythonlib"
@@ -4655,9 +4684,81 @@ function buildRuntimeImports(usedFunctions, basePath) {
4655
4684
  function transpile(python, options = {}) {
4656
4685
  return generate(python, options).code;
4657
4686
  }
4687
+ function createEslintConfig(tempDir) {
4688
+ return {
4689
+ cwd: tempDir,
4690
+ fix: true,
4691
+ overrideConfigFile: true,
4692
+ overrideConfig: [
4693
+ // TypeScript-ESLint strict + stylistic presets (type-checked)
4694
+ ...tseslint.configs.strictTypeChecked,
4695
+ ...tseslint.configs.stylisticTypeChecked,
4696
+ // Custom configuration
4697
+ {
4698
+ files: ["**/*.ts"],
4699
+ languageOptions: {
4700
+ parserOptions: {
4701
+ projectService: true,
4702
+ tsconfigRootDir: tempDir
4703
+ }
4704
+ },
4705
+ rules: {
4706
+ // ESLint core rules (auto-fixable, not in typescript-eslint presets)
4707
+ "prefer-const": "error",
4708
+ "prefer-arrow-callback": "error",
4709
+ "prefer-template": "error",
4710
+ "prefer-rest-params": "error",
4711
+ "prefer-spread": "error",
4712
+ curly: "error",
4713
+ "no-lonely-if": "error",
4714
+ // Disable rules that don't make sense for generated code
4715
+ "@typescript-eslint/explicit-function-return-type": "off",
4716
+ "@typescript-eslint/explicit-module-boundary-types": "off",
4717
+ "@typescript-eslint/no-explicit-any": "off",
4718
+ "@typescript-eslint/no-unsafe-assignment": "off",
4719
+ "@typescript-eslint/no-unsafe-member-access": "off",
4720
+ "@typescript-eslint/no-unsafe-call": "off",
4721
+ "@typescript-eslint/no-unsafe-return": "off",
4722
+ "@typescript-eslint/no-unsafe-argument": "off"
4723
+ }
4724
+ }
4725
+ ]
4726
+ };
4727
+ }
4728
+ async function applyTypedEslintFixes(code) {
4729
+ const tempDir = mkdtempSync(join(tmpdir(), "python2ts-"));
4730
+ try {
4731
+ const tsconfigPath = join(tempDir, "tsconfig.json");
4732
+ writeFileSync(
4733
+ tsconfigPath,
4734
+ JSON.stringify({
4735
+ compilerOptions: {
4736
+ target: "ES2024",
4737
+ module: "ESNext",
4738
+ moduleResolution: "bundler",
4739
+ strict: true,
4740
+ skipLibCheck: true,
4741
+ noEmit: true
4742
+ },
4743
+ include: ["*.ts"]
4744
+ })
4745
+ );
4746
+ const tempFile = join(tempDir, "output.ts");
4747
+ writeFileSync(tempFile, code);
4748
+ const eslint = new ESLint(createEslintConfig(tempDir));
4749
+ const results = await eslint.lintFiles(["output.ts"]);
4750
+ if (results.length > 0 && results[0]?.output) {
4751
+ return results[0].output;
4752
+ }
4753
+ return readFileSync(tempFile, "utf-8");
4754
+ } finally {
4755
+ rmSync(tempDir, { recursive: true, force: true });
4756
+ }
4757
+ }
4658
4758
  async function formatCode(code) {
4659
4759
  try {
4660
- return await prettier.format(code, prettierOptions);
4760
+ const eslintFixed = await applyTypedEslintFixes(code);
4761
+ return await prettier.format(eslintFixed, prettierOptions);
4661
4762
  } catch {
4662
4763
  return code;
4663
4764
  }
@@ -4703,4 +4804,4 @@ export {
4703
4804
  /* v8 ignore next -- bare yield statement @preserve */
4704
4805
  /* v8 ignore next 2 -- fallback for future/unknown runtime functions @preserve */
4705
4806
  /* v8 ignore start -- async wrappers tested via CLI @preserve */
4706
- //# sourceMappingURL=chunk-65ZOMVMA.js.map
4807
+ //# sourceMappingURL=chunk-MEHQCUVO.js.map