ts-codemod-lib 3.5.1 → 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.
Files changed (24) hide show
  1. package/README.md +7 -3
  2. package/dist/functions/ast-transformers/append-as-const.d.mts +13 -4
  3. package/dist/functions/ast-transformers/append-as-const.d.mts.map +1 -1
  4. package/dist/functions/ast-transformers/append-as-const.mjs +80 -7
  5. package/dist/functions/ast-transformers/append-as-const.mjs.map +1 -1
  6. package/dist/functions/ast-transformers/convert-to-readonly.d.mts +23 -4
  7. package/dist/functions/ast-transformers/convert-to-readonly.d.mts.map +1 -1
  8. package/dist/functions/ast-transformers/convert-to-readonly.mjs +40 -19
  9. package/dist/functions/ast-transformers/convert-to-readonly.mjs.map +1 -1
  10. package/dist/functions/constants/index.d.mts +1 -0
  11. package/dist/functions/constants/index.d.mts.map +1 -1
  12. package/dist/functions/constants/index.mjs +1 -0
  13. package/dist/functions/constants/index.mjs.map +1 -1
  14. package/dist/functions/constants/mutable-prefixes.d.mts +23 -0
  15. package/dist/functions/constants/mutable-prefixes.d.mts.map +1 -0
  16. package/dist/functions/constants/mutable-prefixes.mjs +28 -0
  17. package/dist/functions/constants/mutable-prefixes.mjs.map +1 -0
  18. package/package.json +2 -2
  19. package/src/functions/ast-transformers/append-as-const.mts +152 -18
  20. package/src/functions/ast-transformers/append-as-const.test.mts +79 -1
  21. package/src/functions/ast-transformers/convert-to-readonly.mts +124 -41
  22. package/src/functions/ast-transformers/convert-to-readonly.test.mts +321 -41
  23. package/src/functions/constants/index.mts +1 -0
  24. package/src/functions/constants/mutable-prefixes.mts +28 -0
@@ -1980,6 +1980,7 @@ describe(convertToReadonlyTransformer, () => {
1980
1980
  }
1981
1981
  }
1982
1982
  `,
1983
+ options: { mutablePropertyPrefixes: ['_mut_'] },
1983
1984
  },
1984
1985
  {
1985
1986
  name: 'Method with "draft" prefix',
@@ -1997,6 +1998,7 @@ describe(convertToReadonlyTransformer, () => {
1997
1998
  }
1998
1999
  }
1999
2000
  `,
2001
+ options: { mutablePropertyPrefixes: ['draft'] },
2000
2002
  },
2001
2003
  {
2002
2004
  name: 'Method without mut_ prefix should be transformed',
@@ -3977,15 +3979,20 @@ describe(convertToReadonlyTransformer, () => {
3977
3979
  type T = { draftItems: number[]; readonly b: readonly string[] };
3978
3980
  type U = { mutable_items: number[]; readonly b: readonly string[] };
3979
3981
  `,
3980
- options: { ignorePrefixes: ['draft', 'mutable_'] },
3982
+ options: {
3983
+ mutableVariablePrefixes: ['draft', 'mutable_'],
3984
+ mutablePropertyPrefixes: ['draft', 'mutable_'],
3985
+ },
3981
3986
  },
3982
3987
  {
3983
- name: 'The "_mut_" prefix is recognized by default',
3988
+ name: '"mut_" alone is the default: it covers "#mut_" and no longer "_mut_"',
3984
3989
  source: dedent`
3985
3990
  type T = { _mut_items: number[]; b: string[] };
3991
+ class C { #mut_items: number[] = []; c: string[] = []; }
3986
3992
  `,
3987
3993
  expected: dedent`
3988
- type T = { _mut_items: number[]; readonly b: readonly string[] };
3994
+ type T = Readonly<{ _mut_items: readonly number[]; b: readonly string[] }>;
3995
+ class C { #mut_items: number[] = []; readonly c: readonly string[] = []; }
3989
3996
  `,
3990
3997
  },
3991
3998
  {
@@ -4291,7 +4298,7 @@ describe(convertToReadonlyTransformer, () => {
4291
4298
  expected: dedent`
4292
4299
  type T = Readonly<{ mut_a: readonly number[]; b: readonly string[] }>;
4293
4300
  `,
4294
- options: { ignorePrefixes: [] },
4301
+ options: { mutableVariablePrefixes: [], mutablePropertyPrefixes: [] },
4295
4302
  },
4296
4303
  ])('$name', testFn);
4297
4304
 
@@ -4849,7 +4856,7 @@ describe(convertToReadonlyTransformer, () => {
4849
4856
  ])('$name', testFn);
4850
4857
  });
4851
4858
 
4852
- describe('ignorePrefixes option', () => {
4859
+ describe('mutableVariablePrefixes and mutablePropertyPrefixes options', () => {
4853
4860
  test.each([
4854
4861
  {
4855
4862
  name: 'Variable declarations',
@@ -4872,10 +4879,10 @@ describe(convertToReadonlyTransformer, () => {
4872
4879
  {
4873
4880
  name: 'Type aliases',
4874
4881
  source: dedent`
4875
- type mut_Foo = number[]
4882
+ type MutableFoo = number[]
4876
4883
  `,
4877
4884
  expected: dedent`
4878
- type mut_Foo = number[]
4885
+ type MutableFoo = number[]
4879
4886
  `,
4880
4887
  },
4881
4888
  {
@@ -4889,7 +4896,10 @@ describe(convertToReadonlyTransformer, () => {
4889
4896
  readonly normalValue: readonly string[];
4890
4897
  };
4891
4898
  `,
4892
- options: { ignorePrefixes: ['mut_'] },
4899
+ options: {
4900
+ mutableVariablePrefixes: ['mut_'],
4901
+ mutablePropertyPrefixes: ['mut_'],
4902
+ },
4893
4903
  },
4894
4904
  {
4895
4905
  name: 'Multiple ignore prefixes',
@@ -4903,7 +4913,10 @@ describe(convertToReadonlyTransformer, () => {
4903
4913
  readonly normalValue: readonly boolean[];
4904
4914
  };
4905
4915
  `,
4906
- options: { ignorePrefixes: ['mut_', 'mutable_'] },
4916
+ options: {
4917
+ mutableVariablePrefixes: ['mut_', 'mutable_'],
4918
+ mutablePropertyPrefixes: ['mut_', 'mutable_'],
4919
+ },
4907
4920
  },
4908
4921
  {
4909
4922
  name: 'Ignore prefix in nested properties',
@@ -4923,7 +4936,10 @@ describe(convertToReadonlyTransformer, () => {
4923
4936
  };
4924
4937
  }>;
4925
4938
  `,
4926
- options: { ignorePrefixes: ['mut_'] },
4939
+ options: {
4940
+ mutableVariablePrefixes: ['mut_'],
4941
+ mutablePropertyPrefixes: ['mut_'],
4942
+ },
4927
4943
  },
4928
4944
  {
4929
4945
  name: 'Ignore prefix in interface',
@@ -4939,7 +4955,10 @@ describe(convertToReadonlyTransformer, () => {
4939
4955
  readonly roles: readonly string[];
4940
4956
  }
4941
4957
  `,
4942
- options: { ignorePrefixes: ['mut_'] },
4958
+ options: {
4959
+ mutableVariablePrefixes: ['mut_'],
4960
+ mutablePropertyPrefixes: ['mut_'],
4961
+ },
4943
4962
  },
4944
4963
  {
4945
4964
  name: 'Ignore prefixes for various name node types in interface',
@@ -4961,7 +4980,10 @@ describe(convertToReadonlyTransformer, () => {
4961
4980
  readonly ['mu' + 't_d']: readonly string[]; // ComputedPropertyName
4962
4981
  }
4963
4982
  `,
4964
- options: { ignorePrefixes: ['mut_'] },
4983
+ options: {
4984
+ mutableVariablePrefixes: ['mut_'],
4985
+ mutablePropertyPrefixes: ['mut_'],
4986
+ },
4965
4987
  },
4966
4988
  {
4967
4989
  name: 'Ignore prefix with index signature',
@@ -4979,7 +5001,10 @@ describe(convertToReadonlyTransformer, () => {
4979
5001
  };
4980
5002
  };
4981
5003
  `,
4982
- options: { ignorePrefixes: ['mut_'] },
5004
+ options: {
5005
+ mutableVariablePrefixes: ['mut_'],
5006
+ mutablePropertyPrefixes: ['mut_'],
5007
+ },
4983
5008
  },
4984
5009
  {
4985
5010
  name: 'Index signature in ignored property',
@@ -4997,21 +5022,27 @@ describe(convertToReadonlyTransformer, () => {
4997
5022
  };
4998
5023
  }
4999
5024
  `,
5000
- options: { ignorePrefixes: ['mut_'] },
5025
+ options: {
5026
+ mutableVariablePrefixes: ['mut_'],
5027
+ mutablePropertyPrefixes: ['mut_'],
5028
+ },
5001
5029
  },
5002
5030
  {
5003
5031
  name: 'Type alias with ignored prefix',
5004
5032
  source: dedent`
5005
- type mut_Config = {
5033
+ type MutableConfig = {
5006
5034
  items: string[];
5007
5035
  };
5008
5036
  `,
5009
5037
  expected: dedent`
5010
- type mut_Config = {
5038
+ type MutableConfig = {
5011
5039
  items: string[];
5012
5040
  };
5013
5041
  `,
5014
- options: { ignorePrefixes: ['mut_'] },
5042
+ options: {
5043
+ mutableVariablePrefixes: ['mut_'],
5044
+ mutablePropertyPrefixes: ['mut_'],
5045
+ },
5015
5046
  },
5016
5047
  {
5017
5048
  name: 'Function with ignored prefix',
@@ -5021,21 +5052,27 @@ describe(convertToReadonlyTransformer, () => {
5021
5052
  expected: dedent`
5022
5053
  function mut_process(data: string[]): number[] { return []; }
5023
5054
  `,
5024
- options: { ignorePrefixes: ['mut_'] },
5055
+ options: {
5056
+ mutableVariablePrefixes: ['mut_'],
5057
+ mutablePropertyPrefixes: ['mut_'],
5058
+ },
5025
5059
  },
5026
5060
  {
5027
5061
  name: 'Class with ignored prefix',
5028
5062
  source: dedent`
5029
- class mut_Store {
5063
+ class MutableStore {
5030
5064
  items: string[] = [];
5031
5065
  }
5032
5066
  `,
5033
5067
  expected: dedent`
5034
- class mut_Store {
5068
+ class MutableStore {
5035
5069
  items: string[] = [];
5036
5070
  }
5037
5071
  `,
5038
- options: { ignorePrefixes: ['mut_'] },
5072
+ options: {
5073
+ mutableVariablePrefixes: ['mut_'],
5074
+ mutablePropertyPrefixes: ['mut_'],
5075
+ },
5039
5076
  },
5040
5077
  {
5041
5078
  name: 'Variable declaration with ignored prefix',
@@ -5045,37 +5082,46 @@ describe(convertToReadonlyTransformer, () => {
5045
5082
  expected: dedent`
5046
5083
  const mut_items: string[] = []
5047
5084
  `,
5048
- options: { ignorePrefixes: ['mut_'] },
5085
+ options: {
5086
+ mutableVariablePrefixes: ['mut_'],
5087
+ mutablePropertyPrefixes: ['mut_'],
5088
+ },
5049
5089
  },
5050
5090
  {
5051
5091
  name: 'Generic type with ignored prefix',
5052
5092
  source: dedent`
5053
- type mut_List<T> = {
5093
+ type MutableList<T> = {
5054
5094
  items: T[]
5055
5095
  }
5056
5096
  `,
5057
5097
  expected: dedent`
5058
- type mut_List<T> = {
5098
+ type MutableList<T> = {
5059
5099
  items: T[];
5060
5100
  };
5061
5101
  `,
5062
- options: { ignorePrefixes: ['mut_'] },
5102
+ options: {
5103
+ mutableVariablePrefixes: ['mut_'],
5104
+ mutablePropertyPrefixes: ['mut_'],
5105
+ },
5063
5106
  },
5064
5107
  {
5065
5108
  name: 'Union type with ignored prefix members',
5066
5109
  source: dedent`
5067
- type Result = mut_Success | Error;
5068
- type mut_Success = {
5110
+ type Result = MutableSuccess | Error;
5111
+ type MutableSuccess = {
5069
5112
  data: string[]
5070
5113
  };
5071
5114
  `,
5072
5115
  expected: dedent`
5073
- type Result = mut_Success | Error;
5074
- type mut_Success = {
5116
+ type Result = MutableSuccess | Error;
5117
+ type MutableSuccess = {
5075
5118
  data: string[];
5076
5119
  };
5077
5120
  `,
5078
- options: { ignorePrefixes: ['mut_'] },
5121
+ options: {
5122
+ mutableVariablePrefixes: ['mut_'],
5123
+ mutablePropertyPrefixes: ['mut_'],
5124
+ },
5079
5125
  },
5080
5126
  {
5081
5127
  name: 'Property with ignored prefix in class',
@@ -5091,7 +5137,10 @@ describe(convertToReadonlyTransformer, () => {
5091
5137
  readonly items: readonly number[] = [];
5092
5138
  }
5093
5139
  `,
5094
- options: { ignorePrefixes: ['mut_'] },
5140
+ options: {
5141
+ mutableVariablePrefixes: ['mut_'],
5142
+ mutablePropertyPrefixes: ['mut_'],
5143
+ },
5095
5144
  },
5096
5145
  {
5097
5146
  name: 'Method parameter with ignored prefix',
@@ -5105,7 +5154,10 @@ describe(convertToReadonlyTransformer, () => {
5105
5154
  process(mut_data: string[], data: readonly number[]) {}
5106
5155
  }
5107
5156
  `,
5108
- options: { ignorePrefixes: ['mut_'] },
5157
+ options: {
5158
+ mutableVariablePrefixes: ['mut_'],
5159
+ mutablePropertyPrefixes: ['mut_'],
5160
+ },
5109
5161
  },
5110
5162
  {
5111
5163
  name: 'Function expression with ignored prefix',
@@ -5115,7 +5167,10 @@ describe(convertToReadonlyTransformer, () => {
5115
5167
  expected: dedent`
5116
5168
  const fn = function mut_process(data: string[]): number[] { return []; }
5117
5169
  `,
5118
- options: { ignorePrefixes: ['mut_'] },
5170
+ options: {
5171
+ mutableVariablePrefixes: ['mut_'],
5172
+ mutablePropertyPrefixes: ['mut_'],
5173
+ },
5119
5174
  },
5120
5175
  {
5121
5176
  name: 'Array binding pattern in variable declaration (not implemented)',
@@ -5125,7 +5180,10 @@ describe(convertToReadonlyTransformer, () => {
5125
5180
  expected: dedent`
5126
5181
  const [mut_first, mut_second]: readonly [readonly string[], readonly number[]] = [[], []];
5127
5182
  `,
5128
- options: { ignorePrefixes: ['mut_'] },
5183
+ options: {
5184
+ mutableVariablePrefixes: ['mut_'],
5185
+ mutablePropertyPrefixes: ['mut_'],
5186
+ },
5129
5187
  },
5130
5188
  {
5131
5189
  // The binding pattern itself is not looked at (see the TODO in
@@ -5137,7 +5195,10 @@ describe(convertToReadonlyTransformer, () => {
5137
5195
  expected: dedent`
5138
5196
  const { mut_arr, mut_obj }: { mut_arr: string[], mut_obj: number[] } = { mut_arr: [], mut_obj: [] };
5139
5197
  `,
5140
- options: { ignorePrefixes: ['mut_'] },
5198
+ options: {
5199
+ mutableVariablePrefixes: ['mut_'],
5200
+ mutablePropertyPrefixes: ['mut_'],
5201
+ },
5141
5202
  },
5142
5203
  {
5143
5204
  name: 'Parameter with ignored prefix in class constructor',
@@ -5151,7 +5212,10 @@ describe(convertToReadonlyTransformer, () => {
5151
5212
  constructor(mut_config: string[]) {}
5152
5213
  }
5153
5214
  `,
5154
- options: { ignorePrefixes: ['mut_'] },
5215
+ options: {
5216
+ mutableVariablePrefixes: ['mut_'],
5217
+ mutablePropertyPrefixes: ['mut_'],
5218
+ },
5155
5219
  },
5156
5220
  {
5157
5221
  name: 'Parameter with ignored prefix in type literal method',
@@ -5165,7 +5229,10 @@ describe(convertToReadonlyTransformer, () => {
5165
5229
  process(mut_data: string[]): void;
5166
5230
  }>;
5167
5231
  `,
5168
- options: { ignorePrefixes: ['mut_'] },
5232
+ options: {
5233
+ mutableVariablePrefixes: ['mut_'],
5234
+ mutablePropertyPrefixes: ['mut_'],
5235
+ },
5169
5236
  },
5170
5237
  {
5171
5238
  name: 'Multiple parameters with ignored prefix',
@@ -5179,7 +5246,10 @@ describe(convertToReadonlyTransformer, () => {
5179
5246
  update(mut_id: string, mut_data: object[], data: readonly string[]): void;
5180
5247
  }
5181
5248
  `,
5182
- options: { ignorePrefixes: ['mut_'] },
5249
+ options: {
5250
+ mutableVariablePrefixes: ['mut_'],
5251
+ mutablePropertyPrefixes: ['mut_'],
5252
+ },
5183
5253
  },
5184
5254
  {
5185
5255
  name: 'Arrow function with ignored prefix parameters',
@@ -5189,18 +5259,228 @@ describe(convertToReadonlyTransformer, () => {
5189
5259
  expected: dedent`
5190
5260
  const handler = (mut_event: Event[], event: readonly CustomEvent[]) => {};
5191
5261
  `,
5192
- options: { ignorePrefixes: ['mut_'] },
5262
+ options: {
5263
+ mutableVariablePrefixes: ['mut_'],
5264
+ mutablePropertyPrefixes: ['mut_'],
5265
+ },
5193
5266
  },
5194
5267
  {
5195
- name: 'Arrow function parameters with "draft" prefix (default)',
5268
+ name: '"draft" is not a default prefix',
5196
5269
  source: dedent`
5197
5270
  const handler = (draft: Event[], event: CustomEvent[]) => {};
5271
+ type T = { draft: boolean; items: string[] };
5272
+ `,
5273
+ expected: dedent`
5274
+ const handler = (draft: readonly Event[], event: readonly CustomEvent[]) => {};
5275
+ type T = Readonly<{ draft: boolean; items: readonly string[] }>;
5276
+ `,
5277
+ },
5278
+ {
5279
+ name: '"Mutable" and "mut_" are the default type prefixes',
5280
+ source: dedent`
5281
+ type MutableFoo = { a: string[] };
5282
+ interface MutableBar { a: string[] }
5283
+ class MutableBaz { a: string[] = []; }
5284
+ const Q = class MutableQ { a: string[] = []; };
5285
+ type mut_Qux = { a: string[] };
5286
+ type Foo = { a: MutableFoo[] };
5287
+ `,
5288
+ expected: dedent`
5289
+ type MutableFoo = { a: string[] };
5290
+ interface MutableBar { a: string[] }
5291
+ class MutableBaz { a: string[] = []; }
5292
+ const Q = class MutableQ { a: string[] = []; };
5293
+ type mut_Qux = { a: string[] };
5294
+ type Foo = Readonly<{ a: readonly MutableFoo[] }>;
5295
+ `,
5296
+ },
5297
+ {
5298
+ name: 'Variable and property prefixes are separate',
5299
+ source: dedent`
5300
+ const handler = (draft: Event[]) => {};
5301
+ type T = { draft: boolean; items: string[] };
5302
+ `,
5303
+ expected: dedent`
5304
+ const handler = (draft: Event[]) => {};
5305
+ type T = Readonly<{ draft: boolean; items: readonly string[] }>;
5306
+ `,
5307
+ options: { mutableVariablePrefixes: ['draft'] },
5308
+ },
5309
+ {
5310
+ name: 'Each kind of name is matched against its own list: variables',
5311
+ source: dedent`
5312
+ type mut_T = { a: string[] };
5313
+ interface mut_I { a: string[] }
5314
+ class mut_C { a: string[] = []; }
5315
+ function mut_f(a: string[]): void {}
5316
+ const mut_x: string[] = [];
5317
+ type U = [mut_a: string[], b: string[]];
5318
+ class D { #mut_p: string[] = []; 'mut_q': string[] = []; }
5319
+ type V = { mut_r: string[]; s: string[] };
5320
+ interface J { mut_a: string[]; f(mut_p: string[]): void }
5321
+ type W = { mut_m(): string[]; b: string[] };
5322
+ class E { mut_m(x: string[]): string[] { return []; } get mut_g(): string[] { return []; } }
5323
+ `,
5324
+ expected: dedent`
5325
+ type mut_T = Readonly<{ a: readonly string[] }>;
5326
+ interface mut_I { readonly a: readonly string[] }
5327
+ class mut_C { readonly a: readonly string[] = []; }
5328
+ function mut_f(a: string[]): void {}
5329
+ const mut_x: string[] = [];
5330
+ type U = readonly [mut_a: readonly string[], b: readonly string[]];
5331
+ class D { readonly #mut_p: readonly string[] = []; readonly 'mut_q': readonly string[] = []; }
5332
+ type V = Readonly<{ mut_r: readonly string[]; s: readonly string[] }>;
5333
+ interface J { readonly mut_a: readonly string[]; f(mut_p: string[]): void }
5334
+ type W = Readonly<{ mut_m(): readonly string[]; b: readonly string[] }>;
5335
+ class E { mut_m(x: readonly string[]): readonly string[] { return []; } get mut_g(): readonly string[] { return []; } }
5336
+ `,
5337
+ options: {
5338
+ mutableVariablePrefixes: ['mut_'],
5339
+ mutableTypePrefixes: [],
5340
+ mutablePropertyPrefixes: [],
5341
+ },
5342
+ },
5343
+ {
5344
+ name: 'Each kind of name is matched against its own list: types',
5345
+ source: dedent`
5346
+ type mut_T = { a: string[] };
5347
+ interface mut_I { a: string[] }
5348
+ class mut_C { a: string[] = []; }
5349
+ function mut_f(a: string[]): void {}
5350
+ const mut_x: string[] = [];
5351
+ type U = [mut_a: string[], b: string[]];
5352
+ class D { #mut_p: string[] = []; 'mut_q': string[] = []; }
5353
+ type V = { mut_r: string[]; s: string[] };
5354
+ interface J { mut_a: string[]; f(mut_p: string[]): void }
5355
+ type W = { mut_m(): string[]; b: string[] };
5356
+ class E { mut_m(x: string[]): string[] { return []; } get mut_g(): string[] { return []; } }
5357
+ `,
5358
+ expected: dedent`
5359
+ type mut_T = { a: string[] };
5360
+ interface mut_I { a: string[] }
5361
+ class mut_C { a: string[] = []; }
5362
+ function mut_f(a: readonly string[]): void {}
5363
+ const mut_x: readonly string[] = [];
5364
+ type U = readonly [mut_a: readonly string[], b: readonly string[]];
5365
+ class D { readonly #mut_p: readonly string[] = []; readonly 'mut_q': readonly string[] = []; }
5366
+ type V = Readonly<{ mut_r: readonly string[]; s: readonly string[] }>;
5367
+ interface J { readonly mut_a: readonly string[]; f(mut_p: readonly string[]): void }
5368
+ type W = Readonly<{ mut_m(): readonly string[]; b: readonly string[] }>;
5369
+ class E { mut_m(x: readonly string[]): readonly string[] { return []; } get mut_g(): readonly string[] { return []; } }
5370
+ `,
5371
+ options: {
5372
+ mutableVariablePrefixes: [],
5373
+ mutableTypePrefixes: ['mut_'],
5374
+ mutablePropertyPrefixes: [],
5375
+ },
5376
+ },
5377
+ {
5378
+ name: 'Each kind of name is matched against its own list: properties',
5379
+ source: dedent`
5380
+ type mut_T = { a: string[] };
5381
+ interface mut_I { a: string[] }
5382
+ class mut_C { a: string[] = []; }
5383
+ function mut_f(a: string[]): void {}
5384
+ const mut_x: string[] = [];
5385
+ type U = [mut_a: string[], b: string[]];
5386
+ class D { #mut_p: string[] = []; 'mut_q': string[] = []; }
5387
+ type V = { mut_r: string[]; s: string[] };
5388
+ interface J { mut_a: string[]; f(mut_p: string[]): void }
5389
+ type W = { mut_m(): string[]; b: string[] };
5390
+ class E { mut_m(x: string[]): string[] { return []; } get mut_g(): string[] { return []; } }
5391
+ `,
5392
+ expected: dedent`
5393
+ type mut_T = Readonly<{ a: readonly string[] }>;
5394
+ interface mut_I { readonly a: readonly string[] }
5395
+ class mut_C { readonly a: readonly string[] = []; }
5396
+ function mut_f(a: readonly string[]): void {}
5397
+ const mut_x: readonly string[] = [];
5398
+ type U = readonly [mut_a: string[], b: readonly string[]];
5399
+ class D { #mut_p: string[] = []; 'mut_q': string[] = []; }
5400
+ type V = { mut_r: string[]; readonly s: readonly string[] };
5401
+ interface J { mut_a: string[]; f(mut_p: readonly string[]): void }
5402
+ type W = { mut_m(): string[]; readonly b: readonly string[] };
5403
+ class E { mut_m(x: string[]): string[] { return []; } get mut_g(): string[] { return []; } }
5404
+ `,
5405
+ options: {
5406
+ mutableVariablePrefixes: [],
5407
+ mutableTypePrefixes: [],
5408
+ mutablePropertyPrefixes: ['mut_'],
5409
+ },
5410
+ },
5411
+ {
5412
+ name: 'A property prefix with a "#" covers private names only',
5413
+ source: dedent`
5414
+ class C { #mut_a: string[] = []; mut_b: string[] = []; }
5415
+ `,
5416
+ expected: dedent`
5417
+ class C { #mut_a: string[] = []; readonly mut_b: readonly string[] = []; }
5418
+ `,
5419
+ options: { mutablePropertyPrefixes: ['#mut_'] },
5420
+ },
5421
+ {
5422
+ name: 'A property prefix does not apply to variables',
5423
+ source: dedent`
5424
+ const handler = (draft: Event[]) => {};
5425
+ type T = { draft: boolean; items: string[] };
5198
5426
  `,
5199
5427
  expected: dedent`
5200
- const handler = (draft: Event[], event: readonly CustomEvent[]) => {};
5428
+ const handler = (draft: readonly Event[]) => {};
5429
+ type T = { draft: boolean; readonly items: readonly string[] };
5201
5430
  `,
5431
+ options: { mutablePropertyPrefixes: ['draft'] },
5432
+ },
5433
+ {
5434
+ name: 'A constructor parameter property is a property',
5435
+ source: dedent`
5436
+ class C {
5437
+ draftA: string[] = [];
5438
+ constructor(private draftB: string[], readonly draftD: string[], draftC: string[]) {}
5439
+ }
5440
+ `,
5441
+ expected: dedent`
5442
+ class C {
5443
+ draftA: string[] = [];
5444
+ constructor(private draftB: string[], readonly draftD: string[], draftC: readonly string[]) {}
5445
+ }
5446
+ `,
5447
+ options: { mutablePropertyPrefixes: ['draft'] },
5448
+ },
5449
+ {
5450
+ name: 'A constructor parameter that is not a property is a variable',
5451
+ source: dedent`
5452
+ class C {
5453
+ draftA: string[] = [];
5454
+ constructor(private draftB: string[], draftC: string[]) {}
5455
+ }
5456
+ `,
5457
+ expected: dedent`
5458
+ class C {
5459
+ readonly draftA: readonly string[] = [];
5460
+ constructor(private readonly draftB: readonly string[], draftC: string[]) {}
5461
+ }
5462
+ `,
5463
+ options: { mutableVariablePrefixes: ['draft'] },
5202
5464
  },
5203
5465
  ])('$name', testFn);
5466
+
5467
+ test('the removed ignorePrefixes option is refused', () => {
5468
+ expect(() =>
5469
+ convertToReadonlyTransformer(
5470
+ // @ts-expect-error removed in 4.0.0
5471
+ { ignorePrefixes: ['mut_'] },
5472
+ ),
5473
+ ).toThrow('mutableVariablePrefixes');
5474
+ });
5475
+
5476
+ test('an unset ignorePrefixes option is accepted', () => {
5477
+ expect(() =>
5478
+ convertToReadonlyTransformer(
5479
+ // @ts-expect-error removed in 4.0.0
5480
+ { ignorePrefixes: undefined },
5481
+ ),
5482
+ ).not.toThrow();
5483
+ });
5204
5484
  });
5205
5485
 
5206
5486
  describe('Disable comment handling', () => {
@@ -1 +1,2 @@
1
1
  export * from './ignore-comment-text.mjs';
2
+ export * from './mutable-prefixes.mjs';
@@ -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
+ ]);