ts-codemod-lib 3.5.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -9
- package/dist/functions/ast-transformers/append-as-const.d.mts +13 -4
- package/dist/functions/ast-transformers/append-as-const.d.mts.map +1 -1
- package/dist/functions/ast-transformers/append-as-const.mjs +81 -5
- package/dist/functions/ast-transformers/append-as-const.mjs.map +1 -1
- package/dist/functions/ast-transformers/convert-to-readonly.d.mts +33 -4
- package/dist/functions/ast-transformers/convert-to-readonly.d.mts.map +1 -1
- package/dist/functions/ast-transformers/convert-to-readonly.mjs +155 -30
- package/dist/functions/ast-transformers/convert-to-readonly.mjs.map +1 -1
- package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.d.mts +7 -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 +25 -2
- package/dist/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mjs.map +1 -1
- package/dist/functions/constants/index.d.mts +1 -0
- package/dist/functions/constants/index.d.mts.map +1 -1
- package/dist/functions/constants/index.mjs +1 -0
- package/dist/functions/constants/index.mjs.map +1 -1
- package/dist/functions/constants/mutable-prefixes.d.mts +23 -0
- package/dist/functions/constants/mutable-prefixes.d.mts.map +1 -0
- package/dist/functions/constants/mutable-prefixes.mjs +28 -0
- package/dist/functions/constants/mutable-prefixes.mjs.map +1 -0
- package/package.json +19 -19
- package/src/functions/ast-transformers/append-as-const.mts +152 -15
- package/src/functions/ast-transformers/append-as-const.test.mts +79 -1
- package/src/functions/ast-transformers/convert-to-readonly.mts +302 -57
- package/src/functions/ast-transformers/convert-to-readonly.test.mts +738 -49
- package/src/functions/ast-transformers/readonly-transformer-helpers/group-union-types.mts +36 -5
- package/src/functions/constants/index.mts +1 -0
- package/src/functions/constants/mutable-prefixes.mts +28 -0
|
@@ -22,6 +22,11 @@ import {
|
|
|
22
22
|
* member that `Readonly` still means something to (see `staysOutsideReadonly`):
|
|
23
23
|
* taking such a member out of the `Readonly` it was written under would drop
|
|
24
24
|
* its readonly-ness.
|
|
25
|
+
*
|
|
26
|
+
* `keptUnwrapped` names the further type literals the caller leaves unwrapped
|
|
27
|
+
* (one with a property of an ignored prefix, such as `mut_`), which stay out of
|
|
28
|
+
* that group as one with a call or construct signature does — except under a
|
|
29
|
+
* `Readonly` intersection with a member that may be an array.
|
|
25
30
|
*/
|
|
26
31
|
export const groupUnionIntersectionTypes = (
|
|
27
32
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
@@ -30,10 +35,13 @@ export const groupUnionIntersectionTypes = (
|
|
|
30
35
|
operator,
|
|
31
36
|
underReadonly,
|
|
32
37
|
deepReadonlyTypeName,
|
|
38
|
+
keptUnwrapped = () => false,
|
|
33
39
|
}: Readonly<{
|
|
34
40
|
operator: '&' | '|';
|
|
35
41
|
underReadonly: boolean;
|
|
36
42
|
deepReadonlyTypeName: string;
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
44
|
+
keptUnwrapped?: (node: tsm.TypeLiteralNode) => boolean;
|
|
37
45
|
}>,
|
|
38
46
|
): Readonly<{
|
|
39
47
|
primitives:
|
|
@@ -109,6 +117,28 @@ export const groupUnionIntersectionTypes = (
|
|
|
109
117
|
others: undefined,
|
|
110
118
|
};
|
|
111
119
|
|
|
120
|
+
// Taking a literal out of `Readonly<A & { mut_x: X }>` leaves
|
|
121
|
+
// `Readonly<A> & { mut_x: X }`, which is another type when `A` may be an
|
|
122
|
+
// array (see `isMergeableReadonlyTypeReferenceNode`). So `keptUnwrapped` is
|
|
123
|
+
// honoured under `Readonly<... & ...>` only when every member that stays
|
|
124
|
+
// under it is an object type.
|
|
125
|
+
const honoursKeptUnwrapped =
|
|
126
|
+
!underReadonly ||
|
|
127
|
+
operator === '|' ||
|
|
128
|
+
types.every((t_) => {
|
|
129
|
+
const t = removeParentheses(t_);
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
isAtomicTypeNode(t) ||
|
|
133
|
+
t.isKind(tsm.SyntaxKind.ArrayType) ||
|
|
134
|
+
t.isKind(tsm.SyntaxKind.TupleType) ||
|
|
135
|
+
isReadonlyTupleOrArrayTypeNode(t) ||
|
|
136
|
+
t.isKind(tsm.SyntaxKind.TypeLiteral) ||
|
|
137
|
+
isMergeableReadonlyTypeReferenceNode(t, operator) ||
|
|
138
|
+
staysOutsideReadonly(t, deepReadonlyTypeName)
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
|
|
112
142
|
for (const [i, t_] of types.entries()) {
|
|
113
143
|
const t = removeParentheses(t_);
|
|
114
144
|
|
|
@@ -143,14 +173,15 @@ export const groupUnionIntersectionTypes = (
|
|
|
143
173
|
continue;
|
|
144
174
|
}
|
|
145
175
|
|
|
146
|
-
// A type literal that declares a call or construct signature
|
|
147
|
-
// not grouped here: this group is
|
|
148
|
-
// `Readonly<...>`, which such a literal does
|
|
149
|
-
// to `others`, which leaves it as written. See
|
|
176
|
+
// A type literal that declares a call or construct signature, or one the
|
|
177
|
+
// caller keeps unwrapped, is deliberately not grouped here: this group is
|
|
178
|
+
// joined and wrapped in a single `Readonly<...>`, which such a literal does
|
|
179
|
+
// not survive. It falls through to `others`, which leaves it as written. See
|
|
150
180
|
// `hasCallOrConstructSignature`.
|
|
151
181
|
if (
|
|
152
182
|
(t.isKind(tsm.SyntaxKind.TypeLiteral) &&
|
|
153
|
-
!hasCallOrConstructSignature(t)
|
|
183
|
+
!hasCallOrConstructSignature(t) &&
|
|
184
|
+
!(honoursKeptUnwrapped && keptUnwrapped(t))) ||
|
|
154
185
|
isMergeableReadonlyTypeReferenceNode(t, operator) ||
|
|
155
186
|
(underReadonly && !staysOutsideReadonly(t, deepReadonlyTypeName))
|
|
156
187
|
) {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The default `mutableVariablePrefixes` and `mutablePropertyPrefixes` of the
|
|
3
|
+
* transformers: a name that starts with one of these is left mutable. A
|
|
4
|
+
* private name (`#mut_x`) is matched with or after its `#`.
|
|
5
|
+
*
|
|
6
|
+
* The ESLint counterpart is `ignoredMutablePattern` in
|
|
7
|
+
* `libs/eslint-config-typed/src/rules/eslint-functional-rules.mts` (and, for a
|
|
8
|
+
* property, the `ignoreAccessorPattern` of `functional/immutable-data` there);
|
|
9
|
+
* `libs/eslint-config-typed/src/rules/eslint-functional-rules.test.mts` fails
|
|
10
|
+
* when the two differ; it reads this package's `dist/`, so build first.
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_MUTABLE_PREFIXES: readonly string[] = Object.freeze([
|
|
13
|
+
'mut_',
|
|
14
|
+
]);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The default `mutableTypePrefixes` of the transformers: a type alias, an
|
|
18
|
+
* interface or a class whose name starts with one of these is left mutable,
|
|
19
|
+
* and `append-as-const` adds no `as const` where the value has to be
|
|
20
|
+
* assignable to it (an annotated variable, `satisfies`, an arrow's return).
|
|
21
|
+
* `Mutable` suits the PascalCase of type names; `mut_` is accepted as for
|
|
22
|
+
* variables. No ESLint rule reads type names, so there is no counterpart to
|
|
23
|
+
* keep in step.
|
|
24
|
+
*/
|
|
25
|
+
export const DEFAULT_MUTABLE_TYPE_PREFIXES: readonly string[] = Object.freeze([
|
|
26
|
+
'Mutable',
|
|
27
|
+
'mut_',
|
|
28
|
+
]);
|