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
@@ -1,27 +1,55 @@
1
+ import { Arr } from 'ts-data-forge';
1
2
  import * as tsm from 'ts-morph';
2
3
 
3
4
  const extractFileIgnoreTransformers = (code) => {
4
- const match = /\/\*\s*transformer-ignore\s*(.*?)\s*\*\//u.exec(code);
5
- if (match === null) {
6
- return [];
7
- }
8
- const targetTransformers = match[1]?.trim() ?? '';
9
- // Empty means ignore all transformers
10
- if (targetTransformers === '') {
11
- return [];
5
+ // Try to find any of the supported file-level ignore comment prefixes
6
+ const patterns = [
7
+ {
8
+ prefix: 'transformer-ignore',
9
+ regex: /\/\*\s*transformer-ignore\s*(.*?)\s*\*\//u,
10
+ },
11
+ {
12
+ prefix: 'ts-codemod-ignore',
13
+ regex: /\/\*\s*ts-codemod-ignore\s*(.*?)\s*\*\//u,
14
+ },
15
+ {
16
+ prefix: 'codemod-ignore',
17
+ regex: /\/\*\s*codemod-ignore\s*(.*?)\s*\*\//u,
18
+ },
19
+ {
20
+ prefix: 'transform-ignore',
21
+ regex: /\/\*\s*transform-ignore\s*(.*?)\s*\*\//u,
22
+ },
23
+ ];
24
+ for (const { regex } of patterns) {
25
+ const match = regex.exec(code);
26
+ if (match !== null) {
27
+ const targetTransformers = match[1]?.trim() ?? '';
28
+ // Empty means ignore all transformers
29
+ if (targetTransformers === '') {
30
+ return [];
31
+ }
32
+ // Parse comma-separated transformer names
33
+ return targetTransformers.split(',').map((name) => name.trim());
34
+ }
12
35
  }
13
- // Parse comma-separated transformer names
14
- return targetTransformers.split(',').map((name) => name.trim());
36
+ return [];
15
37
  };
16
38
  const shouldSkipFile = (code, transformerName) => {
17
39
  const ignoredTransformers = extractFileIgnoreTransformers(code);
18
40
  // If no file-level ignore comment found, don't skip
19
- if (ignoredTransformers.length === 0 &&
20
- !/\/\*\s*transformer-ignore\s*.*?\s*\*\//u.test(code)) {
41
+ const patterns = [
42
+ /\/\*\s*transformer-ignore\s*.*?\s*\*\//u,
43
+ /\/\*\s*ts-codemod-ignore\s*.*?\s*\*\//u,
44
+ /\/\*\s*codemod-ignore\s*.*?\s*\*\//u,
45
+ /\/\*\s*transform-ignore\s*.*?\s*\*\//u,
46
+ ];
47
+ const hasFileIgnoreComment = patterns.some((regex) => regex.test(code));
48
+ if (Arr.isArrayOfLength(ignoredTransformers, 0) && !hasFileIgnoreComment) {
21
49
  return false;
22
50
  }
23
51
  // Empty array means ignore all transformers (file-level ignore without specific transformers)
24
- if (ignoredTransformers.length === 0) {
52
+ if (Arr.isArrayOfLength(ignoredTransformers, 0)) {
25
53
  return true;
26
54
  }
27
55
  // If transformer name is not specified, don't skip
@@ -1 +1 @@
1
- {"version":3,"file":"transform-source-code.mjs","sources":["../../../src/functions/ast-transformers/transform-source-code.mts"],"sourcesContent":[null],"names":[],"mappings":";;AAGA,MAAM,6BAA6B,GAAG,CAAC,IAAY,KAAuB;IACxE,MAAM,KAAK,GAAG,2CAA2C,CAAC,IAAI,CAAC,IAAI,CAAC;AAEpE,IAAA,IAAI,KAAK,KAAK,IAAI,EAAE;AAClB,QAAA,OAAO,EAAE;IACX;IAEA,MAAM,kBAAkB,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE;;AAGjD,IAAA,IAAI,kBAAkB,KAAK,EAAE,EAAE;AAC7B,QAAA,OAAO,EAAE;IACX;;AAGA,IAAA,OAAO,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;AACjE,CAAC;AAED,MAAM,cAAc,GAAG,CACrB,IAAY,EACZ,eAAmC,KACxB;AACX,IAAA,MAAM,mBAAmB,GAAG,6BAA6B,CAAC,IAAI,CAAC;;AAG/D,IAAA,IACE,mBAAmB,CAAC,MAAM,KAAK,CAAC;AAChC,QAAA,CAAC,yCAAyC,CAAC,IAAI,CAAC,IAAI,CAAC,EACrD;AACA,QAAA,OAAO,KAAK;IACd;;AAGA,IAAA,IAAI,mBAAmB,CAAC,MAAM,KAAK,CAAC,EAAE;AACpC,QAAA,OAAO,IAAI;IACb;;AAGA,IAAA,IAAI,eAAe,KAAK,SAAS,EAAE;AACjC,QAAA,OAAO,KAAK;IACd;;AAGA,IAAA,OAAO,mBAAmB,CAAC,QAAQ,CAAC,eAAe,CAAC;AACtD,CAAC;AAEM,MAAM,mBAAmB,GAAG,CACjC,IAAY,EACZ,KAAc,EACd,YAA2C,EAC3C,KAAA,GAAiB,KAAK,KACZ;AACV,IAAA,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC;AAC9B,QAAA,qBAAqB,EAAE,IAAI;AAC3B,QAAA,eAAe,EAAE;AACf,YAAA,GAAG,EAAE,KAAK,GAAG,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,GAAG,SAAS;AAC7C,YAAA,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM;AAClC,YAAA,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM;AACjC,SAAA;AACF,KAAA,CAAC;IAEF,MAAM,SAAS,GAAG,OAAO,CAAC,gBAAgB,CACxC,CAAA,OAAA,EAAU,KAAK,GAAG,KAAK,GAAG,IAAI,EAAE,EAChC,IAAI,CACL;AAED,IAAA,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE;AACtC,QAAA,MAAM,eAAe,GAAG,WAAW,CAAC,IAAI;AAExC,QAAA,IAAI,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,EAAE;YACzC,IAAI,KAAK,EAAE;AACT,gBAAA,OAAO,CAAC,KAAK,CACX,mDAAmD,eAAe,CAAA,CAAE,CACrE;YACH;YAEA;QACF;AAEA,QAAA,WAAW,CAAC,SAAS,CAAC,SAAS,CAAC;IAClC;AAEA,IAAA,OAAO,SAAS,CAAC,WAAW,EAAE;AAChC;;;;"}
1
+ {"version":3,"file":"transform-source-code.mjs","sources":["../../../src/functions/ast-transformers/transform-source-code.mts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- export declare const IGNORE_LINE_COMMENT_PREFIX = "transformer-ignore-next-line";
2
- export declare const IGNORE_FILE_COMMENT_PREFIX = "transformer-ignore";
1
+ export declare const IGNORE_LINE_COMMENT_PREFIXES: readonly ["transformer-ignore-next-line", "ts-codemod-ignore-next-line", "codemod-ignore-next-line", "transform-ignore-next-line"];
2
+ export declare const IGNORE_FILE_COMMENT_PREFIXES: readonly ["transformer-ignore", "ts-codemod-ignore", "codemod-ignore", "transform-ignore"];
3
3
  //# sourceMappingURL=ignore-comment-text.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ignore-comment-text.d.mts","sourceRoot":"","sources":["../../../src/functions/constants/ignore-comment-text.mts"],"names":[],"mappings":"AAAA,eAAO,MAAM,0BAA0B,iCAAiC,CAAC;AAEzE,eAAO,MAAM,0BAA0B,uBAAuB,CAAC"}
1
+ {"version":3,"file":"ignore-comment-text.d.mts","sourceRoot":"","sources":["../../../src/functions/constants/ignore-comment-text.mts"],"names":[],"mappings":"AAAA,eAAO,MAAM,4BAA4B,oIAK/B,CAAC;AAEX,eAAO,MAAM,4BAA4B,4FAK/B,CAAC"}
@@ -1,5 +1,15 @@
1
- const IGNORE_LINE_COMMENT_PREFIX = 'transformer-ignore-next-line';
2
- const IGNORE_FILE_COMMENT_PREFIX = 'transformer-ignore';
1
+ const IGNORE_LINE_COMMENT_PREFIXES = [
2
+ 'transformer-ignore-next-line',
3
+ 'ts-codemod-ignore-next-line',
4
+ 'codemod-ignore-next-line',
5
+ 'transform-ignore-next-line',
6
+ ];
7
+ const IGNORE_FILE_COMMENT_PREFIXES = [
8
+ 'transformer-ignore',
9
+ 'ts-codemod-ignore',
10
+ 'codemod-ignore',
11
+ 'transform-ignore',
12
+ ];
3
13
 
4
- export { IGNORE_FILE_COMMENT_PREFIX, IGNORE_LINE_COMMENT_PREFIX };
14
+ export { IGNORE_FILE_COMMENT_PREFIXES, IGNORE_LINE_COMMENT_PREFIXES };
5
15
  //# sourceMappingURL=ignore-comment-text.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ignore-comment-text.mjs","sources":["../../../src/functions/constants/ignore-comment-text.mts"],"sourcesContent":[null],"names":[],"mappings":"AAAO,MAAM,0BAA0B,GAAG;AAEnC,MAAM,0BAA0B,GAAG;;;;"}
1
+ {"version":3,"file":"ignore-comment-text.mjs","sources":["../../../src/functions/constants/ignore-comment-text.mts"],"sourcesContent":[null],"names":[],"mappings":"AAAO,MAAM,4BAA4B,GAAG;IAC1C,8BAA8B;IAC9B,6BAA6B;IAC7B,0BAA0B;IAC1B,4BAA4B;;AAGvB,MAAM,4BAA4B,GAAG;IAC1C,oBAAoB;IACpB,mBAAmB;IACnB,gBAAgB;IAChB,kBAAkB;;;;;"}
@@ -1,2 +1,2 @@
1
- export { IGNORE_FILE_COMMENT_PREFIX, IGNORE_LINE_COMMENT_PREFIX } from './ignore-comment-text.mjs';
1
+ export { IGNORE_FILE_COMMENT_PREFIXES, IGNORE_LINE_COMMENT_PREFIXES } from './ignore-comment-text.mjs';
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1,7 +1,7 @@
1
1
  import * as tsm from 'ts-morph';
2
2
  /**
3
- * Checks if a given ts-morph Node is immediately preceded by a
4
- * '// transformer-ignore-next-line' comment, optionally filtered by transformer name(s).
3
+ * Checks if a given ts-morph Node is immediately preceded by an ignore-next-line comment,
4
+ * optionally filtered by transformer name(s).
5
5
  *
6
6
  * @param node - The ts-morph Node to check.
7
7
  * @param transformerName - Optional transformer name to check for specific ignore directive.
@@ -10,6 +10,7 @@ import * as tsm from 'ts-morph';
10
10
  * - `// transformer-ignore-next-line` (ignores all transformers)
11
11
  * - `// transformer-ignore-next-line append-as-const` (specific transformer)
12
12
  * - `// transformer-ignore-next-line append-as-const, replace-any-with-unknown` (multiple transformers)
13
+ * - Also accepts `ts-codemod-ignore-next-line`, `codemod-ignore-next-line`, `transform-ignore-next-line`
13
14
  * @returns True if the node is preceded by the ignore comment on the immediately previous line, false otherwise.
14
15
  */
15
16
  export declare const hasDisableNextLineComment: (node: tsm.Node, transformerName?: string) => boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"has-disable-next-line-comment.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/has-disable-next-line-comment.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAGhC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB,GACpC,MAAM,GAAG,CAAC,IAAI,EACd,kBAAkB,MAAM,KACvB,OAmEF,CAAC"}
1
+ {"version":3,"file":"has-disable-next-line-comment.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/has-disable-next-line-comment.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAGhC;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,yBAAyB,GACpC,MAAM,GAAG,CAAC,IAAI,EACd,kBAAkB,MAAM,KACvB,OAwEF,CAAC"}
@@ -1,9 +1,9 @@
1
1
  import * as tsm from 'ts-morph';
2
- import { IGNORE_LINE_COMMENT_PREFIX } from '../constants/ignore-comment-text.mjs';
2
+ import { IGNORE_LINE_COMMENT_PREFIXES } from '../constants/ignore-comment-text.mjs';
3
3
 
4
4
  /**
5
- * Checks if a given ts-morph Node is immediately preceded by a
6
- * '// transformer-ignore-next-line' comment, optionally filtered by transformer name(s).
5
+ * Checks if a given ts-morph Node is immediately preceded by an ignore-next-line comment,
6
+ * optionally filtered by transformer name(s).
7
7
  *
8
8
  * @param node - The ts-morph Node to check.
9
9
  * @param transformerName - Optional transformer name to check for specific ignore directive.
@@ -12,6 +12,7 @@ import { IGNORE_LINE_COMMENT_PREFIX } from '../constants/ignore-comment-text.mjs
12
12
  * - `// transformer-ignore-next-line` (ignores all transformers)
13
13
  * - `// transformer-ignore-next-line append-as-const` (specific transformer)
14
14
  * - `// transformer-ignore-next-line append-as-const, replace-any-with-unknown` (multiple transformers)
15
+ * - Also accepts `ts-codemod-ignore-next-line`, `codemod-ignore-next-line`, `transform-ignore-next-line`
15
16
  * @returns True if the node is preceded by the ignore comment on the immediately previous line, false otherwise.
16
17
  */
17
18
  const hasDisableNextLineComment = (node, transformerName) => {
@@ -34,11 +35,13 @@ const hasDisableNextLineComment = (node, transformerName) => {
34
35
  // Check if it's a single-line comment containing the specific ignore text
35
36
  if (commentRange.getKind() === tsm.SyntaxKind.SingleLineCommentTrivia) {
36
37
  const commentText = commentRange.getText().trim();
37
- if (commentText.includes(IGNORE_LINE_COMMENT_PREFIX)) {
38
+ // Check if the comment contains any of the supported ignore prefixes
39
+ const matchedPrefix = IGNORE_LINE_COMMENT_PREFIXES.find((prefix) => commentText.includes(prefix));
40
+ if (matchedPrefix !== undefined) {
38
41
  // Extract the part after the prefix
39
42
  const afterPrefix = commentText
40
- .slice(commentText.indexOf(IGNORE_LINE_COMMENT_PREFIX))
41
- .replace(IGNORE_LINE_COMMENT_PREFIX, '')
43
+ .slice(commentText.indexOf(matchedPrefix))
44
+ .replace(matchedPrefix, '')
42
45
  .trim();
43
46
  // If no transformer name specified, check if comment applies to all transformers
44
47
  if (transformerName === undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"has-disable-next-line-comment.mjs","sources":["../../../src/functions/functions/has-disable-next-line-comment.mts"],"sourcesContent":[null],"names":[],"mappings":";;;AAGA;;;;;;;;;;;;AAYG;MACU,yBAAyB,GAAG,CACvC,IAAc,EACd,eAAwB,KACb;AACX,IAAA,MAAM,aAAa,GAAG,IAAI,CAAC,kBAAkB,EAAE;;AAG/C,IAAA,IAAI,aAAa,IAAI,CAAC,EAAE;AACtB,QAAA,OAAO,KAAK;IACd;IAEA,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;AAExC,IAAA,MAAM,oBAAoB,GAAG,IAAI,CAAC,uBAAuB,EAAE;;AAG3D,IAAA,KAAK,IAAI,KAAK,GAAG,oBAAoB,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE;;AAErE,QAAA,MAAM,YAAY,GAAG,oBAAoB,CAAC,KAAK,CAAE;;AAGjD,QAAA,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,EAAE;QAE3C,MAAM,cAAc,GAAG,UAAU,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC,IAAI;;AAG3E,QAAA,IAAI,aAAa,KAAK,cAAc,GAAG,CAAC,EAAE;;YAExC,IAAI,YAAY,CAAC,OAAO,EAAE,KAAK,GAAG,CAAC,UAAU,CAAC,uBAAuB,EAAE;gBACrE,MAAM,WAAW,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE;AAEjD,gBAAA,IAAI,WAAW,CAAC,QAAQ,CAAC,0BAA0B,CAAC,EAAE;;oBAEpD,MAAM,WAAW,GAAG;AACjB,yBAAA,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,0BAA0B,CAAC;AACrD,yBAAA,OAAO,CAAC,0BAA0B,EAAE,EAAE;AACtC,yBAAA,IAAI,EAAE;;AAGT,oBAAA,IAAI,eAAe,KAAK,SAAS,EAAE;AACjC,wBAAA,OAAO,IAAI;oBACb;;AAGA,oBAAA,IAAI,WAAW,KAAK,EAAE,EAAE;AACtB,wBAAA,OAAO,IAAI;oBACb;;oBAGA,MAAM,kBAAkB,GAAG;yBACxB,KAAK,CAAC,GAAG;yBACT,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;AAE7B,oBAAA,OAAO,kBAAkB,CAAC,QAAQ,CAAC,eAAe,CAAC;gBACrD;YACF;;;;AAKA,YAAA,OAAO,KAAK;QACd;;AAGA,QAAA,IAAI,cAAc,GAAG,aAAa,GAAG,CAAC,EAAE;YACtC;QACF;IACF;AAEA,IAAA,OAAO,KAAK;AACd;;;;"}
1
+ {"version":3,"file":"has-disable-next-line-comment.mjs","sources":["../../../src/functions/functions/has-disable-next-line-comment.mts"],"sourcesContent":[null],"names":[],"mappings":";;;AAGA;;;;;;;;;;;;;AAaG;MACU,yBAAyB,GAAG,CACvC,IAAc,EACd,eAAwB,KACb;AACX,IAAA,MAAM,aAAa,GAAG,IAAI,CAAC,kBAAkB,EAAE;;AAG/C,IAAA,IAAI,aAAa,IAAI,CAAC,EAAE;AACtB,QAAA,OAAO,KAAK;IACd;IAEA,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;AAExC,IAAA,MAAM,oBAAoB,GAAG,IAAI,CAAC,uBAAuB,EAAE;;AAG3D,IAAA,KAAK,IAAI,KAAK,GAAG,oBAAoB,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE;;AAErE,QAAA,MAAM,YAAY,GAAG,oBAAoB,CAAC,KAAK,CAAE;;AAGjD,QAAA,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,EAAE;QAE3C,MAAM,cAAc,GAAG,UAAU,CAAC,qBAAqB,CAAC,aAAa,CAAC,CAAC,IAAI;;AAG3E,QAAA,IAAI,aAAa,KAAK,cAAc,GAAG,CAAC,EAAE;;YAExC,IAAI,YAAY,CAAC,OAAO,EAAE,KAAK,GAAG,CAAC,UAAU,CAAC,uBAAuB,EAAE;gBACrE,MAAM,WAAW,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE;;AAGjD,gBAAA,MAAM,aAAa,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC,MAAM,KAC7D,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,CAC7B;AAED,gBAAA,IAAI,aAAa,KAAK,SAAS,EAAE;;oBAE/B,MAAM,WAAW,GAAG;AACjB,yBAAA,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,aAAa,CAAC;AACxC,yBAAA,OAAO,CAAC,aAAa,EAAE,EAAE;AACzB,yBAAA,IAAI,EAAE;;AAGT,oBAAA,IAAI,eAAe,KAAK,SAAS,EAAE;AACjC,wBAAA,OAAO,IAAI;oBACb;;AAGA,oBAAA,IAAI,WAAW,KAAK,EAAE,EAAE;AACtB,wBAAA,OAAO,IAAI;oBACb;;oBAGA,MAAM,kBAAkB,GAAG;yBACxB,KAAK,CAAC,GAAG;yBACT,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;AAE7B,oBAAA,OAAO,kBAAkB,CAAC,QAAQ,CAAC,eAAe,CAAC;gBACrD;YACF;;;;AAKA,YAAA,OAAO,KAAK;QACd;;AAGA,QAAA,IAAI,cAAc,GAAG,aAAa,GAAG,CAAC,EAAE;YACtC;QACF;IACF;AAEA,IAAA,OAAO,KAAK;AACd;;;;"}
@@ -4,6 +4,7 @@ export * from './is-atomic-type-node.mjs';
4
4
  export * from './is-readonly-node.mjs';
5
5
  export * from './is-spread-parameter-node.mjs';
6
6
  export * from './remove-parentheses.mjs';
7
+ export * from './should-avoid-parentheses-for-readonly.mjs';
7
8
  export * from './unwrap-readonly.mjs';
8
9
  export * from './wrap-with-parentheses.mjs';
9
10
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/index.mts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAC;AACpD,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC"}
1
+ {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/index.mts"],"names":[],"mappings":"AAAA,cAAc,qCAAqC,CAAC;AACpD,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,6CAA6C,CAAC;AAC5D,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC"}
@@ -4,6 +4,7 @@ export { isAtomicTypeNode } from './is-atomic-type-node.mjs';
4
4
  export { isReadonlyArrayTypeNode, isReadonlyTupleOrArrayTypeNode, isReadonlyTupleTypeNode, isReadonlyTypeReferenceNode, isShallowReadonlyTypeNode } from './is-readonly-node.mjs';
5
5
  export { isSpreadNamedTupleMemberNode, isSpreadParameterNode } from './is-spread-parameter-node.mjs';
6
6
  export { removeParentheses } from './remove-parentheses.mjs';
7
+ export { shouldAvoidParenthesesForReadonly } from './should-avoid-parentheses-for-readonly.mjs';
7
8
  export { unwrapReadonlyTypeArgText } from './unwrap-readonly.mjs';
8
9
  export { wrapWithParentheses } from './wrap-with-parentheses.mjs';
9
10
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;"}
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"is-as-const-node.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/is-as-const-node.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,UAAU,CAAC;AAE/B,eAAO,MAAM,aAAa,GACxB,MAAM,EAAE,CAAC,IAAI,KACZ,IAAI,IAAI,EAAE,CAAC,YAAY,GACxB,QAAQ,CAAC;IACP,IAAI,EAAE,EAAE,CAAC,iBAAiB,GACxB,QAAQ,CAAC;QACP,QAAQ,EAAE,EAAE,CAAC,UAAU,GACrB,QAAQ,CAAC;YACP,IAAI,EAAE,OAAO,CAAC;SACf,CAAC,CAAC;QACL,aAAa,EAAE,SAAS,CAAC;KAC1B,CAAC,CAAC;CACN,CAgCF,CAAC"}
1
+ {"version":3,"file":"is-as-const-node.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/is-as-const-node.mts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,UAAU,CAAC;AAE/B,eAAO,MAAM,aAAa,GACxB,MAAM,EAAE,CAAC,IAAI,KACZ,IAAI,IAAI,EAAE,CAAC,YAAY,GACxB,QAAQ,CAAC;IACP,IAAI,EAAE,EAAE,CAAC,iBAAiB,GACxB,QAAQ,CAAC;QACP,QAAQ,EAAE,EAAE,CAAC,UAAU,GACrB,QAAQ,CAAC;YACP,IAAI,EAAE,OAAO,CAAC;SACf,CAAC,CAAC;QACL,aAAa,EAAE,SAAS,CAAC;KAC1B,CAAC,CAAC;CACN,CAgCF,CAAC"}
@@ -1,3 +1,4 @@
1
+ import { Arr } from 'ts-data-forge';
1
2
  import * as tsm from 'ts-morph';
2
3
 
3
4
  const isAsConstNode = (node) => {
@@ -23,7 +24,7 @@ const isAsConstNode = (node) => {
23
24
  // 6. Check if the Identifier's text is 'const'
24
25
  // and that there are no type arguments (as const doesn't have them)
25
26
  return (typeNameNode.getText() === 'const' &&
26
- typeNode.getTypeArguments().length === 0);
27
+ Arr.isArrayOfLength(typeNode.getTypeArguments(), 0));
27
28
  };
28
29
 
29
30
  export { isAsConstNode };
@@ -1 +1 @@
1
- {"version":3,"file":"is-as-const-node.mjs","sources":["../../../src/functions/functions/is-as-const-node.mts"],"sourcesContent":[null],"names":["ts"],"mappings":";;AAEO,MAAM,aAAa,GAAG,CAC3B,IAAa,KAWR;AACL,IAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAACA,GAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE;AAC5C,QAAA,OAAO,KAAK;IACd;;AAGA,IAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE;AAEnC,IAAA,IAAI,QAAQ,KAAK,SAAS,EAAE;QAC1B,OAAO,KAAK,CAAC;IACf;;AAGA,IAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAACA,GAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE;AACjD,QAAA,OAAO,KAAK;IACd;;AAGA,IAAA,MAAM,YAAY,GAAG,QAAQ,CAAC,WAAW,EAAE;;AAG3C,IAAA,IAAI,CAAC,YAAY,CAAC,MAAM,CAACA,GAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;;AAElD,QAAA,OAAO,KAAK;IACd;;;AAIA,IAAA,QACE,YAAY,CAAC,OAAO,EAAE,KAAK,OAAO;QAClC,QAAQ,CAAC,gBAAgB,EAAE,CAAC,MAAM,KAAK,CAAC;AAE5C;;;;"}
1
+ {"version":3,"file":"is-as-const-node.mjs","sources":["../../../src/functions/functions/is-as-const-node.mts"],"sourcesContent":[null],"names":["ts"],"mappings":";;;AAGO,MAAM,aAAa,GAAG,CAC3B,IAAa,KAWR;AACL,IAAA,IAAI,CAAC,IAAI,CAAC,MAAM,CAACA,GAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE;AAC5C,QAAA,OAAO,KAAK;IACd;;AAGA,IAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE;AAEnC,IAAA,IAAI,QAAQ,KAAK,SAAS,EAAE;QAC1B,OAAO,KAAK,CAAC;IACf;;AAGA,IAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAACA,GAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE;AACjD,QAAA,OAAO,KAAK;IACd;;AAGA,IAAA,MAAM,YAAY,GAAG,QAAQ,CAAC,WAAW,EAAE;;AAG3C,IAAA,IAAI,CAAC,YAAY,CAAC,MAAM,CAACA,GAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;;AAElD,QAAA,OAAO,KAAK;IACd;;;AAIA,IAAA,QACE,YAAY,CAAC,OAAO,EAAE,KAAK,OAAO;QAClC,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;AAEvD;;;;"}
@@ -0,0 +1,16 @@
1
+ import * as tsm from 'ts-morph';
2
+ /**
3
+ * Determines if parentheses should be avoided when adding 'readonly' prefix to a type.
4
+ *
5
+ * Parentheses should be AVOIDED in these specific contexts:
6
+ * - Type predicates: `x is [T, U]` -> `x is readonly [T, U]` (not `x is (readonly [T, U])`)
7
+ * because parentheses around the type in a type predicate cause syntax errors
8
+ *
9
+ * For all other contexts, we keep parentheses for safety to avoid precedence issues,
10
+ * relying on prettier to remove unnecessary ones.
11
+ *
12
+ * @param node - The type node to check
13
+ * @returns true if parentheses should be avoided, false otherwise (keep parentheses)
14
+ */
15
+ export declare const shouldAvoidParenthesesForReadonly: (node: tsm.Node) => boolean;
16
+ //# sourceMappingURL=should-avoid-parentheses-for-readonly.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"should-avoid-parentheses-for-readonly.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/should-avoid-parentheses-for-readonly.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iCAAiC,GAAI,MAAM,GAAG,CAAC,IAAI,KAAG,OAgBlE,CAAC"}
@@ -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
+ const shouldAvoidParenthesesForReadonly = (node) => {
17
+ const parent = node.getParent();
18
+ if (parent === undefined) {
19
+ return false;
20
+ }
21
+ // Check if parent is TypePredicate: x is T
22
+ // In this case, we MUST avoid parentheses: x is readonly T (not x is (readonly T))
23
+ // because `x is (readonly T)` is a syntax error
24
+ if (parent.isKind(tsm.SyntaxKind.TypePredicate)) {
25
+ return true;
26
+ }
27
+ // For all other cases, keep parentheses for safety
28
+ return false;
29
+ };
30
+
31
+ export { shouldAvoidParenthesesForReadonly };
32
+ //# sourceMappingURL=should-avoid-parentheses-for-readonly.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"should-avoid-parentheses-for-readonly.mjs","sources":["../../../src/functions/functions/should-avoid-parentheses-for-readonly.mts"],"sourcesContent":[null],"names":[],"mappings":";;AAEA;;;;;;;;;;;;AAYG;AACI,MAAM,iCAAiC,GAAG,CAAC,IAAc,KAAa;AAC3E,IAAA,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE;AAE/B,IAAA,IAAI,MAAM,KAAK,SAAS,EAAE;AACxB,QAAA,OAAO,KAAK;IACd;;;;IAKA,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE;AAC/C,QAAA,OAAO,IAAI;IACb;;AAGA,IAAA,OAAO,KAAK;AACd;;;;"}
@@ -1,2 +1,14 @@
1
- export declare const wrapWithParentheses: (nodeStr: string) => `(${string})`;
1
+ /**
2
+ * Wraps a string with parentheses if not already wrapped.
3
+ * Avoids adding redundant parentheses when the expression is already
4
+ * fully wrapped with balanced parentheses.
5
+ *
6
+ * @example
7
+ * wrapWithParentheses('A') // '(A)'
8
+ * wrapWithParentheses('(A)') // '(A)' (not '((A))')
9
+ * wrapWithParentheses('A | B') // '(A | B)'
10
+ * wrapWithParentheses('(A | B)') // '(A | B)' (not '((A | B))')
11
+ * wrapWithParentheses('(A) | (B)') // '((A) | (B))' (needs outer parens)
12
+ */
13
+ export declare const wrapWithParentheses: (nodeStr: string) => string;
2
14
  //# sourceMappingURL=wrap-with-parentheses.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wrap-with-parentheses.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/wrap-with-parentheses.mts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,GAAI,SAAS,MAAM,KAAG,IAAI,MAAM,GAChC,CAAC"}
1
+ {"version":3,"file":"wrap-with-parentheses.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/wrap-with-parentheses.mts"],"names":[],"mappings":"AAsDA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,GAAI,SAAS,MAAM,KAAG,MAQrD,CAAC"}
@@ -1,4 +1,61 @@
1
- const wrapWithParentheses = (nodeStr) => `(${nodeStr.trim()})`;
1
+ import { range, asUint32 } from 'ts-data-forge';
2
+
3
+ /**
4
+ * Checks if a string is already wrapped with a single pair of balanced parentheses
5
+ * that encompasses the entire expression.
6
+ *
7
+ * @example
8
+ * isWrappedWithParentheses('(A)') // true
9
+ * isWrappedWithParentheses('((A))') // true (outer pair wraps everything)
10
+ * isWrappedWithParentheses('(A) | (B)') // false (outer parens don't wrap everything)
11
+ * isWrappedWithParentheses('A') // false
12
+ */
13
+ const isWrappedWithParentheses = (str) => {
14
+ const trimmed = str.trim();
15
+ if (!trimmed.startsWith('(') || !trimmed.endsWith(')')) {
16
+ return false;
17
+ }
18
+ // Check if the opening and closing parentheses are balanced
19
+ // and the opening parenthesis corresponds to the closing one
20
+ let mut_depth = 0;
21
+ for (const mut_i of range(0, asUint32(trimmed.length))) {
22
+ const char = trimmed.charAt(mut_i);
23
+ switch (char) {
24
+ case '(': {
25
+ mut_depth += 1;
26
+ break;
27
+ }
28
+ case ')': {
29
+ mut_depth -= 1;
30
+ // If we reach depth 0 before the end, the outer parentheses don't wrap everything
31
+ if (mut_depth === 0 && mut_i < trimmed.length - 1) {
32
+ return false;
33
+ }
34
+ break;
35
+ }
36
+ }
37
+ }
38
+ return true;
39
+ };
40
+ /**
41
+ * Wraps a string with parentheses if not already wrapped.
42
+ * Avoids adding redundant parentheses when the expression is already
43
+ * fully wrapped with balanced parentheses.
44
+ *
45
+ * @example
46
+ * wrapWithParentheses('A') // '(A)'
47
+ * wrapWithParentheses('(A)') // '(A)' (not '((A))')
48
+ * wrapWithParentheses('A | B') // '(A | B)'
49
+ * wrapWithParentheses('(A | B)') // '(A | B)' (not '((A | B))')
50
+ * wrapWithParentheses('(A) | (B)') // '((A) | (B))' (needs outer parens)
51
+ */
52
+ const wrapWithParentheses = (nodeStr) => {
53
+ const trimmed = nodeStr.trim();
54
+ if (isWrappedWithParentheses(trimmed)) {
55
+ return trimmed;
56
+ }
57
+ return `(${trimmed})`;
58
+ };
2
59
 
3
60
  export { wrapWithParentheses };
4
61
  //# sourceMappingURL=wrap-with-parentheses.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"wrap-with-parentheses.mjs","sources":["../../../src/functions/functions/wrap-with-parentheses.mts"],"sourcesContent":[null],"names":[],"mappings":"AAAO,MAAM,mBAAmB,GAAG,CAAC,OAAe,KACjD,IAAI,OAAO,CAAC,IAAI,EAAE;;;;"}
1
+ {"version":3,"file":"wrap-with-parentheses.mjs","sources":["../../../src/functions/functions/wrap-with-parentheses.mts"],"sourcesContent":[null],"names":[],"mappings":";;AAAA;;;;;;;;;AASG;AAGH,MAAM,wBAAwB,GAAG,CAAC,GAAW,KAAa;AACxD,IAAA,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE;AAE1B,IAAA,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;AACtD,QAAA,OAAO,KAAK;IACd;;;IAIA,IAAI,SAAS,GAAG,CAAC;AAEjB,IAAA,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE;QACtD,MAAM,IAAI,GAAW,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QAE1C,QAAQ,IAAI;YACV,KAAK,GAAG,EAAE;gBACR,SAAS,IAAI,CAAC;gBAEd;YACF;YAEA,KAAK,GAAG,EAAE;gBACR,SAAS,IAAI,CAAC;;AAGd,gBAAA,IAAI,SAAS,KAAK,CAAC,IAAI,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE;AACjD,oBAAA,OAAO,KAAK;gBACd;gBAEA;YACF;;IAOJ;AAEA,IAAA,OAAO,IAAI;AACb,CAAC;AAED;;;;;;;;;;;AAWG;AACI,MAAM,mBAAmB,GAAG,CAAC,OAAe,KAAY;AAC7D,IAAA,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE;AAE9B,IAAA,IAAI,wBAAwB,CAAC,OAAO,CAAC,EAAE;AACrC,QAAA,OAAO,OAAO;IAChB;IAEA,OAAO,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA,CAAY;AAChC;;;;"}
@@ -8,13 +8,14 @@ export { nextReadonlyContext } from './ast-transformers/readonly-transformer-hel
8
8
  export { replaceAnyWithUnknownTransformer } from './ast-transformers/replace-any-with-unknown.mjs';
9
9
  export { replaceRecordWithUnknownRecordTransformer } from './ast-transformers/replace-record-with-unknown-record.mjs';
10
10
  export { transformSourceCode } from './ast-transformers/transform-source-code.mjs';
11
- export { IGNORE_FILE_COMMENT_PREFIX, IGNORE_LINE_COMMENT_PREFIX } from './constants/ignore-comment-text.mjs';
11
+ export { IGNORE_FILE_COMMENT_PREFIXES, IGNORE_LINE_COMMENT_PREFIXES } from './constants/ignore-comment-text.mjs';
12
12
  export { hasDisableNextLineComment } from './functions/has-disable-next-line-comment.mjs';
13
13
  export { isAsConstNode } from './functions/is-as-const-node.mjs';
14
14
  export { isAtomicTypeNode } from './functions/is-atomic-type-node.mjs';
15
15
  export { isReadonlyArrayTypeNode, isReadonlyTupleOrArrayTypeNode, isReadonlyTupleTypeNode, isReadonlyTypeReferenceNode, isShallowReadonlyTypeNode } from './functions/is-readonly-node.mjs';
16
16
  export { isSpreadNamedTupleMemberNode, isSpreadParameterNode } from './functions/is-spread-parameter-node.mjs';
17
17
  export { removeParentheses } from './functions/remove-parentheses.mjs';
18
+ export { shouldAvoidParenthesesForReadonly } from './functions/should-avoid-parentheses-for-readonly.mjs';
18
19
  export { unwrapReadonlyTypeArgText } from './functions/unwrap-readonly.mjs';
19
20
  export { wrapWithParentheses } from './functions/wrap-with-parentheses.mjs';
20
21
  export { replaceNodeWithDebugPrint } from './utils/replace-with-debug.mjs';
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;"}
package/dist/index.mjs CHANGED
@@ -8,13 +8,14 @@ export { nextReadonlyContext } from './functions/ast-transformers/readonly-trans
8
8
  export { replaceAnyWithUnknownTransformer } from './functions/ast-transformers/replace-any-with-unknown.mjs';
9
9
  export { replaceRecordWithUnknownRecordTransformer } from './functions/ast-transformers/replace-record-with-unknown-record.mjs';
10
10
  export { transformSourceCode } from './functions/ast-transformers/transform-source-code.mjs';
11
- export { IGNORE_FILE_COMMENT_PREFIX, IGNORE_LINE_COMMENT_PREFIX } from './functions/constants/ignore-comment-text.mjs';
11
+ export { IGNORE_FILE_COMMENT_PREFIXES, IGNORE_LINE_COMMENT_PREFIXES } from './functions/constants/ignore-comment-text.mjs';
12
12
  export { hasDisableNextLineComment } from './functions/functions/has-disable-next-line-comment.mjs';
13
13
  export { isAsConstNode } from './functions/functions/is-as-const-node.mjs';
14
14
  export { isAtomicTypeNode } from './functions/functions/is-atomic-type-node.mjs';
15
15
  export { isReadonlyArrayTypeNode, isReadonlyTupleOrArrayTypeNode, isReadonlyTupleTypeNode, isReadonlyTypeReferenceNode, isShallowReadonlyTypeNode } from './functions/functions/is-readonly-node.mjs';
16
16
  export { isSpreadNamedTupleMemberNode, isSpreadParameterNode } from './functions/functions/is-spread-parameter-node.mjs';
17
17
  export { removeParentheses } from './functions/functions/remove-parentheses.mjs';
18
+ export { shouldAvoidParenthesesForReadonly } from './functions/functions/should-avoid-parentheses-for-readonly.mjs';
18
19
  export { unwrapReadonlyTypeArgText } from './functions/functions/unwrap-readonly.mjs';
19
20
  export { wrapWithParentheses } from './functions/functions/wrap-with-parentheses.mjs';
20
21
  export { replaceNodeWithDebugPrint } from './functions/utils/replace-with-debug.mjs';
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-codemod-lib",
3
- "version": "2.0.4",
3
+ "version": "2.1.0",
4
4
  "private": false,
5
5
  "keywords": [
6
6
  "typescript",
@@ -99,7 +99,7 @@
99
99
  "z:vitest:node": "pnpm run z:vitest --project='Node.js'"
100
100
  },
101
101
  "dependencies": {
102
- "ts-data-forge": "6.4.0",
102
+ "ts-data-forge": "6.5.0",
103
103
  "ts-morph": "27.0.2"
104
104
  },
105
105
  "devDependencies": {
@@ -110,36 +110,36 @@
110
110
  "@semantic-release/commit-analyzer": "13.0.1",
111
111
  "@semantic-release/exec": "7.1.0",
112
112
  "@semantic-release/git": "10.0.1",
113
- "@semantic-release/github": "12.0.3",
114
- "@semantic-release/npm": "13.1.3",
113
+ "@semantic-release/github": "12.0.6",
114
+ "@semantic-release/npm": "13.1.4",
115
115
  "@semantic-release/release-notes-generator": "14.1.0",
116
- "@types/node": "25.2.0",
116
+ "@types/node": "25.3.2",
117
117
  "@vitest/browser-playwright": "4.0.18",
118
118
  "@vitest/coverage-v8": "4.0.18",
119
119
  "@vitest/ui": "4.0.18",
120
- "cmd-ts": "0.14.3",
120
+ "cmd-ts": "0.15.0",
121
121
  "conventional-changelog-conventionalcommits": "9.1.0",
122
- "cspell": "9.6.3",
122
+ "cspell": "9.6.4",
123
123
  "dedent": "1.7.1",
124
124
  "eslint": "9.39.2",
125
- "eslint-config-typed": "4.6.1",
126
- "github-settings-as-code": "1.1.2",
125
+ "eslint-config-typed": "4.6.4",
126
+ "github-settings-as-code": "1.1.9",
127
127
  "jiti": "2.6.1",
128
128
  "markdownlint": "0.40.0",
129
- "markdownlint-cli2": "0.20.0",
129
+ "markdownlint-cli2": "0.21.0",
130
130
  "npm-run-all2": "8.0.4",
131
- "playwright": "1.58.1",
131
+ "playwright": "1.58.2",
132
132
  "prettier": "3.8.1",
133
133
  "prettier-plugin-organize-imports": "4.3.0",
134
134
  "prettier-plugin-packagejson": "3.0.0",
135
- "rollup": "4.57.1",
135
+ "rollup": "4.59.0",
136
136
  "semantic-release": "25.0.3",
137
- "ts-repo-utils": "8.1.0",
137
+ "ts-repo-utils": "8.2.0",
138
138
  "ts-type-forge": "2.3.1",
139
139
  "tslib": "2.8.1",
140
140
  "tsx": "4.21.0",
141
- "typedoc": "0.28.16",
142
- "typedoc-github-theme": "0.3.1",
141
+ "typedoc": "0.28.17",
142
+ "typedoc-github-theme": "0.4.0",
143
143
  "typescript": "5.9.3",
144
144
  "vite": "7.3.1",
145
145
  "vitest": "4.0.18"
@@ -160,7 +160,7 @@
160
160
  "optional": true
161
161
  }
162
162
  },
163
- "packageManager": "pnpm@10.29.2",
163
+ "packageManager": "pnpm@10.29.3",
164
164
  "engines": {
165
165
  "node": ">=20.11.0",
166
166
  "pnpm": ">=8.0.0"
@@ -9,7 +9,7 @@ const transformer = appendAsConstTransformer();
9
9
 
10
10
  const cmdDef = cmd.command({
11
11
  name: transformer.name,
12
- version: '2.0.4',
12
+ version: '2.1.0',
13
13
  args: {
14
14
  baseDir: cmd.positional({
15
15
  type: cmd.string,
@@ -9,7 +9,7 @@ const transformer = convertInterfaceToTypeTransformer();
9
9
 
10
10
  const cmdDef = cmd.command({
11
11
  name: transformer.name,
12
- version: '2.0.4',
12
+ version: '2.1.0',
13
13
  args: {
14
14
  baseDir: cmd.positional({
15
15
  type: cmd.string,
@@ -9,7 +9,7 @@ const transformer = convertToReadonlyTransformer();
9
9
 
10
10
  const cmdDef = cmd.command({
11
11
  name: transformer.name,
12
- version: '2.0.4',
12
+ version: '2.1.0',
13
13
  args: {
14
14
  baseDir: cmd.positional({
15
15
  type: cmd.string,
@@ -9,7 +9,7 @@ const transformer = replaceAnyWithUnknownTransformer();
9
9
 
10
10
  const cmdDef = cmd.command({
11
11
  name: transformer.name,
12
- version: '2.0.4',
12
+ version: '2.1.0',
13
13
  args: {
14
14
  baseDir: cmd.positional({
15
15
  type: cmd.string,
@@ -9,7 +9,7 @@ const transformer = replaceRecordWithUnknownRecordTransformer();
9
9
 
10
10
  const cmdDef = cmd.command({
11
11
  name: transformer.name,
12
- version: '2.0.4',
12
+ version: '2.1.0',
13
13
  args: {
14
14
  baseDir: cmd.positional({
15
15
  type: cmd.string,
@@ -44,7 +44,7 @@ export const runTransformerCLI = async (
44
44
 
45
45
  const files = filesResult.value;
46
46
 
47
- if (files.length === 0) {
47
+ if (Arr.isArrayOfLength(files, 0)) {
48
48
  echoIfNotSilent(
49
49
  options.uncommitted
50
50
  ? 'No uncommitted files found'
@@ -71,7 +71,7 @@ export const runTransformerCLI = async (
71
71
  📊 Total: ${files.length}
72
72
  `);
73
73
 
74
- if (errorFiles.length > 0) {
74
+ if (Arr.isNonEmpty(errorFiles)) {
75
75
  echoIfNotSilent('\nFiles with errors:');
76
76
 
77
77
  for (const fileName of errorFiles) {
@@ -81,7 +81,7 @@ export const runTransformerCLI = async (
81
81
 
82
82
  echoIfNotSilent(hr);
83
83
 
84
- if (errorFiles.length > 0) {
84
+ if (Arr.isNonEmpty(errorFiles)) {
85
85
  return Result.err(undefined);
86
86
  }
87
87