ts-codemod-lib 2.0.4 → 2.1.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.
Files changed (72) hide show
  1. package/dist/cmd/append-as-const.mjs +1 -1
  2. package/dist/cmd/convert-interface-to-type.mjs +1 -1
  3. package/dist/cmd/convert-to-readonly.mjs +1 -1
  4. package/dist/cmd/replace-any-with-unknown.mjs +1 -1
  5. package/dist/cmd/replace-record-with-unknown-record.mjs +1 -1
  6. package/dist/cmd/run-transformer-cli.mjs +3 -3
  7. package/dist/cmd/run-transformer-cli.mjs.map +1 -1
  8. package/dist/entry-point.mjs +2 -1
  9. package/dist/entry-point.mjs.map +1 -1
  10. package/dist/functions/ast-transformers/convert-interface-to-type.d.mts.map +1 -1
  11. package/dist/functions/ast-transformers/convert-interface-to-type.mjs +4 -4
  12. package/dist/functions/ast-transformers/convert-interface-to-type.mjs.map +1 -1
  13. package/dist/functions/ast-transformers/convert-to-readonly.d.mts.map +1 -1
  14. package/dist/functions/ast-transformers/convert-to-readonly.mjs +31 -12
  15. package/dist/functions/ast-transformers/convert-to-readonly.mjs.map +1 -1
  16. package/dist/functions/ast-transformers/readonly-transformer-helpers/compare-union-types.mjs +1 -0
  17. package/dist/functions/ast-transformers/readonly-transformer-helpers/compare-union-types.mjs.map +1 -1
  18. package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mjs +1 -0
  19. package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mjs.map +1 -1
  20. package/dist/functions/ast-transformers/replace-any-with-unknown.mjs +1 -1
  21. package/dist/functions/ast-transformers/replace-record-with-unknown-record.mjs +13 -12
  22. package/dist/functions/ast-transformers/replace-record-with-unknown-record.mjs.map +1 -1
  23. package/dist/functions/ast-transformers/transform-source-code.d.mts.map +1 -1
  24. package/dist/functions/ast-transformers/transform-source-code.mjs +41 -13
  25. package/dist/functions/ast-transformers/transform-source-code.mjs.map +1 -1
  26. package/dist/functions/constants/ignore-comment-text.d.mts +2 -2
  27. package/dist/functions/constants/ignore-comment-text.d.mts.map +1 -1
  28. package/dist/functions/constants/ignore-comment-text.mjs +13 -3
  29. package/dist/functions/constants/ignore-comment-text.mjs.map +1 -1
  30. package/dist/functions/constants/index.mjs +1 -1
  31. package/dist/functions/functions/has-disable-next-line-comment.d.mts +3 -2
  32. package/dist/functions/functions/has-disable-next-line-comment.d.mts.map +1 -1
  33. package/dist/functions/functions/has-disable-next-line-comment.mjs +9 -6
  34. package/dist/functions/functions/has-disable-next-line-comment.mjs.map +1 -1
  35. package/dist/functions/functions/index.d.mts +1 -0
  36. package/dist/functions/functions/index.d.mts.map +1 -1
  37. package/dist/functions/functions/index.mjs +1 -0
  38. package/dist/functions/functions/index.mjs.map +1 -1
  39. package/dist/functions/functions/is-as-const-node.d.mts.map +1 -1
  40. package/dist/functions/functions/is-as-const-node.mjs +2 -1
  41. package/dist/functions/functions/is-as-const-node.mjs.map +1 -1
  42. package/dist/functions/functions/should-avoid-parentheses-for-readonly.d.mts +16 -0
  43. package/dist/functions/functions/should-avoid-parentheses-for-readonly.d.mts.map +1 -0
  44. package/dist/functions/functions/should-avoid-parentheses-for-readonly.mjs +32 -0
  45. package/dist/functions/functions/should-avoid-parentheses-for-readonly.mjs.map +1 -0
  46. package/dist/functions/functions/wrap-with-parentheses.d.mts +13 -1
  47. package/dist/functions/functions/wrap-with-parentheses.d.mts.map +1 -1
  48. package/dist/functions/functions/wrap-with-parentheses.mjs +58 -1
  49. package/dist/functions/functions/wrap-with-parentheses.mjs.map +1 -1
  50. package/dist/functions/index.mjs +2 -1
  51. package/dist/functions/index.mjs.map +1 -1
  52. package/dist/index.mjs +2 -1
  53. package/dist/index.mjs.map +1 -1
  54. package/package.json +16 -16
  55. package/src/cmd/append-as-const.mts +1 -1
  56. package/src/cmd/convert-interface-to-type.mts +1 -1
  57. package/src/cmd/convert-to-readonly.mts +1 -1
  58. package/src/cmd/replace-any-with-unknown.mts +1 -1
  59. package/src/cmd/replace-record-with-unknown-record.mts +1 -1
  60. package/src/cmd/run-transformer-cli.mts +3 -3
  61. package/src/functions/ast-transformers/convert-interface-to-type.mts +6 -7
  62. package/src/functions/ast-transformers/convert-to-readonly.mts +39 -13
  63. package/src/functions/ast-transformers/convert-to-readonly.test.mts +79 -0
  64. package/src/functions/ast-transformers/replace-record-with-unknown-record.mts +15 -12
  65. package/src/functions/ast-transformers/transform-source-code.mts +44 -15
  66. package/src/functions/ast-transformers/transformer-specific-ignore.test.mts +129 -0
  67. package/src/functions/constants/ignore-comment-text.mts +12 -2
  68. package/src/functions/functions/has-disable-next-line-comment.mts +12 -6
  69. package/src/functions/functions/index.mts +1 -0
  70. package/src/functions/functions/is-as-const-node.mts +2 -1
  71. package/src/functions/functions/should-avoid-parentheses-for-readonly.mts +32 -0
  72. package/src/functions/functions/wrap-with-parentheses.mts +75 -2
@@ -0,0 +1,32 @@
1
+ import * as tsm from 'ts-morph';
2
+
3
+ /**
4
+ * Determines if parentheses should be avoided when adding 'readonly' prefix to a type.
5
+ *
6
+ * Parentheses should be AVOIDED in these specific contexts:
7
+ * - Type predicates: `x is [T, U]` -> `x is readonly [T, U]` (not `x is (readonly [T, U])`)
8
+ * because parentheses around the type in a type predicate cause syntax errors
9
+ *
10
+ * For all other contexts, we keep parentheses for safety to avoid precedence issues,
11
+ * relying on prettier to remove unnecessary ones.
12
+ *
13
+ * @param node - The type node to check
14
+ * @returns true if parentheses should be avoided, false otherwise (keep parentheses)
15
+ */
16
+ export const shouldAvoidParenthesesForReadonly = (node: tsm.Node): boolean => {
17
+ const parent = node.getParent();
18
+
19
+ if (parent === undefined) {
20
+ return false;
21
+ }
22
+
23
+ // Check if parent is TypePredicate: x is T
24
+ // In this case, we MUST avoid parentheses: x is readonly T (not x is (readonly T))
25
+ // because `x is (readonly T)` is a syntax error
26
+ if (parent.isKind(tsm.SyntaxKind.TypePredicate)) {
27
+ return true;
28
+ }
29
+
30
+ // For all other cases, keep parentheses for safety
31
+ return false;
32
+ };
@@ -1,2 +1,75 @@
1
- export const wrapWithParentheses = (nodeStr: string): `(${string})` =>
2
- `(${nodeStr.trim()})` as const;
1
+ /**
2
+ * Checks if a string is already wrapped with a single pair of balanced parentheses
3
+ * that encompasses the entire expression.
4
+ *
5
+ * @example
6
+ * isWrappedWithParentheses('(A)') // true
7
+ * isWrappedWithParentheses('((A))') // true (outer pair wraps everything)
8
+ * isWrappedWithParentheses('(A) | (B)') // false (outer parens don't wrap everything)
9
+ * isWrappedWithParentheses('A') // false
10
+ */
11
+ import { asUint32, range } from 'ts-data-forge';
12
+
13
+ const isWrappedWithParentheses = (str: string): boolean => {
14
+ const trimmed = str.trim();
15
+
16
+ if (!trimmed.startsWith('(') || !trimmed.endsWith(')')) {
17
+ return false;
18
+ }
19
+
20
+ // Check if the opening and closing parentheses are balanced
21
+ // and the opening parenthesis corresponds to the closing one
22
+ let mut_depth = 0;
23
+
24
+ for (const mut_i of range(0, asUint32(trimmed.length))) {
25
+ const char: string = trimmed.charAt(mut_i);
26
+
27
+ switch (char) {
28
+ case '(': {
29
+ mut_depth += 1;
30
+
31
+ break;
32
+ }
33
+
34
+ case ')': {
35
+ mut_depth -= 1;
36
+
37
+ // If we reach depth 0 before the end, the outer parentheses don't wrap everything
38
+ if (mut_depth === 0 && mut_i < trimmed.length - 1) {
39
+ return false;
40
+ }
41
+
42
+ break;
43
+ }
44
+
45
+ default: {
46
+ // Other characters - no action needed
47
+ break;
48
+ }
49
+ }
50
+ }
51
+
52
+ return true;
53
+ };
54
+
55
+ /**
56
+ * Wraps a string with parentheses if not already wrapped.
57
+ * Avoids adding redundant parentheses when the expression is already
58
+ * fully wrapped with balanced parentheses.
59
+ *
60
+ * @example
61
+ * wrapWithParentheses('A') // '(A)'
62
+ * wrapWithParentheses('(A)') // '(A)' (not '((A))')
63
+ * wrapWithParentheses('A | B') // '(A | B)'
64
+ * wrapWithParentheses('(A | B)') // '(A | B)' (not '((A | B))')
65
+ * wrapWithParentheses('(A) | (B)') // '((A) | (B))' (needs outer parens)
66
+ */
67
+ export const wrapWithParentheses = (nodeStr: string): string => {
68
+ const trimmed = nodeStr.trim();
69
+
70
+ if (isWrappedWithParentheses(trimmed)) {
71
+ return trimmed;
72
+ }
73
+
74
+ return `(${trimmed})` as const;
75
+ };