ts-codemod-lib 2.2.1 → 2.2.2
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/cmd/append-as-const.mjs +51 -48
- package/dist/cmd/append-as-const.mjs.map +1 -1
- package/dist/cmd/convert-interface-to-type.mjs +51 -48
- package/dist/cmd/convert-interface-to-type.mjs.map +1 -1
- package/dist/cmd/convert-to-readonly.mjs +51 -48
- package/dist/cmd/convert-to-readonly.mjs.map +1 -1
- package/dist/cmd/replace-any-with-unknown.mjs +51 -48
- package/dist/cmd/replace-any-with-unknown.mjs.map +1 -1
- package/dist/cmd/replace-record-with-unknown-record.mjs +51 -48
- package/dist/cmd/replace-record-with-unknown-record.mjs.map +1 -1
- package/dist/cmd/run-transformer-cli.d.mts.map +1 -1
- package/dist/cmd/run-transformer-cli.mjs +138 -127
- package/dist/cmd/run-transformer-cli.mjs.map +1 -1
- package/dist/functions/ast-transformers/append-as-const.d.mts.map +1 -1
- package/dist/functions/ast-transformers/append-as-const.mjs +205 -191
- package/dist/functions/ast-transformers/append-as-const.mjs.map +1 -1
- package/dist/functions/ast-transformers/convert-interface-to-type.mjs +62 -82
- package/dist/functions/ast-transformers/convert-interface-to-type.mjs.map +1 -1
- package/dist/functions/ast-transformers/convert-to-readonly.d.mts.map +1 -1
- package/dist/functions/ast-transformers/convert-to-readonly.mjs +742 -834
- package/dist/functions/ast-transformers/convert-to-readonly.mjs.map +1 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/compare-union-types.d.mts.map +1 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/compare-union-types.mjs +2 -14
- package/dist/functions/ast-transformers/readonly-transformer-helpers/compare-union-types.mjs.map +1 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/constants.d.mts +2 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/constants.d.mts.map +1 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/constants.mjs +8 -8
- package/dist/functions/ast-transformers/readonly-transformer-helpers/constants.mjs.map +1 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.d.mts.map +1 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mjs +51 -62
- package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mjs.map +1 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/readonly-context.d.mts +12 -12
- package/dist/functions/ast-transformers/readonly-transformer-helpers/readonly-context.d.mts.map +1 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/readonly-context.mjs +16 -14
- package/dist/functions/ast-transformers/readonly-transformer-helpers/readonly-context.mjs.map +1 -1
- package/dist/functions/ast-transformers/replace-any-with-unknown.mjs +25 -27
- package/dist/functions/ast-transformers/replace-any-with-unknown.mjs.map +1 -1
- package/dist/functions/ast-transformers/replace-record-with-unknown-record.mjs +149 -208
- package/dist/functions/ast-transformers/replace-record-with-unknown-record.mjs.map +1 -1
- package/dist/functions/ast-transformers/transform-source-code.d.mts.map +1 -1
- package/dist/functions/ast-transformers/transform-source-code.mjs +70 -72
- package/dist/functions/ast-transformers/transform-source-code.mjs.map +1 -1
- package/dist/functions/constants/ignore-comment-text.d.mts +2 -2
- package/dist/functions/constants/ignore-comment-text.d.mts.map +1 -1
- package/dist/functions/constants/ignore-comment-text.mjs +8 -8
- package/dist/functions/constants/ignore-comment-text.mjs.map +1 -1
- package/dist/functions/functions/has-disable-next-line-comment.d.mts.map +1 -1
- package/dist/functions/functions/has-disable-next-line-comment.mjs +33 -65
- package/dist/functions/functions/has-disable-next-line-comment.mjs.map +1 -1
- package/dist/functions/functions/is-as-const-node.d.mts +1 -1
- package/dist/functions/functions/is-as-const-node.d.mts.map +1 -1
- package/dist/functions/functions/is-as-const-node.mjs +15 -23
- package/dist/functions/functions/is-as-const-node.mjs.map +1 -1
- package/dist/functions/functions/is-atomic-type-node.d.mts.map +1 -1
- package/dist/functions/functions/is-atomic-type-node.mjs +22 -36
- package/dist/functions/functions/is-atomic-type-node.mjs.map +1 -1
- package/dist/functions/functions/is-conditional-type-distribution-guard.d.mts.map +1 -1
- package/dist/functions/functions/is-conditional-type-distribution-guard.mjs +9 -33
- package/dist/functions/functions/is-conditional-type-distribution-guard.mjs.map +1 -1
- package/dist/functions/functions/is-readonly-node.d.mts.map +1 -1
- package/dist/functions/functions/is-readonly-node.mjs +11 -21
- package/dist/functions/functions/is-readonly-node.mjs.map +1 -1
- package/dist/functions/functions/is-spread-parameter-node.d.mts.map +1 -1
- package/dist/functions/functions/is-spread-parameter-node.mjs +2 -4
- package/dist/functions/functions/is-spread-parameter-node.mjs.map +1 -1
- package/dist/functions/functions/remove-parentheses.d.mts.map +1 -1
- package/dist/functions/functions/remove-parentheses.mjs +1 -4
- package/dist/functions/functions/remove-parentheses.mjs.map +1 -1
- package/dist/functions/functions/should-avoid-parentheses-for-readonly.d.mts.map +1 -1
- package/dist/functions/functions/should-avoid-parentheses-for-readonly.mjs +7 -24
- package/dist/functions/functions/should-avoid-parentheses-for-readonly.mjs.map +1 -1
- package/dist/functions/functions/unwrap-readonly.d.mts.map +1 -1
- package/dist/functions/functions/unwrap-readonly.mjs +1 -3
- package/dist/functions/functions/unwrap-readonly.mjs.map +1 -1
- package/dist/functions/functions/wrap-with-parentheses.d.mts.map +1 -1
- package/dist/functions/functions/wrap-with-parentheses.mjs +26 -51
- package/dist/functions/functions/wrap-with-parentheses.mjs.map +1 -1
- package/dist/functions/utils/replace-with-debug.d.mts.map +1 -1
- package/dist/functions/utils/replace-with-debug.mjs +2 -2
- package/dist/functions/utils/replace-with-debug.mjs.map +1 -1
- package/package.json +30 -29
- package/src/cmd/append-as-const.mts +3 -3
- package/src/cmd/convert-interface-to-type.mts +3 -3
- package/src/cmd/convert-to-readonly.mts +3 -3
- package/src/cmd/replace-any-with-unknown.mts +3 -3
- package/src/cmd/replace-record-with-unknown-record.mts +3 -3
- package/src/cmd/run-transformer-cli.mts +21 -17
- package/src/functions/ast-transformers/convert-interface-to-type.mts +1 -1
- package/src/functions/ast-transformers/convert-to-readonly.mts +64 -35
- package/src/functions/ast-transformers/convert-to-readonly.test.mts +67 -1
- package/src/functions/ast-transformers/readonly-transformer-helpers/readonly-context.mts +6 -6
- package/src/functions/ast-transformers/replace-record-with-unknown-record.mts +4 -4
- package/src/functions/functions/has-disable-next-line-comment.mts +5 -5
- package/src/functions/functions/wrap-with-parentheses.mts +17 -23
|
@@ -1,39 +1,15 @@
|
|
|
1
1
|
import * as tsm from 'ts-morph';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Determines whether a type node is an operand (check or extends type) of a
|
|
5
|
-
* conditional type whose check type is wrapped to suppress union distribution,
|
|
6
|
-
* i.e. the `X` and `Y` in `X extends Y ? ... : ...` where `X` is itself a tuple
|
|
7
|
-
* or array.
|
|
8
|
-
*
|
|
9
|
-
* Wrapping a naked type parameter so that it is no longer naked is a well-known
|
|
10
|
-
* type-implementation idiom used to suppress union distribution. Both
|
|
11
|
-
* `[A] extends [B] ? ...` (tuple wrapping) and `A[] extends B[] ? ...` (array
|
|
12
|
-
* wrapping) rely on this. Adding a `readonly` modifier to those operands neither
|
|
13
|
-
* makes the type more immutable in any meaningful way nor preserves the idiom's
|
|
14
|
-
* intent, so such operands must be left untouched.
|
|
15
|
-
*
|
|
16
|
-
* A naked check type such as `T extends string[] ? ...` still distributes, so it
|
|
17
|
-
* is not a guard; arrays/tuples in its extends position are converted as usual.
|
|
18
|
-
*
|
|
19
|
-
* @param node - The type node to check
|
|
20
|
-
* @returns true if the node is the check or extends type of a distribution-guarded
|
|
21
|
-
* conditional type
|
|
22
|
-
*/
|
|
23
3
|
const isConditionalTypeDistributionGuard = (node) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
return (checkType.compilerNode === node.compilerNode ||
|
|
36
|
-
parent.getExtendsType().compilerNode === node.compilerNode);
|
|
4
|
+
const parent = node.getParent();
|
|
5
|
+
if (parent?.isKind(tsm.SyntaxKind.ConditionalType) !== true) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
const checkType = parent.getCheckType();
|
|
9
|
+
if (!checkType.isKind(tsm.SyntaxKind.TupleType) && !checkType.isKind(tsm.SyntaxKind.ArrayType)) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
return checkType.compilerNode === node.compilerNode || parent.getExtendsType().compilerNode === node.compilerNode;
|
|
37
13
|
};
|
|
38
14
|
|
|
39
15
|
export { isConditionalTypeDistributionGuard };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-conditional-type-distribution-guard.mjs","sources":["../../../src/functions/functions/is-conditional-type-distribution-guard.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"is-conditional-type-distribution-guard.mjs","sources":["../../../src/functions/functions/is-conditional-type-distribution-guard.mts"],"sourcesContent":["import * as tsm from 'ts-morph';\n\n/**\n * Determines whether a type node is an operand (check or extends type) of a\n * conditional type whose check type is wrapped to suppress union distribution,\n * i.e. the `X` and `Y` in `X extends Y ? ... : ...` where `X` is itself a tuple\n * or array.\n *\n * Wrapping a naked type parameter so that it is no longer naked is a well-known\n * type-implementation idiom used to suppress union distribution. Both\n * `[A] extends [B] ? ...` (tuple wrapping) and `A[] extends B[] ? ...` (array\n * wrapping) rely on this. Adding a `readonly` modifier to those operands neither\n * makes the type more immutable in any meaningful way nor preserves the idiom's\n * intent, so such operands must be left untouched.\n *\n * A naked check type such as `T extends string[] ? ...` still distributes, so it\n * is not a guard; arrays/tuples in its extends position are converted as usual.\n *\n * @param node - The type node to check\n * @returns true if the node is the check or extends type of a distribution-guarded\n * conditional type\n */\nexport const isConditionalTypeDistributionGuard = (node: tsm.Node): boolean => {\n const parent = node.getParent();\n\n if (parent?.isKind(tsm.SyntaxKind.ConditionalType) !== true) {\n return false;\n }\n\n const checkType = parent.getCheckType();\n\n // The guard is only in effect when the check type itself is wrapped in a tuple\n // or array; otherwise (e.g. a naked `T`) the conditional still distributes.\n if (\n !checkType.isKind(tsm.SyntaxKind.TupleType) &&\n !checkType.isKind(tsm.SyntaxKind.ArrayType)\n ) {\n return false;\n }\n\n return (\n checkType.compilerNode === node.compilerNode ||\n parent.getExtendsType().compilerNode === node.compilerNode\n );\n};\n"],"names":[],"mappings":";;AAsBO,MAAM,kCAAA,GAAqC,CAAC,IAAA,KAA4B;AAC7E,EAAA,MAAM,MAAA,GAAS,KAAK,SAAA,EAAU;AAE9B,EAAA,IAAI,QAAQ,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,eAAe,MAAM,IAAA,EAAM;AAC3D,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,SAAA,GAAY,OAAO,YAAA,EAAa;AAItC,EAAA,IACE,CAAC,SAAA,CAAU,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,SAAS,CAAA,IAC1C,CAAC,SAAA,CAAU,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,SAAS,CAAA,EAC1C;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OACE,SAAA,CAAU,iBAAiB,IAAA,CAAK,YAAA,IAChC,OAAO,cAAA,EAAe,CAAE,iBAAiB,IAAA,CAAK,YAAA;AAElD;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-readonly-node.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/is-readonly-node.mts"],"names":[],"mappings":"AACA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,eAAO,MAAM,yBAAyB,
|
|
1
|
+
{"version":3,"file":"is-readonly-node.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/is-readonly-node.mts"],"names":[],"mappings":"AACA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,eAAO,MAAM,yBAAyB,SAAU,GAAG,CAAC,IAAI,KAAG,OAGnC,CAAC;AAEzB,eAAO,MAAM,8BAA8B,SACnC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAC3B,IAAI,IAAI,qBAAqB,GAAG,qBAIqB,CAAC;AAEzD,MAAM,MAAM,qBAAqB,GAAG,GAAG,CAAC,QAAQ,GAC9C,IAAI,CAAC,GAAG,CAAC,oBAAoB,EAAE,aAAa,GAAG,aAAa,CAAC,GAC7D,QAAQ,CAAC;IACP,WAAW,EAAE,MAAM,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC;IAClD,WAAW,EAAE,MAAM,GAAG,CAAC,aAAa,CAAC;CACtC,CAAC,CAAC;AAEL,eAAO,MAAM,uBAAuB,SAC5B,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAC3B,IAAI,IAAI,qBAG0C,CAAC;AA8DtD,MAAM,MAAM,qBAAqB,GAAG,GAAG,CAAC,QAAQ,GAC9C,IAAI,CAAC,GAAG,CAAC,oBAAoB,EAAE,aAAa,GAAG,aAAa,CAAC,GAC7D,QAAQ,CAAC;IACP,WAAW,EAAE,MAAM,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC;IAClD,WAAW,EAAE,MAAM,GAAG,CAAC,aAAa,CAAC;CACtC,CAAC,CAAC;AAEL,eAAO,MAAM,uBAAuB,SAC5B,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAC3B,IAAI,IAAI,qBAG0C,CAAC;AAkDtD,MAAM,MAAM,yBAAyB,GAAG,GAAG,CAAC,QAAQ,GAClD,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,aAAa,GAAG,kBAAkB,CAAC,GAC/D,QAAQ,CAAC;IACP,WAAW,EAAE,MAAM,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,SAAS,CAAC,GAChD,QAAQ,CAAC;QACP,OAAO,EAAE,MAAM,UAAU,CAAC;KAC3B,CAAC,CAAC;IACL,gBAAgB,EAAE,MAAM,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;CACjD,CAAC,CAAC;AAEL,eAAO,MAAM,2BAA2B,SAChC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,KAC3B,IAAI,IAAI,yBAcV,CAAC"}
|
|
@@ -2,28 +2,18 @@ import { Arr } from 'ts-data-forge';
|
|
|
2
2
|
import * as tsm from 'ts-morph';
|
|
3
3
|
import { isAtomicTypeNode } from './is-atomic-type-node.mjs';
|
|
4
4
|
|
|
5
|
-
const isShallowReadonlyTypeNode = (node) => isReadonlyTupleOrArrayTypeNode(node) ||
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
(node.getTypeNode().isKind(tsm.SyntaxKind.ArrayType) || // Use optional chaining and isKind
|
|
11
|
-
node.getTypeNode().isKind(tsm.SyntaxKind.TupleType));
|
|
12
|
-
const isReadonlyArrayTypeNode = (node) => node.isKind(tsm.SyntaxKind.TypeOperator) &&
|
|
13
|
-
node.getOperator() === tsm.SyntaxKind.ReadonlyKeyword &&
|
|
14
|
-
node.getTypeNode().isKind(tsm.SyntaxKind.ArrayType);
|
|
15
|
-
const isReadonlyTupleTypeNode = (node) => node.isKind(tsm.SyntaxKind.TypeOperator) &&
|
|
16
|
-
node.getOperator() === tsm.SyntaxKind.ReadonlyKeyword &&
|
|
17
|
-
node.getTypeNode().isKind(tsm.SyntaxKind.TupleType);
|
|
5
|
+
const isShallowReadonlyTypeNode = (node) => isReadonlyTupleOrArrayTypeNode(node) || isReadonlyTypeReferenceNode(node) || isAtomicTypeNode(node);
|
|
6
|
+
const isReadonlyTupleOrArrayTypeNode = (node) => node.isKind(tsm.SyntaxKind.TypeOperator) && node.getOperator() === tsm.SyntaxKind.ReadonlyKeyword && (node.getTypeNode().isKind(tsm.SyntaxKind.ArrayType) || // Use optional chaining and isKind
|
|
7
|
+
node.getTypeNode().isKind(tsm.SyntaxKind.TupleType));
|
|
8
|
+
const isReadonlyArrayTypeNode = (node) => node.isKind(tsm.SyntaxKind.TypeOperator) && node.getOperator() === tsm.SyntaxKind.ReadonlyKeyword && node.getTypeNode().isKind(tsm.SyntaxKind.ArrayType);
|
|
9
|
+
const isReadonlyTupleTypeNode = (node) => node.isKind(tsm.SyntaxKind.TypeOperator) && node.getOperator() === tsm.SyntaxKind.ReadonlyKeyword && node.getTypeNode().isKind(tsm.SyntaxKind.TupleType);
|
|
18
10
|
const isReadonlyTypeReferenceNode = (node) => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
typeName.getText() === 'Readonly' &&
|
|
26
|
-
Arr.isArrayOfLength(typeArguments, 1));
|
|
11
|
+
if (!node.isKind(tsm.SyntaxKind.TypeReference)) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
const typeName = node.getTypeName();
|
|
15
|
+
const typeArguments = node.getTypeArguments();
|
|
16
|
+
return typeName.isKind(tsm.SyntaxKind.Identifier) && typeName.getText() === "Readonly" && Arr.isArrayOfLength(typeArguments, 1);
|
|
27
17
|
};
|
|
28
18
|
|
|
29
19
|
export { isReadonlyArrayTypeNode, isReadonlyTupleOrArrayTypeNode, isReadonlyTupleTypeNode, isReadonlyTypeReferenceNode, isShallowReadonlyTypeNode };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-readonly-node.mjs","sources":["../../../src/functions/functions/is-readonly-node.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"is-readonly-node.mjs","sources":["../../../src/functions/functions/is-readonly-node.mts"],"sourcesContent":["import { Arr, expectType } from 'ts-data-forge';\nimport * as tsm from 'ts-morph';\nimport { type DeepReadonly } from 'ts-type-forge';\nimport { isAtomicTypeNode } from './is-atomic-type-node.mjs';\n\nexport const isShallowReadonlyTypeNode = (node: tsm.Node): boolean =>\n isReadonlyTupleOrArrayTypeNode(node) ||\n isReadonlyTypeReferenceNode(node) ||\n isAtomicTypeNode(node);\n\nexport const isReadonlyTupleOrArrayTypeNode = (\n node: DeepReadonly<tsm.Node>,\n): node is ReadonlyArrayTypeNode | ReadonlyTupleTypeNode =>\n node.isKind(tsm.SyntaxKind.TypeOperator) &&\n node.getOperator() === tsm.SyntaxKind.ReadonlyKeyword &&\n (node.getTypeNode().isKind(tsm.SyntaxKind.ArrayType) || // Use optional chaining and isKind\n node.getTypeNode().isKind(tsm.SyntaxKind.TupleType));\n\nexport type ReadonlyArrayTypeNode = tsm.TypeNode &\n Omit<tsm.TypeOperatorTypeNode, 'getOperator' | 'getTypeNode'> &\n Readonly<{\n getOperator: () => tsm.SyntaxKind.ReadonlyKeyword;\n getTypeNode: () => tsm.ArrayTypeNode;\n }>;\n\nexport const isReadonlyArrayTypeNode = (\n node: DeepReadonly<tsm.Node>,\n): node is ReadonlyArrayTypeNode =>\n node.isKind(tsm.SyntaxKind.TypeOperator) &&\n node.getOperator() === tsm.SyntaxKind.ReadonlyKeyword &&\n node.getTypeNode().isKind(tsm.SyntaxKind.ArrayType);\n\n// Helper to get a specific type node from source code\nconst getTypeNodeFromSource = (\n sourceCode: string,\n typeName: string,\n): tsm.Node => {\n const project = new tsm.Project({ useInMemoryFileSystem: true });\n\n const sourceFile = project.createSourceFile('test.ts', sourceCode);\n\n const typeAlias = sourceFile.getTypeAliasOrThrow(typeName);\n\n return typeAlias.getTypeNodeOrThrow();\n};\n\nif (import.meta.vitest !== undefined) {\n describe('isReadonlyArrayTypeNode', () => {\n test('should return true for readonly array type', () => {\n const node = getTypeNodeFromSource(\n 'type Test = readonly number[];',\n 'Test',\n );\n\n if (isReadonlyArrayTypeNode(node)) {\n const _operator = node.getOperator();\n\n expectType<typeof _operator, tsm.SyntaxKind.ReadonlyKeyword>('=');\n\n const _typeNode = node.getTypeNode();\n\n expectType<typeof _typeNode, tsm.ArrayTypeNode>('=');\n }\n\n assert.isTrue(node.isKind(tsm.SyntaxKind.TypeOperator));\n\n if (!isReadonlyArrayTypeNode(node)) {\n throw new Error('node should be ReadonlyArrayTypeNode');\n }\n\n expect(node.getOperator()).toBe(tsm.SyntaxKind.ReadonlyKeyword);\n\n assert.isTrue(node.getTypeNode().isKind(tsm.SyntaxKind.ArrayType));\n });\n\n test('should return false for non-readonly array', () => {\n const node = getTypeNodeFromSource('type Test = string[];', 'Test');\n\n assert.isFalse(isReadonlyArrayTypeNode(node));\n });\n\n test('should return false for readonly tuple', () => {\n const node = getTypeNodeFromSource(\n 'type Test = readonly [string];',\n 'Test',\n );\n\n assert.isFalse(isReadonlyArrayTypeNode(node));\n });\n });\n}\n\nexport type ReadonlyTupleTypeNode = tsm.TypeNode &\n Omit<tsm.TypeOperatorTypeNode, 'getOperator' | 'getTypeNode'> &\n Readonly<{\n getOperator: () => tsm.SyntaxKind.ReadonlyKeyword;\n getTypeNode: () => tsm.TupleTypeNode;\n }>;\n\nexport const isReadonlyTupleTypeNode = (\n node: DeepReadonly<tsm.Node>,\n): node is ReadonlyTupleTypeNode =>\n node.isKind(tsm.SyntaxKind.TypeOperator) &&\n node.getOperator() === tsm.SyntaxKind.ReadonlyKeyword &&\n node.getTypeNode().isKind(tsm.SyntaxKind.TupleType);\n\nif (import.meta.vitest !== undefined) {\n describe('isReadonlyTupleTypeNode', () => {\n test('should return true for readonly tuple type', () => {\n const node = getTypeNodeFromSource(\n 'type Test = readonly [number, string];',\n 'Test',\n );\n\n assert.isTrue(isReadonlyTupleTypeNode(node));\n\n if (isReadonlyTupleTypeNode(node)) {\n const _operator = node.getOperator();\n\n expectType<typeof _operator, tsm.SyntaxKind.ReadonlyKeyword>('=');\n\n const _typeNode = node.getTypeNode();\n\n expectType<typeof _typeNode, tsm.TupleTypeNode>('=');\n }\n\n assert.isTrue(node.isKind(tsm.SyntaxKind.TypeOperator));\n\n if (!isReadonlyTupleTypeNode(node)) {\n throw new Error('node should be ReadonlyTupleTypeNode');\n }\n\n expect(node.getOperator()).toBe(tsm.SyntaxKind.ReadonlyKeyword);\n\n assert.isTrue(node.getTypeNode().isKind(tsm.SyntaxKind.TupleType));\n });\n\n test('should return false for non-readonly tuple', () => {\n const node = getTypeNodeFromSource('type Test = [boolean];', 'Test');\n\n assert.isFalse(isReadonlyTupleTypeNode(node));\n });\n\n test('should return false for readonly array', () => {\n const node = getTypeNodeFromSource(\n 'type Test = readonly number[];',\n 'Test',\n );\n\n assert.isFalse(isReadonlyTupleTypeNode(node));\n });\n });\n}\n\nexport type ReadonlyTypeReferenceNode = tsm.TypeNode &\n Omit<tsm.TypeReferenceNode, 'getTypeName' | 'getTypeArguments'> &\n Readonly<{\n getTypeName: () => Omit<tsm.Identifier, 'getText'> &\n Readonly<{\n getText: () => 'Readonly';\n }>;\n getTypeArguments: () => readonly [tsm.TypeNode];\n }>;\n\nexport const isReadonlyTypeReferenceNode = (\n node: DeepReadonly<tsm.Node>,\n): node is ReadonlyTypeReferenceNode => {\n if (!node.isKind(tsm.SyntaxKind.TypeReference)) {\n return false;\n }\n\n const typeName = node.getTypeName();\n\n const typeArguments = node.getTypeArguments();\n\n return (\n typeName.isKind(tsm.SyntaxKind.Identifier) &&\n typeName.getText() === 'Readonly' &&\n Arr.isArrayOfLength(typeArguments, 1)\n );\n};\n\nif (import.meta.vitest !== undefined) {\n describe('isReadonlyTypeReferenceNode', () => {\n test('should return true for Readonly<T>', () => {\n const node = getTypeNodeFromSource(\n 'type Test = Readonly<{ x: number }>;',\n 'Test',\n );\n\n assert.isTrue(isReadonlyTypeReferenceNode(node));\n\n if (isReadonlyTypeReferenceNode(node)) {\n const _typeNameText = node.getTypeName().getText();\n\n expectType<typeof _typeNameText, 'Readonly'>('=');\n\n const _typeArguments = node.getTypeArguments();\n\n expectType<\n typeof _typeArguments,\n readonly [tsm.TypeNode<tsm.ts.TypeNode>]\n >('=');\n }\n\n assert.isTrue(node.isKind(tsm.SyntaxKind.TypeReference));\n\n if (!isReadonlyTypeReferenceNode(node)) {\n throw new Error('node should be ReadonlyNode');\n }\n\n expect(node.getTypeName().getText()).toBe('Readonly');\n\n expect(node.getTypeArguments()).toHaveLength(1);\n });\n\n test('should return false for other type references', () => {\n const node = getTypeNodeFromSource(\n 'type Test = Partial<{ y: string }>;',\n 'Test',\n );\n\n assert.isFalse(isReadonlyTypeReferenceNode(node));\n });\n\n test('should return false for Readonly without type arguments', () => {\n // Note: This is syntactically incorrect TS, but testing the guard\n const node = getTypeNodeFromSource('type Test = Readonly;', 'Test');\n\n assert.isFalse(isReadonlyTypeReferenceNode(node));\n });\n\n test('should return false for Readonly with multiple type arguments', () => {\n // Note: This is syntactically incorrect TS, but testing the guard\n const project = new tsm.Project({ useInMemoryFileSystem: true });\n\n // Need to create manually as TS parser might reject Readonly<A, B>\n const sourceFile = project.createSourceFile(\n 'test.ts',\n 'type Test = Readonly<string, number>;',\n );\n\n const node = sourceFile.getTypeAliasOrThrow('Test').getTypeNodeOrThrow();\n\n assert.isFalse(isReadonlyTypeReferenceNode(node));\n });\n });\n}\n"],"names":[],"mappings":";;;;MAKa,yBAAA,GAA4B,CAAC,IAAA,KACxC,8BAAA,CAA+B,IAAI,KACnC,2BAAA,CAA4B,IAAI,CAAA,IAChC,gBAAA,CAAiB,IAAI;MAEV,8BAAA,GAAiC,CAC5C,IAAA,KAEA,IAAA,CAAK,OAAO,GAAA,CAAI,UAAA,CAAW,YAAY,CAAA,IACvC,IAAA,CAAK,aAAY,KAAM,GAAA,CAAI,WAAW,eAAA,KACrC,IAAA,CAAK,aAAY,CAAE,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,SAAS,CAAA;AACjD,IAAA,CAAK,WAAA,EAAY,CAAE,MAAA,CAAO,GAAA,CAAI,WAAW,SAAS,CAAA;MASzC,uBAAA,GAA0B,CACrC,IAAA,KAEA,IAAA,CAAK,OAAO,GAAA,CAAI,UAAA,CAAW,YAAY,CAAA,IACvC,IAAA,CAAK,aAAY,KAAM,GAAA,CAAI,WAAW,eAAA,IACtC,IAAA,CAAK,aAAY,CAAE,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,SAAS;MAqEvC,uBAAA,GAA0B,CACrC,IAAA,KAEA,IAAA,CAAK,OAAO,GAAA,CAAI,UAAA,CAAW,YAAY,CAAA,IACvC,IAAA,CAAK,aAAY,KAAM,GAAA,CAAI,WAAW,eAAA,IACtC,IAAA,CAAK,aAAY,CAAE,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,SAAS;AA4D7C,MAAM,2BAAA,GAA8B,CACzC,IAAA,KACsC;AACtC,EAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,aAAa,CAAA,EAAG;AAC9C,IAAA,OAAO,KAAA;AAAA,EAAA;AAGT,EAAA,MAAM,QAAA,GAAW,KAAK,WAAA,EAAY;AAElC,EAAA,MAAM,aAAA,GAAgB,KAAK,gBAAA,EAAiB;AAE5C,EAAA,OACE,QAAA,CAAS,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,UAAU,CAAA,IACzC,QAAA,CAAS,OAAA,EAAQ,KAAM,UAAA,IACvB,GAAA,CAAI,eAAA,CAAgB,eAAe,CAAC,CAAA;AAExC;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-spread-parameter-node.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/is-spread-parameter-node.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"is-spread-parameter-node.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/is-spread-parameter-node.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAEhC,eAAO,MAAM,qBAAqB,SAC1B,GAAG,CAAC,IAAI,KACb,IAAI,IAAI,GAAG,CAAC,oBAEyB,CAAC;AAEzC,eAAO,MAAM,4BAA4B,SACjC,GAAG,CAAC,IAAI,KACb,IAAI,IAAI,GAAG,CAAC,gBAEyB,CAAC"}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import * as tsm from 'ts-morph';
|
|
2
2
|
|
|
3
|
-
const isSpreadParameterNode = (node) => node.isKind(tsm.SyntaxKind.Parameter) &&
|
|
4
|
-
|
|
5
|
-
const isSpreadNamedTupleMemberNode = (node) => node.isKind(tsm.SyntaxKind.NamedTupleMember) &&
|
|
6
|
-
node.getDotDotDotToken() !== undefined;
|
|
3
|
+
const isSpreadParameterNode = (node) => node.isKind(tsm.SyntaxKind.Parameter) && node.getDotDotDotToken() !== void 0;
|
|
4
|
+
const isSpreadNamedTupleMemberNode = (node) => node.isKind(tsm.SyntaxKind.NamedTupleMember) && node.getDotDotDotToken() !== void 0;
|
|
7
5
|
|
|
8
6
|
export { isSpreadNamedTupleMemberNode, isSpreadParameterNode };
|
|
9
7
|
//# sourceMappingURL=is-spread-parameter-node.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is-spread-parameter-node.mjs","sources":["../../../src/functions/functions/is-spread-parameter-node.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"is-spread-parameter-node.mjs","sources":["../../../src/functions/functions/is-spread-parameter-node.mts"],"sourcesContent":["import * as tsm from 'ts-morph';\n\nexport const isSpreadParameterNode = (\n node: tsm.Node,\n): node is tsm.ParameterDeclaration =>\n node.isKind(tsm.SyntaxKind.Parameter) &&\n node.getDotDotDotToken() !== undefined;\n\nexport const isSpreadNamedTupleMemberNode = (\n node: tsm.Node,\n): node is tsm.NamedTupleMember =>\n node.isKind(tsm.SyntaxKind.NamedTupleMember) &&\n node.getDotDotDotToken() !== undefined;\n"],"names":[],"mappings":";;AAEO,MAAM,qBAAA,GAAwB,CACnC,IAAA,KAEA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,SAAS,CAAA,IACpC,IAAA,CAAK,iBAAA,EAAkB,KAAM;AAExB,MAAM,4BAAA,GAA+B,CAC1C,IAAA,KAEA,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,gBAAgB,CAAA,IAC3C,IAAA,CAAK,iBAAA,EAAkB,KAAM;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remove-parentheses.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/remove-parentheses.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAGhC,eAAO,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"remove-parentheses.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/remove-parentheses.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAGhC,eAAO,MAAM,iBAAiB,SAAU,GAAG,CAAC,QAAQ,KAAG,GAAG,CAAC,QAGjD,CAAC"}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import * as tsm from 'ts-morph';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
const removeParentheses = (node) => node.isKind(tsm.SyntaxKind.ParenthesizedType)
|
|
5
|
-
? removeParentheses(node.getTypeNode())
|
|
6
|
-
: node;
|
|
3
|
+
const removeParentheses = (node) => node.isKind(tsm.SyntaxKind.ParenthesizedType) ? removeParentheses(node.getTypeNode()) : node;
|
|
7
4
|
|
|
8
5
|
export { removeParentheses };
|
|
9
6
|
//# sourceMappingURL=remove-parentheses.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remove-parentheses.mjs","sources":["../../../src/functions/functions/remove-parentheses.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"remove-parentheses.mjs","sources":["../../../src/functions/functions/remove-parentheses.mts"],"sourcesContent":["import * as tsm from 'ts-morph';\n\n// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types\nexport const removeParentheses = (node: tsm.TypeNode): tsm.TypeNode =>\n node.isKind(tsm.SyntaxKind.ParenthesizedType)\n ? removeParentheses(node.getTypeNode())\n : node;\n"],"names":[],"mappings":";;AAGO,MAAM,iBAAA,GAAoB,CAAC,IAAA,KAChC,IAAA,CAAK,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,iBAAiB,CAAA,GACxC,iBAAA,CAAkB,IAAA,CAAK,WAAA,EAAa,CAAA,GACpC;;;;"}
|
|
@@ -1 +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,
|
|
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,SAAU,GAAG,CAAC,IAAI,KAAG,OAgBlE,CAAC"}
|
|
@@ -1,31 +1,14 @@
|
|
|
1
1
|
import * as tsm from 'ts-morph';
|
|
2
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
3
|
const shouldAvoidParenthesesForReadonly = (node) => {
|
|
17
|
-
|
|
18
|
-
|
|
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
|
|
4
|
+
const parent = node.getParent();
|
|
5
|
+
if (parent === void 0) {
|
|
28
6
|
return false;
|
|
7
|
+
}
|
|
8
|
+
if (parent.isKind(tsm.SyntaxKind.TypePredicate)) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
return false;
|
|
29
12
|
};
|
|
30
13
|
|
|
31
14
|
export { shouldAvoidParenthesesForReadonly };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"should-avoid-parentheses-for-readonly.mjs","sources":["../../../src/functions/functions/should-avoid-parentheses-for-readonly.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"should-avoid-parentheses-for-readonly.mjs","sources":["../../../src/functions/functions/should-avoid-parentheses-for-readonly.mts"],"sourcesContent":["import * as tsm from 'ts-morph';\n\n/**\n * Determines if parentheses should be avoided when adding 'readonly' prefix to a type.\n *\n * Parentheses should be AVOIDED in these specific contexts:\n * - Type predicates: `x is [T, U]` -> `x is readonly [T, U]` (not `x is (readonly [T, U])`)\n * because parentheses around the type in a type predicate cause syntax errors\n *\n * For all other contexts, we keep parentheses for safety to avoid precedence issues,\n * relying on prettier to remove unnecessary ones.\n *\n * @param node - The type node to check\n * @returns true if parentheses should be avoided, false otherwise (keep parentheses)\n */\nexport const shouldAvoidParenthesesForReadonly = (node: tsm.Node): boolean => {\n const parent = node.getParent();\n\n if (parent === undefined) {\n return false;\n }\n\n // Check if parent is TypePredicate: x is T\n // In this case, we MUST avoid parentheses: x is readonly T (not x is (readonly T))\n // because `x is (readonly T)` is a syntax error\n if (parent.isKind(tsm.SyntaxKind.TypePredicate)) {\n return true;\n }\n\n // For all other cases, keep parentheses for safety\n return false;\n};\n"],"names":[],"mappings":";;AAeO,MAAM,iCAAA,GAAoC,CAAC,IAAA,KAA4B;AAC5E,EAAA,MAAM,MAAA,GAAS,KAAK,SAAA,EAAU;AAE9B,EAAA,IAAI,WAAW,MAAA,EAAW;AACxB,IAAA,OAAO,KAAA;AAAA,EACT;AAKA,EAAA,IAAI,MAAA,CAAO,MAAA,CAAO,GAAA,CAAI,UAAA,CAAW,aAAa,CAAA,EAAG;AAC/C,IAAA,OAAO,IAAA;AAAA,EACT;AAGA,EAAA,OAAO,KAAA;AACT;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unwrap-readonly.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/unwrap-readonly.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAGxE,eAAO,MAAM,yBAAyB,
|
|
1
|
+
{"version":3,"file":"unwrap-readonly.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/unwrap-readonly.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AAGxE,eAAO,MAAM,yBAAyB,SAE9B,yBAAyB,KAC9B,MAAuE,CAAC"}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { wrapWithParentheses } from './wrap-with-parentheses.mjs';
|
|
2
2
|
|
|
3
|
-
const unwrapReadonlyTypeArgText = (
|
|
4
|
-
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
5
|
-
node) => wrapWithParentheses(node.getTypeArguments()[0].getFullText());
|
|
3
|
+
const unwrapReadonlyTypeArgText = (node) => wrapWithParentheses(node.getTypeArguments()[0].getFullText());
|
|
6
4
|
|
|
7
5
|
export { unwrapReadonlyTypeArgText };
|
|
8
6
|
//# sourceMappingURL=unwrap-readonly.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unwrap-readonly.mjs","sources":["../../../src/functions/functions/unwrap-readonly.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"unwrap-readonly.mjs","sources":["../../../src/functions/functions/unwrap-readonly.mts"],"sourcesContent":["import { type ReadonlyTypeReferenceNode } from './is-readonly-node.mjs';\nimport { wrapWithParentheses } from './wrap-with-parentheses.mjs';\n\nexport const unwrapReadonlyTypeArgText = (\n // eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types\n node: ReadonlyTypeReferenceNode,\n): string => wrapWithParentheses(node.getTypeArguments()[0].getFullText());\n"],"names":[],"mappings":";;AAGO,MAAM,yBAAA,GAA4B,CAEvC,IAAA,KACW,mBAAA,CAAoB,IAAA,CAAK,kBAAiB,CAAE,CAAC,CAAA,CAAE,WAAA,EAAa;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrap-with-parentheses.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/wrap-with-parentheses.mts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"wrap-with-parentheses.d.mts","sourceRoot":"","sources":["../../../src/functions/functions/wrap-with-parentheses.mts"],"names":[],"mappings":"AAgDA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,YAAa,MAAM,KAAG,MAQrD,CAAC"}
|
|
@@ -1,60 +1,35 @@
|
|
|
1
1
|
import { range, asUint32 } from 'ts-data-forge';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
const parenDepthDelta = (char) => {
|
|
4
|
+
switch (char) {
|
|
5
|
+
case "(":
|
|
6
|
+
return 1;
|
|
7
|
+
case ")":
|
|
8
|
+
return -1;
|
|
9
|
+
default:
|
|
10
|
+
return 0;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
13
|
const isWrappedWithParentheses = (str) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
}
|
|
14
|
+
const trimmed = str.trim();
|
|
15
|
+
if (!trimmed.startsWith("(") || !trimmed.endsWith(")")) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
let mut_depth = 0;
|
|
19
|
+
for (const mut_i of range(0, asUint32(trimmed.length))) {
|
|
20
|
+
mut_depth += parenDepthDelta(trimmed.charAt(mut_i));
|
|
21
|
+
if (mut_depth === 0 && mut_i < trimmed.length - 1) {
|
|
22
|
+
return false;
|
|
37
23
|
}
|
|
38
|
-
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
39
26
|
};
|
|
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
27
|
const wrapWithParentheses = (nodeStr) => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
28
|
+
const trimmed = nodeStr.trim();
|
|
29
|
+
if (isWrappedWithParentheses(trimmed)) {
|
|
30
|
+
return trimmed;
|
|
31
|
+
}
|
|
32
|
+
return `(${trimmed})`;
|
|
58
33
|
};
|
|
59
34
|
|
|
60
35
|
export { wrapWithParentheses };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrap-with-parentheses.mjs","sources":["../../../src/functions/functions/wrap-with-parentheses.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"wrap-with-parentheses.mjs","sources":["../../../src/functions/functions/wrap-with-parentheses.mts"],"sourcesContent":["/**\n * Checks if a string is already wrapped with a single pair of balanced parentheses\n * that encompasses the entire expression.\n *\n * @example\n * isWrappedWithParentheses('(A)') // true\n * isWrappedWithParentheses('((A))') // true (outer pair wraps everything)\n * isWrappedWithParentheses('(A) | (B)') // false (outer parens don't wrap everything)\n * isWrappedWithParentheses('A') // false\n */\nimport { asUint32, range } from 'ts-data-forge';\n\nconst parenDepthDelta = (char: string): number => {\n switch (char) {\n case '(':\n return 1;\n\n case ')':\n return -1;\n\n default:\n return 0;\n }\n};\n\nconst isWrappedWithParentheses = (str: string): boolean => {\n const trimmed = str.trim();\n\n if (!trimmed.startsWith('(') || !trimmed.endsWith(')')) {\n return false;\n }\n\n // Check if the opening and closing parentheses are balanced\n // and the opening parenthesis corresponds to the closing one\n let mut_depth = 0;\n\n for (const mut_i of range(0, asUint32(trimmed.length))) {\n mut_depth += parenDepthDelta(trimmed.charAt(mut_i));\n\n // If we reach depth 0 before the end, the outer parentheses don't wrap everything\n if (mut_depth === 0 && mut_i < trimmed.length - 1) {\n return false;\n }\n }\n\n return true;\n};\n\n/**\n * Wraps a string with parentheses if not already wrapped.\n * Avoids adding redundant parentheses when the expression is already\n * fully wrapped with balanced parentheses.\n *\n * @example\n * wrapWithParentheses('A') // '(A)'\n * wrapWithParentheses('(A)') // '(A)' (not '((A))')\n * wrapWithParentheses('A | B') // '(A | B)'\n * wrapWithParentheses('(A | B)') // '(A | B)' (not '((A | B))')\n * wrapWithParentheses('(A) | (B)') // '((A) | (B))' (needs outer parens)\n */\nexport const wrapWithParentheses = (nodeStr: string): string => {\n const trimmed = nodeStr.trim();\n\n if (isWrappedWithParentheses(trimmed)) {\n return trimmed;\n }\n\n return `(${trimmed})` as const;\n};\n"],"names":[],"mappings":";;AAYA,MAAM,eAAA,GAAkB,CAAC,IAAA,KAAyB;AAChD,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,GAAA;AACH,MAAA,OAAO,CAAA;AAAA,IAET,KAAK,GAAA;AACH,MAAA,OAAO,EAAA;AAAA,IAET;AACE,MAAA,OAAO,CAAA;AAAA;AAEb,CAAA;AAEA,MAAM,wBAAA,GAA2B,CAAC,GAAA,KAAyB;AACzD,EAAA,MAAM,OAAA,GAAU,IAAI,IAAA,EAAK;AAEzB,EAAA,IAAI,CAAC,QAAQ,UAAA,CAAW,GAAG,KAAK,CAAC,OAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,EAAG;AACtD,IAAA,OAAO,KAAA;AAAA,EACT;AAIA,EAAA,IAAI,SAAA,GAAY,CAAA;AAEhB,EAAA,KAAA,MAAW,SAAS,KAAA,CAAM,CAAA,EAAG,SAAS,OAAA,CAAQ,MAAM,CAAC,CAAA,EAAG;AACtD,IAAA,SAAA,IAAa,eAAA,CAAgB,OAAA,CAAQ,MAAA,CAAO,KAAK,CAAC,CAAA;AAGlD,IAAA,IAAI,SAAA,KAAc,CAAA,IAAK,KAAA,GAAQ,OAAA,CAAQ,SAAS,CAAA,EAAG;AACjD,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT,CAAA;AAcO,MAAM,mBAAA,GAAsB,CAAC,OAAA,KAA4B;AAC9D,EAAA,MAAM,OAAA,GAAU,QAAQ,IAAA,EAAK;AAE7B,EAAA,IAAI,wBAAA,CAAyB,OAAO,CAAA,EAAG;AACrC,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,OAAO,IAAI,OAAO,CAAA,CAAA,CAAA;AACpB;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replace-with-debug.d.mts","sourceRoot":"","sources":["../../../src/functions/utils/replace-with-debug.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,CAAC;AAErC,eAAO,MAAM,yBAAyB,
|
|
1
|
+
{"version":3,"file":"replace-with-debug.d.mts","sourceRoot":"","sources":["../../../src/functions/utils/replace-with-debug.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,CAAC;AAErC,eAAO,MAAM,yBAAyB,SAC9B,GAAG,CAAC,IAAI,eACD,MAAM,KAClB,IAIF,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const replaceNodeWithDebugPrint = (node, newNodeText) => {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
console.debug(`${node.getText()} -> ${newNodeText}`);
|
|
3
|
+
node.replaceWithText(newNodeText);
|
|
4
4
|
};
|
|
5
5
|
|
|
6
6
|
export { replaceNodeWithDebugPrint };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replace-with-debug.mjs","sources":["../../../src/functions/utils/replace-with-debug.mts"],"sourcesContent":[
|
|
1
|
+
{"version":3,"file":"replace-with-debug.mjs","sources":["../../../src/functions/utils/replace-with-debug.mts"],"sourcesContent":["import type * as tsm from 'ts-morph';\n\nexport const replaceNodeWithDebugPrint = (\n node: tsm.Node,\n newNodeText: string,\n): void => {\n console.debug(`${node.getText()} -> ${newNodeText}`);\n\n node.replaceWithText(newNodeText);\n};\n"],"names":[],"mappings":"AAEO,MAAM,yBAAA,GAA4B,CACvC,IAAA,EACA,WAAA,KACS;AACT,EAAA,OAAA,CAAQ,MAAM,CAAA,EAAG,IAAA,CAAK,SAAS,CAAA,IAAA,EAAO,WAAW,CAAA,CAAE,CAAA;AAEnD,EAAA,IAAA,CAAK,gBAAgB,WAAW,CAAA;AAClC;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-codemod-lib",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -97,22 +97,21 @@
|
|
|
97
97
|
"test:cov:ui": "vite preview --outDir ./coverage",
|
|
98
98
|
"test:ui": "pnpm run z:vitest:node --ui",
|
|
99
99
|
"testw": "pnpm run z:vitest:node watch",
|
|
100
|
-
"tsc": "tsc --noEmit",
|
|
101
|
-
"tscw": "tsc --noEmit --watch -p ./tsconfig.json",
|
|
102
|
-
"type-check": "tsc --noEmit",
|
|
103
|
-
"update-packages": "pnpm update --latest",
|
|
100
|
+
"tsc": "node ./node_modules/typescript-native/bin/tsc --noEmit",
|
|
101
|
+
"tscw": "node ./node_modules/typescript-native/bin/tsc --noEmit --watch -p ./tsconfig.json",
|
|
102
|
+
"type-check": "node ./node_modules/typescript-native/bin/tsc --noEmit",
|
|
103
|
+
"update-packages": "pnpm update --latest '!typescript'",
|
|
104
104
|
"z:vitest": "vitest --config ./configs/vitest.config.mts",
|
|
105
105
|
"z:vitest:node": "pnpm run z:vitest --project='Node.js'"
|
|
106
106
|
},
|
|
107
107
|
"dependencies": {
|
|
108
|
-
"ts-data-forge": "^
|
|
108
|
+
"ts-data-forge": "^7.1.1",
|
|
109
109
|
"ts-morph": "^28.0.0",
|
|
110
|
-
"ts-type-forge": "^
|
|
110
|
+
"ts-type-forge": "^4.0.0"
|
|
111
111
|
},
|
|
112
112
|
"devDependencies": {
|
|
113
113
|
"@rollup/plugin-replace": "6.0.3",
|
|
114
114
|
"@rollup/plugin-strip": "3.0.4",
|
|
115
|
-
"@rollup/plugin-typescript": "12.3.0",
|
|
116
115
|
"@semantic-release/changelog": "6.0.3",
|
|
117
116
|
"@semantic-release/commit-analyzer": "13.0.1",
|
|
118
117
|
"@semantic-release/exec": "7.1.0",
|
|
@@ -120,35 +119,37 @@
|
|
|
120
119
|
"@semantic-release/github": "12.0.8",
|
|
121
120
|
"@semantic-release/npm": "13.1.5",
|
|
122
121
|
"@semantic-release/release-notes-generator": "14.1.1",
|
|
123
|
-
"@types/node": "
|
|
124
|
-
"@vitest/browser-playwright": "4.1.
|
|
125
|
-
"@vitest/coverage-v8": "4.1.
|
|
126
|
-
"@vitest/ui": "4.1.
|
|
122
|
+
"@types/node": "26.1.0",
|
|
123
|
+
"@vitest/browser-playwright": "4.1.10",
|
|
124
|
+
"@vitest/coverage-v8": "4.1.10",
|
|
125
|
+
"@vitest/ui": "4.1.9",
|
|
127
126
|
"cmd-ts": "0.15.0",
|
|
128
|
-
"conventional-changelog-conventionalcommits": "
|
|
127
|
+
"conventional-changelog-conventionalcommits": "10.2.1",
|
|
129
128
|
"cspell": "10.0.1",
|
|
130
129
|
"dedent": "1.7.2",
|
|
131
|
-
"
|
|
132
|
-
"eslint
|
|
130
|
+
"esbuild": "0.28.1",
|
|
131
|
+
"eslint": "10.6.0",
|
|
132
|
+
"eslint-config-typed": "5.4.0",
|
|
133
133
|
"github-settings-as-code": "1.2.9",
|
|
134
134
|
"jiti": "2.7.0",
|
|
135
|
-
"markdownlint": "0.
|
|
136
|
-
"markdownlint-cli2": "0.
|
|
137
|
-
"npm-run-all2": "
|
|
138
|
-
"playwright": "1.
|
|
139
|
-
"prettier": "3.
|
|
135
|
+
"markdownlint": "0.41.0",
|
|
136
|
+
"markdownlint-cli2": "0.23.0",
|
|
137
|
+
"npm-run-all2": "9.0.2",
|
|
138
|
+
"playwright": "1.61.1",
|
|
139
|
+
"prettier": "3.9.4",
|
|
140
140
|
"prettier-plugin-organize-imports": "4.3.0",
|
|
141
141
|
"prettier-plugin-packagejson": "3.0.2",
|
|
142
|
-
"rollup": "4.
|
|
142
|
+
"rollup": "4.62.2",
|
|
143
|
+
"rollup-plugin-esbuild": "6.2.1",
|
|
143
144
|
"semantic-release": "25.0.5",
|
|
144
145
|
"ts-repo-utils": "10.1.2",
|
|
145
|
-
"
|
|
146
|
-
"tsx": "4.22.3",
|
|
146
|
+
"tsx": "4.23.0",
|
|
147
147
|
"typedoc": "0.28.19",
|
|
148
148
|
"typedoc-github-theme": "0.4.0",
|
|
149
|
-
"typescript": "
|
|
150
|
-
"
|
|
151
|
-
"
|
|
149
|
+
"typescript": "6.0.3",
|
|
150
|
+
"typescript-native": "npm:typescript@7.0.1-rc",
|
|
151
|
+
"vite": "8.1.2",
|
|
152
|
+
"vitest": "4.1.9"
|
|
152
153
|
},
|
|
153
154
|
"peerDependencies": {
|
|
154
155
|
"cmd-ts": "0.14.3",
|
|
@@ -166,12 +167,12 @@
|
|
|
166
167
|
"optional": true
|
|
167
168
|
}
|
|
168
169
|
},
|
|
169
|
-
"packageManager": "pnpm@10.
|
|
170
|
+
"packageManager": "pnpm@11.10.0+sha512.0b7f8b98060031904c017e3a41eb187a16d40eeb829b95c4f8cb03681761fc4ab53dd219115b9b447f4dce1a05a214764461e7d3703392a9f32f9511ce8c86c8",
|
|
170
171
|
"engines": {
|
|
171
|
-
"node": ">=22.
|
|
172
|
+
"node": ">=22.22.2",
|
|
172
173
|
"pnpm": ">=9.0.0"
|
|
173
174
|
},
|
|
174
175
|
"volta": {
|
|
175
|
-
"node": "
|
|
176
|
+
"node": "26.3.1"
|
|
176
177
|
}
|
|
177
178
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import * as cmd from 'cmd-ts';
|
|
4
|
-
import { Result } from 'ts-data-forge';
|
|
4
|
+
import { Arr, Result } from 'ts-data-forge';
|
|
5
5
|
import { appendAsConstTransformer } from '../functions/index.mjs';
|
|
6
6
|
import { runTransformerCLI } from './run-transformer-cli.mjs';
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@ const transformer = appendAsConstTransformer();
|
|
|
9
9
|
|
|
10
10
|
const cmdDef = cmd.command({
|
|
11
11
|
name: transformer.name,
|
|
12
|
-
version: '2.2.
|
|
12
|
+
version: '2.2.2',
|
|
13
13
|
args: {
|
|
14
14
|
baseDir: cmd.positional({
|
|
15
15
|
type: cmd.string,
|
|
@@ -64,4 +64,4 @@ const cmdDef = cmd.command({
|
|
|
64
64
|
},
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
await cmd.run(cmdDef, process.argv
|
|
67
|
+
await cmd.run(cmdDef, Arr.skip(process.argv, 2));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import * as cmd from 'cmd-ts';
|
|
4
|
-
import { Result } from 'ts-data-forge';
|
|
4
|
+
import { Arr, Result } from 'ts-data-forge';
|
|
5
5
|
import { convertInterfaceToTypeTransformer } from '../functions/index.mjs';
|
|
6
6
|
import { runTransformerCLI } from './run-transformer-cli.mjs';
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@ const transformer = convertInterfaceToTypeTransformer();
|
|
|
9
9
|
|
|
10
10
|
const cmdDef = cmd.command({
|
|
11
11
|
name: transformer.name,
|
|
12
|
-
version: '2.2.
|
|
12
|
+
version: '2.2.2',
|
|
13
13
|
args: {
|
|
14
14
|
baseDir: cmd.positional({
|
|
15
15
|
type: cmd.string,
|
|
@@ -64,4 +64,4 @@ const cmdDef = cmd.command({
|
|
|
64
64
|
},
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
await cmd.run(cmdDef, process.argv
|
|
67
|
+
await cmd.run(cmdDef, Arr.skip(process.argv, 2));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import * as cmd from 'cmd-ts';
|
|
4
|
-
import { Result } from 'ts-data-forge';
|
|
4
|
+
import { Arr, Result } from 'ts-data-forge';
|
|
5
5
|
import { convertToReadonlyTransformer } from '../functions/index.mjs';
|
|
6
6
|
import { runTransformerCLI } from './run-transformer-cli.mjs';
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@ const transformer = convertToReadonlyTransformer();
|
|
|
9
9
|
|
|
10
10
|
const cmdDef = cmd.command({
|
|
11
11
|
name: transformer.name,
|
|
12
|
-
version: '2.2.
|
|
12
|
+
version: '2.2.2',
|
|
13
13
|
args: {
|
|
14
14
|
baseDir: cmd.positional({
|
|
15
15
|
type: cmd.string,
|
|
@@ -64,4 +64,4 @@ const cmdDef = cmd.command({
|
|
|
64
64
|
},
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
await cmd.run(cmdDef, process.argv
|
|
67
|
+
await cmd.run(cmdDef, Arr.skip(process.argv, 2));
|