@monorepolint/rules 0.6.0-alpha.5 → 0.6.0-alpha.6

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 (107) hide show
  1. package/.turbo/turbo-clean.log +1 -1
  2. package/.turbo/turbo-compile-typescript.log +1 -1
  3. package/.turbo/turbo-lint.log +1 -1
  4. package/.turbo/turbo-test.log +446 -94
  5. package/.turbo/turbo-transpile-typescript.log +5 -5
  6. package/CHANGELOG.md +102 -0
  7. package/build/js/index.js +413 -368
  8. package/build/js/index.js.map +1 -1
  9. package/build/tsconfig.tsbuildinfo +1 -1
  10. package/build/types/REMOVE.d.ts +2 -0
  11. package/build/types/REMOVE.d.ts.map +1 -0
  12. package/build/types/__tests__/alphabeticalDependencies.spec.d.ts +8 -0
  13. package/build/types/__tests__/alphabeticalDependencies.spec.d.ts.map +1 -0
  14. package/build/types/__tests__/forceError.spec.d.ts +8 -0
  15. package/build/types/__tests__/forceError.spec.d.ts.map +1 -0
  16. package/build/types/__tests__/oncePerPackage.spec.d.ts +8 -0
  17. package/build/types/__tests__/oncePerPackage.spec.d.ts.map +1 -0
  18. package/build/types/__tests__/standardTsconfig.spec.d.ts +8 -0
  19. package/build/types/__tests__/standardTsconfig.spec.d.ts.map +1 -0
  20. package/build/types/bannedDependencies.d.ts +9 -33
  21. package/build/types/bannedDependencies.d.ts.map +1 -1
  22. package/build/types/consistentDependencies.d.ts +6 -6
  23. package/build/types/consistentDependencies.d.ts.map +1 -1
  24. package/build/types/consistentVersions.d.ts +6 -10
  25. package/build/types/consistentVersions.d.ts.map +1 -1
  26. package/build/types/fileContents.d.ts +3 -2
  27. package/build/types/fileContents.d.ts.map +1 -1
  28. package/build/types/index.d.ts +1 -0
  29. package/build/types/index.d.ts.map +1 -1
  30. package/build/types/mustSatisfyPeerDependencies.d.ts +12 -190
  31. package/build/types/mustSatisfyPeerDependencies.d.ts.map +1 -1
  32. package/build/types/nestedWorkspaces.d.ts +2 -2
  33. package/build/types/nestedWorkspaces.d.ts.map +1 -1
  34. package/build/types/oncePerPackage.d.ts +6 -6
  35. package/build/types/oncePerPackage.d.ts.map +1 -1
  36. package/build/types/packageEntry.d.ts +11 -33
  37. package/build/types/packageEntry.d.ts.map +1 -1
  38. package/build/types/packageOrder.d.ts +2 -1
  39. package/build/types/packageOrder.d.ts.map +1 -1
  40. package/build/types/packageScript.d.ts +13 -22
  41. package/build/types/packageScript.d.ts.map +1 -1
  42. package/build/types/requireDependency.d.ts +5 -20
  43. package/build/types/requireDependency.d.ts.map +1 -1
  44. package/build/types/standardTsconfig.d.ts +12 -19
  45. package/build/types/standardTsconfig.d.ts.map +1 -1
  46. package/build/types/util/zodSchemas.d.ts +14 -0
  47. package/build/types/util/zodSchemas.d.ts.map +1 -0
  48. package/coverage/block-navigation.js +1 -1
  49. package/coverage/clover.xml +1454 -1442
  50. package/coverage/coverage-final.json +21 -19
  51. package/coverage/index.html +27 -27
  52. package/coverage/sorter.js +21 -7
  53. package/coverage/src/REMOVE.ts.html +88 -0
  54. package/coverage/src/alphabeticalDependencies.ts.html +34 -34
  55. package/coverage/src/alphabeticalScripts.ts.html +5 -5
  56. package/coverage/src/bannedDependencies.ts.html +20 -53
  57. package/coverage/src/consistentDependencies.ts.html +20 -14
  58. package/coverage/src/consistentVersions.ts.html +330 -183
  59. package/coverage/src/fileContents.ts.html +223 -88
  60. package/coverage/src/forceError.ts.html +60 -60
  61. package/coverage/src/index.html +127 -112
  62. package/coverage/src/index.ts.html +11 -5
  63. package/coverage/src/mustSatisfyPeerDependencies.ts.html +15 -501
  64. package/coverage/src/nestedWorkspaces.ts.html +5 -5
  65. package/coverage/src/oncePerPackage.ts.html +59 -59
  66. package/coverage/src/packageEntry.ts.html +121 -91
  67. package/coverage/src/packageOrder.ts.html +44 -14
  68. package/coverage/src/packageScript.ts.html +235 -88
  69. package/coverage/src/requireDependency.ts.html +241 -82
  70. package/coverage/src/standardTsconfig.ts.html +193 -193
  71. package/coverage/src/util/checkAlpha.ts.html +40 -40
  72. package/coverage/src/util/createRuleFactory.ts.html +19 -19
  73. package/coverage/src/util/index.html +30 -15
  74. package/coverage/src/util/makeDirectory.ts.html +11 -11
  75. package/coverage/src/util/packageDependencyGraphService.ts.html +1 -1
  76. package/coverage/src/util/zodSchemas.ts.html +130 -0
  77. package/package.json +14 -14
  78. package/src/REMOVE.ts +1 -0
  79. package/src/__tests__/alphabeticalDependencies.spec.ts +102 -0
  80. package/src/__tests__/alphabeticalScripts.spec.ts +18 -0
  81. package/src/__tests__/bannedDependencies.spec.ts +49 -0
  82. package/src/__tests__/consistentDependencies.spec.ts +23 -0
  83. package/src/__tests__/consistentVersions.spec.ts +142 -0
  84. package/src/__tests__/fileContents.spec.ts +348 -0
  85. package/src/__tests__/forceError.spec.ts +70 -0
  86. package/src/__tests__/mustSatisfyPeerDependencies.spec.ts +44 -0
  87. package/src/__tests__/nestedWorkspaces.spec.ts +14 -0
  88. package/src/__tests__/oncePerPackage.spec.ts +75 -0
  89. package/src/__tests__/packageEntry.spec.ts +177 -0
  90. package/src/__tests__/packageOrder.spec.ts +22 -0
  91. package/src/__tests__/packageScript.spec.ts +549 -0
  92. package/src/__tests__/requireDependency.spec.ts +259 -2
  93. package/src/__tests__/standardTsconfig.spec.ts +91 -0
  94. package/src/bannedDependencies.ts +14 -25
  95. package/src/consistentDependencies.ts +10 -8
  96. package/src/consistentVersions.ts +132 -83
  97. package/src/fileContents.ts +80 -35
  98. package/src/index.ts +2 -0
  99. package/src/mustSatisfyPeerDependencies.ts +10 -172
  100. package/src/nestedWorkspaces.ts +4 -4
  101. package/src/oncePerPackage.ts +6 -6
  102. package/src/packageEntry.ts +60 -50
  103. package/src/packageOrder.ts +19 -9
  104. package/src/packageScript.ts +67 -18
  105. package/src/requireDependency.ts +84 -31
  106. package/src/standardTsconfig.ts +26 -26
  107. package/src/util/zodSchemas.ts +15 -0
@@ -23,16 +23,16 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">83.72% </span>
26
+ <span class="strong">93.33% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>72/86</span>
28
+ <span class='fraction'>112/120</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">38.46% </span>
33
+ <span class="strong">90.32% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>5/13</span>
35
+ <span class='fraction'>28/31</span>
36
36
  </div>
37
37
 
38
38
 
@@ -44,9 +44,9 @@
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">83.72% </span>
47
+ <span class="strong">93.33% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>72/86</span>
49
+ <span class='fraction'>112/120</span>
50
50
  </div>
51
51
 
52
52
 
@@ -171,7 +171,52 @@
171
171
  <a name='L106'></a><a href='#L106'>106</a>
172
172
  <a name='L107'></a><a href='#L107'>107</a>
173
173
  <a name='L108'></a><a href='#L108'>108</a>
174
- <a name='L109'></a><a href='#L109'>109</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
174
+ <a name='L109'></a><a href='#L109'>109</a>
175
+ <a name='L110'></a><a href='#L110'>110</a>
176
+ <a name='L111'></a><a href='#L111'>111</a>
177
+ <a name='L112'></a><a href='#L112'>112</a>
178
+ <a name='L113'></a><a href='#L113'>113</a>
179
+ <a name='L114'></a><a href='#L114'>114</a>
180
+ <a name='L115'></a><a href='#L115'>115</a>
181
+ <a name='L116'></a><a href='#L116'>116</a>
182
+ <a name='L117'></a><a href='#L117'>117</a>
183
+ <a name='L118'></a><a href='#L118'>118</a>
184
+ <a name='L119'></a><a href='#L119'>119</a>
185
+ <a name='L120'></a><a href='#L120'>120</a>
186
+ <a name='L121'></a><a href='#L121'>121</a>
187
+ <a name='L122'></a><a href='#L122'>122</a>
188
+ <a name='L123'></a><a href='#L123'>123</a>
189
+ <a name='L124'></a><a href='#L124'>124</a>
190
+ <a name='L125'></a><a href='#L125'>125</a>
191
+ <a name='L126'></a><a href='#L126'>126</a>
192
+ <a name='L127'></a><a href='#L127'>127</a>
193
+ <a name='L128'></a><a href='#L128'>128</a>
194
+ <a name='L129'></a><a href='#L129'>129</a>
195
+ <a name='L130'></a><a href='#L130'>130</a>
196
+ <a name='L131'></a><a href='#L131'>131</a>
197
+ <a name='L132'></a><a href='#L132'>132</a>
198
+ <a name='L133'></a><a href='#L133'>133</a>
199
+ <a name='L134'></a><a href='#L134'>134</a>
200
+ <a name='L135'></a><a href='#L135'>135</a>
201
+ <a name='L136'></a><a href='#L136'>136</a>
202
+ <a name='L137'></a><a href='#L137'>137</a>
203
+ <a name='L138'></a><a href='#L138'>138</a>
204
+ <a name='L139'></a><a href='#L139'>139</a>
205
+ <a name='L140'></a><a href='#L140'>140</a>
206
+ <a name='L141'></a><a href='#L141'>141</a>
207
+ <a name='L142'></a><a href='#L142'>142</a>
208
+ <a name='L143'></a><a href='#L143'>143</a>
209
+ <a name='L144'></a><a href='#L144'>144</a>
210
+ <a name='L145'></a><a href='#L145'>145</a>
211
+ <a name='L146'></a><a href='#L146'>146</a>
212
+ <a name='L147'></a><a href='#L147'>147</a>
213
+ <a name='L148'></a><a href='#L148'>148</a>
214
+ <a name='L149'></a><a href='#L149'>149</a>
215
+ <a name='L150'></a><a href='#L150'>150</a>
216
+ <a name='L151'></a><a href='#L151'>151</a>
217
+ <a name='L152'></a><a href='#L152'>152</a>
218
+ <a name='L153'></a><a href='#L153'>153</a>
219
+ <a name='L154'></a><a href='#L154'>154</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
175
220
  <span class="cline-any cline-neutral">&nbsp;</span>
176
221
  <span class="cline-any cline-neutral">&nbsp;</span>
177
222
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -185,9 +230,17 @@
185
230
  <span class="cline-any cline-yes">1x</span>
186
231
  <span class="cline-any cline-yes">1x</span>
187
232
  <span class="cline-any cline-yes">1x</span>
233
+ <span class="cline-any cline-neutral">&nbsp;</span>
234
+ <span class="cline-any cline-yes">1x</span>
235
+ <span class="cline-any cline-yes">1x</span>
236
+ <span class="cline-any cline-yes">1x</span>
237
+ <span class="cline-any cline-yes">1x</span>
238
+ <span class="cline-any cline-neutral">&nbsp;</span>
239
+ <span class="cline-any cline-yes">1x</span>
240
+ <span class="cline-any cline-yes">14x</span>
241
+ <span class="cline-any cline-yes">1x</span>
188
242
  <span class="cline-any cline-yes">1x</span>
189
243
  <span class="cline-any cline-yes">1x</span>
190
- <span class="cline-any cline-no">&nbsp;</span>
191
244
  <span class="cline-any cline-yes">1x</span>
192
245
  <span class="cline-any cline-yes">1x</span>
193
246
  <span class="cline-any cline-yes">1x</span>
@@ -211,39 +264,51 @@
211
264
  <span class="cline-any cline-yes">1x</span>
212
265
  <span class="cline-any cline-yes">1x</span>
213
266
  <span class="cline-any cline-yes">1x</span>
214
- <span class="cline-any cline-yes">6x</span>
215
- <span class="cline-any cline-yes">6x</span>
267
+ <span class="cline-any cline-yes">30x</span>
216
268
  <span class="cline-any cline-neutral">&nbsp;</span>
217
- <span class="cline-any cline-yes">6x</span>
218
- <span class="cline-any cline-yes">6x</span>
219
- <span class="cline-any cline-no">&nbsp;</span>
220
- <span class="cline-any cline-yes">6x</span>
221
- <span class="cline-any cline-yes">6x</span>
222
- <span class="cline-any cline-yes">6x</span>
223
- <span class="cline-any cline-no">&nbsp;</span>
224
- <span class="cline-any cline-yes">6x</span>
225
269
  <span class="cline-any cline-neutral">&nbsp;</span>
226
- <span class="cline-any cline-yes">6x</span>
227
- <span class="cline-any cline-no">&nbsp;</span>
228
- <span class="cline-any cline-yes">6x</span>
270
+ <span class="cline-any cline-yes">30x</span>
271
+ <span class="cline-any cline-yes">2x</span>
272
+ <span class="cline-any cline-yes">2x</span>
229
273
  <span class="cline-any cline-neutral">&nbsp;</span>
274
+ <span class="cline-any cline-yes">28x</span>
275
+ <span class="cline-any cline-neutral">&nbsp;</span>
276
+ <span class="cline-any cline-neutral">&nbsp;</span>
277
+ <span class="cline-any cline-yes">30x</span>
230
278
  <span class="cline-any cline-yes">6x</span>
231
279
  <span class="cline-any cline-yes">6x</span>
232
- <span class="cline-any cline-yes">6x</span>
233
- <span class="cline-any cline-yes">6x</span>
234
- <span class="cline-any cline-yes">6x</span>
235
- <span class="cline-any cline-yes">6x</span>
236
- <span class="cline-any cline-no">&nbsp;</span>
237
- <span class="cline-any cline-yes">6x</span>
238
- <span class="cline-any cline-yes">6x</span>
239
- <span class="cline-any cline-yes">6x</span>
240
- <span class="cline-any cline-yes">6x</span>
241
- <span class="cline-any cline-yes">6x</span>
242
- <span class="cline-any cline-yes">6x</span>
243
- <span class="cline-any cline-yes">6x</span>
244
- <span class="cline-any cline-yes">6x</span>
245
- <span class="cline-any cline-yes">6x</span>
246
- <span class="cline-any cline-yes">6x</span>
280
+ <span class="cline-any cline-neutral">&nbsp;</span>
281
+ <span class="cline-any cline-yes">18x</span>
282
+ <span class="cline-any cline-yes">18x</span>
283
+ <span class="cline-any cline-yes">2x</span>
284
+ <span class="cline-any cline-yes">16x</span>
285
+ <span class="cline-any cline-yes">30x</span>
286
+ <span class="cline-any cline-yes">16x</span>
287
+ <span class="cline-any cline-yes">16x</span>
288
+ <span class="cline-any cline-yes">2x</span>
289
+ <span class="cline-any cline-yes">14x</span>
290
+ <span class="cline-any cline-neutral">&nbsp;</span>
291
+ <span class="cline-any cline-yes">16x</span>
292
+ <span class="cline-any cline-yes">2x</span>
293
+ <span class="cline-any cline-yes">14x</span>
294
+ <span class="cline-any cline-neutral">&nbsp;</span>
295
+ <span class="cline-any cline-yes">16x</span>
296
+ <span class="cline-any cline-yes">16x</span>
297
+ <span class="cline-any cline-yes">16x</span>
298
+ <span class="cline-any cline-yes">16x</span>
299
+ <span class="cline-any cline-yes">16x</span>
300
+ <span class="cline-any cline-yes">16x</span>
301
+ <span class="cline-any cline-yes">2x</span>
302
+ <span class="cline-any cline-yes">16x</span>
303
+ <span class="cline-any cline-yes">14x</span>
304
+ <span class="cline-any cline-yes">14x</span>
305
+ <span class="cline-any cline-yes">14x</span>
306
+ <span class="cline-any cline-yes">14x</span>
307
+ <span class="cline-any cline-yes">14x</span>
308
+ <span class="cline-any cline-yes">16x</span>
309
+ <span class="cline-any cline-yes">16x</span>
310
+ <span class="cline-any cline-yes">16x</span>
311
+ <span class="cline-any cline-yes">30x</span>
247
312
  <span class="cline-any cline-yes">1x</span>
248
313
  <span class="cline-any cline-yes">1x</span>
249
314
  <span class="cline-any cline-neutral">&nbsp;</span>
@@ -254,9 +319,12 @@
254
319
  <span class="cline-any cline-neutral">&nbsp;</span>
255
320
  <span class="cline-any cline-yes">1x</span>
256
321
  <span class="cline-any cline-neutral">&nbsp;</span>
257
- <span class="cline-any cline-yes">6x</span>
322
+ <span class="cline-any cline-yes">28x</span>
323
+ <span class="cline-any cline-yes">28x</span>
324
+ <span class="cline-any cline-yes">28x</span>
325
+ <span class="cline-any cline-yes">28x</span>
258
326
  <span class="cline-any cline-neutral">&nbsp;</span>
259
- <span class="cline-any cline-yes">6x</span>
327
+ <span class="cline-any cline-yes">28x</span>
260
328
  <span class="cline-any cline-no">&nbsp;</span>
261
329
  <span class="cline-any cline-no">&nbsp;</span>
262
330
  <span class="cline-any cline-no">&nbsp;</span>
@@ -264,21 +332,43 @@
264
332
  <span class="cline-any cline-no">&nbsp;</span>
265
333
  <span class="cline-any cline-no">&nbsp;</span>
266
334
  <span class="cline-any cline-neutral">&nbsp;</span>
267
- <span class="cline-any cline-yes">6x</span>
335
+ <span class="cline-any cline-yes">28x</span>
336
+ <span class="cline-any cline-yes">8x</span>
337
+ <span class="cline-any cline-yes">8x</span>
338
+ <span class="cline-any cline-yes">8x</span>
339
+ <span class="cline-any cline-yes">8x</span>
340
+ <span class="cline-any cline-yes">2x</span>
268
341
  <span class="cline-any cline-yes">2x</span>
269
342
  <span class="cline-any cline-yes">2x</span>
343
+ <span class="cline-any cline-yes">8x</span>
344
+ <span class="cline-any cline-neutral">&nbsp;</span>
345
+ <span class="cline-any cline-yes">6x</span>
270
346
  <span class="cline-any cline-yes">6x</span>
271
- <span class="cline-any cline-yes">4x</span>
272
- <span class="cline-any cline-yes">4x</span>
273
- <span class="cline-any cline-yes">4x</span>
274
347
  <span class="cline-any cline-neutral">&nbsp;</span>
275
- <span class="cline-any cline-yes">4x</span>
276
- <span class="cline-any cline-yes">4x</span>
277
- <span class="cline-any cline-yes">4x</span>
278
- <span class="cline-any cline-no">&nbsp;</span>
348
+ <span class="cline-any cline-yes">6x</span>
349
+ <span class="cline-any cline-yes">6x</span>
350
+ <span class="cline-any cline-yes">6x</span>
351
+ <span class="cline-any cline-yes">6x</span>
352
+ <span class="cline-any cline-yes">6x</span>
353
+ <span class="cline-any cline-yes">6x</span>
354
+ <span class="cline-any cline-neutral">&nbsp;</span>
355
+ <span class="cline-any cline-neutral">&nbsp;</span>
356
+ <span class="cline-any cline-yes">6x</span>
357
+ <span class="cline-any cline-yes">6x</span>
358
+ <span class="cline-any cline-yes">28x</span>
359
+ <span class="cline-any cline-yes">8x</span>
360
+ <span class="cline-any cline-yes">8x</span>
361
+ <span class="cline-any cline-yes">8x</span>
362
+ <span class="cline-any cline-neutral">&nbsp;</span>
363
+ <span class="cline-any cline-yes">8x</span>
364
+ <span class="cline-any cline-yes">8x</span>
365
+ <span class="cline-any cline-yes">20x</span>
366
+ <span class="cline-any cline-yes">12x</span>
367
+ <span class="cline-any cline-yes">12x</span>
368
+ <span class="cline-any cline-yes">12x</span>
279
369
  <span class="cline-any cline-no">&nbsp;</span>
280
370
  <span class="cline-any cline-no">&nbsp;</span>
281
- <span class="cline-any cline-yes">6x</span>
371
+ <span class="cline-any cline-yes">28x</span>
282
372
  <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">/*!
283
373
  * Copyright 2023 Palantir Technologies, Inc.
284
374
  *
@@ -289,50 +379,70 @@
289
379
  import { Context } from "@monorepolint/config";
290
380
  import { diff } from "jest-diff";
291
381
  import * as path from "path";
292
- import * as r from "runtypes";
382
+ import { z } from "zod";
383
+ import { REMOVE } from "./REMOVE.js";
293
384
  import { createRuleFactory } from "./util/createRuleFactory.js";
294
- const Options = r.Union(
295
- r.Record({
296
- file: r.String,
297
- generator: r.Function.withGuard((
298
- <span class="cstat-no" title="statement not covered" > x,</span>
299
- ): x is (context: Context) =&gt; string | Promise&lt;string&gt; =&gt; x != undefined),
300
- template: r.Undefined.optional(),
301
- templateFile: r.Undefined.optional(),
385
+ import { ZodRemove } from "./util/zodSchemas.js";
386
+ &nbsp;
387
+ const Options = z.union([
388
+ z.object({
389
+ file: z.string(),
390
+ generator: z.custom&lt;
391
+ (context: Context) =&gt; string | typeof REMOVE | Promise&lt;string | typeof REMOVE&gt;
392
+ &gt;((val) =&gt; {
393
+ return typeof val === "function";
394
+ }),
395
+ template: z.undefined().optional(),
396
+ templateFile: z.undefined().optional(),
302
397
  }),
303
- r.Record({
304
- file: r.String,
305
- generator: r.Undefined.optional(),
306
- template: r.String.Or(r.Undefined),
307
- templateFile: r.Undefined.optional(),
398
+ z.object({
399
+ file: z.string(),
400
+ generator: z.undefined().optional(),
401
+ template: z.union([
402
+ z.string(),
403
+ ZodRemove,
404
+ ]),
405
+ templateFile: z.undefined().optional(),
308
406
  }),
309
- r.Record({
310
- file: r.String,
311
- generator: r.Undefined.optional(),
312
- template: r.Undefined.optional(),
313
- templateFile: r.String,
407
+ z.object({
408
+ file: z.string(),
409
+ generator: z.undefined().optional(),
410
+ template: z.undefined().optional(),
411
+ templateFile: z.string(),
314
412
  }),
315
- );
413
+ ]);
316
414
  &nbsp;
317
- type Options = r.Static&lt;typeof Options&gt;;
415
+ type Options = z.infer&lt;typeof Options&gt;;
318
416
  &nbsp;
319
417
  export const fileContents = createRuleFactory&lt;Options&gt;({
320
418
  name: "fileContents",
321
419
  check: async (context, opts) =&gt; {
322
420
  const fullPath = path.join(context.packageDir, opts.file);
421
+ &nbsp;
422
+ // Validate that the file path doesn't contain null bytes or other invalid characters
423
+ if (fullPath.includes("\0")) {
424
+ throw new Error(`Invalid file path: path contains null bytes`);
425
+ }
426
+ &nbsp;
323
427
  const expectedContent = await getExpectedContents(context, opts);
428
+ &nbsp;
429
+ // If the generator function failed, an unfixable error was already added, so we should return early
430
+ if (expectedContent === Symbol.for("GENERATOR_ERROR")) {
431
+ return;
432
+ }
324
433
  &nbsp;
325
434
  const pathExists = context.host.exists(fullPath);
326
- const actualContent = <span class="branch-0 cbranch-no" title="branch not covered" >pathExists</span>
327
- <span class="cstat-no" title="statement not covered" > ? context.host.readFile(fullPath, { encoding: "utf-8" })</span>
328
- : undefined;
435
+ const actualContent = pathExists
436
+ ? context.host.readFile(fullPath, { encoding: "utf-8" })
437
+ : REMOVE;
329
438
  if (actualContent !== expectedContent) {
330
- const longMessage = <span class="branch-0 cbranch-no" title="branch not covered" >pathExists &amp;&amp; expectedContent == <span class="branch-0 cbranch-no" title="branch not covered" >undefined</span></span>
331
- <span class="cstat-no" title="statement not covered" > ? undefined</span>
332
- : diff(expectedContent, actualContent, { expand: true });
439
+ const longMessage =
440
+ pathExists &amp;&amp; (expectedContent === undefined || expectedContent === REMOVE)
441
+ ? undefined
442
+ : diff(expectedContent, actualContent, { expand: true });
333
443
  &nbsp;
334
- const message = <span class="branch-0 cbranch-no" title="branch not covered" >pathExists &amp;&amp; expectedContent == <span class="branch-0 cbranch-no" title="branch not covered" >undefined</span></span>
335
- <span class="cstat-no" title="statement not covered" > ? "File should not exist"</span>
444
+ const message = pathExists &amp;&amp; (expectedContent === undefined || expectedContent === REMOVE)
445
+ ? "File should not exist"
336
446
  : "Expect file contents to match";
337
447
  &nbsp;
338
448
  context.addError({
@@ -340,9 +450,9 @@ export const fileContents = createRuleFactory&lt;Options&gt;({
340
450
  message,
341
451
  longMessage,
342
452
  fixer: () =&gt; {
343
- if (expectedContent === undefined) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
344
- <span class="cstat-no" title="statement not covered" > if (pathExists) context.host.deleteFile(fullPath);</span>
345
- } else {
453
+ if (expectedContent === REMOVE) {
454
+ if (pathExists) context.host.deleteFile(fullPath);
455
+ } else if (expectedContent !== undefined &amp;&amp; typeof expectedContent === "string") {
346
456
  context.host.mkdir(path.dirname(fullPath), { recursive: true });
347
457
  context.host.writeFile(fullPath, expectedContent, {
348
458
  encoding: "utf-8",
@@ -352,29 +462,52 @@ export const fileContents = createRuleFactory&lt;Options&gt;({
352
462
  });
353
463
  }
354
464
  },
355
- validateOptions: Options.check,
465
+ validateOptions: Options.parse,
356
466
  });
357
467
  &nbsp;
358
468
  const optionsCache = new Map&lt;
359
469
  Options,
360
- | ((context: Context) =&gt; Promise&lt;string&gt; | string | undefined)
470
+ | ((context: Context) =&gt; Promise&lt;string | typeof REMOVE&gt; | string | typeof REMOVE)
361
471
  | string
362
- | undefined
472
+ | typeof REMOVE
363
473
  &gt;();
364
474
  &nbsp;
365
- async function getExpectedContents(context: Context, opts: Options) {
475
+ async function getExpectedContents(
476
+ context: Context,
477
+ opts: Options,
478
+ ): Promise&lt;string | typeof REMOVE | symbol&gt; {
366
479
  // we need to use has because undefined is a valid value in the cache
367
480
  if (optionsCache.has(opts)) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
368
481
  <span class="cstat-no" title="statement not covered" > const cachedEntry = optionsCache.get(opts);</span>
369
482
  <span class="cstat-no" title="statement not covered" > if (cachedEntry &amp;&amp; typeof cachedEntry === "function") {</span>
370
483
  <span class="cstat-no" title="statement not covered" > return cachedEntry(context);</span>
371
484
  <span class="cstat-no" title="statement not covered" > }</span>
372
- <span class="cstat-no" title="statement not covered" > return cachedEntry;</span>
485
+ <span class="cstat-no" title="statement not covered" > return cachedEntry as string | typeof REMOVE;</span>
373
486
  <span class="cstat-no" title="statement not covered" > }</span>
374
487
  &nbsp;
375
488
  if (opts.generator) {
376
489
  optionsCache.set(opts, opts.generator);
377
- return opts.generator(context);
490
+ try {
491
+ const result = await opts.generator(context);
492
+ if (typeof result !== "string" &amp;&amp; result !== REMOVE) {
493
+ throw new Error(`Generator function must return a string or REMOVE, got ${typeof result}`);
494
+ }
495
+ return result;
496
+ } catch (error) {
497
+ // Instead of throwing, create an unfixable error and return a special marker
498
+ const errorMessage = error instanceof Error ? error.<span class="branch-0 cbranch-no" title="branch not covered" >message : String(error);</span>
499
+ const fullPath = path.join(context.packageDir, opts.file);
500
+ &nbsp;
501
+ context.addError({
502
+ file: fullPath,
503
+ message: `Generator function failed: ${errorMessage}`,
504
+ longMessage:
505
+ `The generator function for file "${opts.file}" threw an error:\n\n${errorMessage}`,
506
+ });
507
+ &nbsp;
508
+ // Return a special marker that will prevent the file comparison from proceeding
509
+ return Symbol.for("GENERATOR_ERROR");
510
+ }
378
511
  } else if (opts.templateFile) {
379
512
  const { packageDir: workspacePackageDir } = context.getWorkspaceContext();
380
513
  const fullPath = path.resolve(workspacePackageDir, opts.templateFile);
@@ -382,9 +515,11 @@ async function getExpectedContents(context: Context, opts: Options) {
382
515
  &nbsp;
383
516
  optionsCache.set(opts, template);
384
517
  return template;
518
+ } else if (opts.template !== undefined) {
519
+ optionsCache.set(opts, opts.template);
520
+ return opts.template;
385
521
  <span class="branch-0 cbranch-no" title="branch not covered" > } else {</span>
386
- <span class="cstat-no" title="statement not covered" > optionsCache.set(opts, opts.template);</span>
387
- <span class="cstat-no" title="statement not covered" > return opts.template;</span>
522
+ <span class="cstat-no" title="statement not covered" > throw new Error("Unable to get expected contents");</span>
388
523
  <span class="cstat-no" title="statement not covered" > }</span>
389
524
  }
390
525
  &nbsp;</pre></td></tr></table></pre>
@@ -394,7 +529,7 @@ async function getExpectedContents(context: Context, opts: Options) {
394
529
  <div class='footer quiet pad2 space-top1 center small'>
395
530
  Code coverage generated by
396
531
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
397
- at 2025-04-02T20:08:01.942Z
532
+ at 2025-11-07T18:00:58.549Z
398
533
  </div>
399
534
  <script src="../prettify.js"></script>
400
535
  <script>
@@ -23,30 +23,30 @@
23
23
  <div class='clearfix'>
24
24
 
25
25
  <div class='fl pad1y space-right2'>
26
- <span class="strong">0% </span>
26
+ <span class="strong">100% </span>
27
27
  <span class="quiet">Statements</span>
28
- <span class='fraction'>0/25</span>
28
+ <span class='fraction'>25/25</span>
29
29
  </div>
30
30
 
31
31
 
32
32
  <div class='fl pad1y space-right2'>
33
- <span class="strong">0% </span>
33
+ <span class="strong">100% </span>
34
34
  <span class="quiet">Branches</span>
35
- <span class='fraction'>0/1</span>
35
+ <span class='fraction'>14/14</span>
36
36
  </div>
37
37
 
38
38
 
39
39
  <div class='fl pad1y space-right2'>
40
- <span class="strong">0% </span>
40
+ <span class="strong">100% </span>
41
41
  <span class="quiet">Functions</span>
42
- <span class='fraction'>0/1</span>
42
+ <span class='fraction'>2/2</span>
43
43
  </div>
44
44
 
45
45
 
46
46
  <div class='fl pad1y space-right2'>
47
- <span class="strong">0% </span>
47
+ <span class="strong">100% </span>
48
48
  <span class="quiet">Lines</span>
49
- <span class='fraction'>0/25</span>
49
+ <span class='fraction'>25/25</span>
50
50
  </div>
51
51
 
52
52
 
@@ -61,7 +61,7 @@
61
61
  </div>
62
62
  </template>
63
63
  </div>
64
- <div class='status-line low'></div>
64
+ <div class='status-line high'></div>
65
65
  <pre><table class="coverage">
66
66
  <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
67
  <a name='L2'></a><a href='#L2'>2</a>
@@ -96,72 +96,72 @@
96
96
  <a name='L31'></a><a href='#L31'>31</a>
97
97
  <a name='L32'></a><a href='#L32'>32</a>
98
98
  <a name='L33'></a><a href='#L33'>33</a>
99
- <a name='L34'></a><a href='#L34'>34</a></td><td class="line-coverage quiet"><span class="cline-any cline-no">&nbsp;</span>
99
+ <a name='L34'></a><a href='#L34'>34</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
100
100
  <span class="cline-any cline-neutral">&nbsp;</span>
101
- <span class="cline-any cline-no">&nbsp;</span>
102
- <span class="cline-any cline-no">&nbsp;</span>
101
+ <span class="cline-any cline-yes">1x</span>
102
+ <span class="cline-any cline-yes">1x</span>
103
103
  <span class="cline-any cline-neutral">&nbsp;</span>
104
- <span class="cline-any cline-no">&nbsp;</span>
105
- <span class="cline-any cline-no">&nbsp;</span>
106
- <span class="cline-any cline-no">&nbsp;</span>
107
- <span class="cline-any cline-no">&nbsp;</span>
108
- <span class="cline-any cline-no">&nbsp;</span>
109
- <span class="cline-any cline-no">&nbsp;</span>
110
- <span class="cline-any cline-no">&nbsp;</span>
104
+ <span class="cline-any cline-yes">1x</span>
105
+ <span class="cline-any cline-yes">4x</span>
106
+ <span class="cline-any cline-yes">4x</span>
107
+ <span class="cline-any cline-yes">2x</span>
108
+ <span class="cline-any cline-yes">4x</span>
109
+ <span class="cline-any cline-yes">4x</span>
110
+ <span class="cline-any cline-yes">4x</span>
111
111
  <span class="cline-any cline-neutral">&nbsp;</span>
112
- <span class="cline-any cline-no">&nbsp;</span>
113
- <span class="cline-any cline-no">&nbsp;</span>
112
+ <span class="cline-any cline-yes">1x</span>
113
+ <span class="cline-any cline-yes">16x</span>
114
114
  <span class="cline-any cline-neutral">&nbsp;</span>
115
- <span class="cline-any cline-no">&nbsp;</span>
116
- <span class="cline-any cline-no">&nbsp;</span>
117
- <span class="cline-any cline-no">&nbsp;</span>
115
+ <span class="cline-any cline-yes">16x</span>
116
+ <span class="cline-any cline-yes">2x</span>
117
+ <span class="cline-any cline-yes">2x</span>
118
118
  <span class="cline-any cline-neutral">&nbsp;</span>
119
- <span class="cline-any cline-no">&nbsp;</span>
119
+ <span class="cline-any cline-yes">10x</span>
120
120
  <span class="cline-any cline-neutral">&nbsp;</span>
121
- <span class="cline-any cline-no">&nbsp;</span>
121
+ <span class="cline-any cline-yes">10x</span>
122
122
  <span class="cline-any cline-neutral">&nbsp;</span>
123
- <span class="cline-any cline-no">&nbsp;</span>
124
- <span class="cline-any cline-no">&nbsp;</span>
125
- <span class="cline-any cline-no">&nbsp;</span>
123
+ <span class="cline-any cline-yes">16x</span>
124
+ <span class="cline-any cline-yes">2x</span>
125
+ <span class="cline-any cline-yes">2x</span>
126
126
  <span class="cline-any cline-neutral">&nbsp;</span>
127
- <span class="cline-any cline-no">&nbsp;</span>
128
- <span class="cline-any cline-no">&nbsp;</span>
129
- <span class="cline-any cline-no">&nbsp;</span>
130
- <span class="cline-any cline-no">&nbsp;</span>
131
- <span class="cline-any cline-no">&nbsp;</span>
132
- <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js"><span class="cstat-no" title="statement not covered" >import { createRuleFactory } from "./util/createRuleFactory.js";<span class="fstat-no" title="function not covered" ><span class="branch-0 cbranch-no" title="branch not covered" ></span></span></span>
127
+ <span class="cline-any cline-yes">16x</span>
128
+ <span class="cline-any cline-yes">2x</span>
129
+ <span class="cline-any cline-yes">2x</span>
130
+ <span class="cline-any cline-yes">16x</span>
131
+ <span class="cline-any cline-yes">1x</span>
132
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import { createRuleFactory } from "./util/createRuleFactory.js";
133
133
  &nbsp;
134
- <span class="cstat-no" title="statement not covered" >export const forceError = createRuleFactory&lt;{ customMessage?: string }&gt;({</span>
135
- <span class="cstat-no" title="statement not covered" > name: "forceError",</span>
134
+ export const forceError = createRuleFactory&lt;{ customMessage?: string }&gt;({
135
+ name: "forceError",
136
136
  &nbsp;
137
- <span class="cstat-no" title="statement not covered" > check: async (context, opts) =&gt; {</span>
138
- <span class="cstat-no" title="statement not covered" > context.addError({</span>
139
- <span class="cstat-no" title="statement not covered" > message: opts?.customMessage</span>
140
- <span class="cstat-no" title="statement not covered" > ?? "Forced error (often used to debug package selection)",</span>
141
- <span class="cstat-no" title="statement not covered" > file: context.getPackageJsonPath(),</span>
142
- <span class="cstat-no" title="statement not covered" > });</span>
143
- <span class="cstat-no" title="statement not covered" > },</span>
137
+ check: async (context, opts) =&gt; {
138
+ context.addError({
139
+ message: opts?.customMessage
140
+ ?? "Forced error (often used to debug package selection)",
141
+ file: context.getPackageJsonPath(),
142
+ });
143
+ },
144
144
  &nbsp;
145
- <span class="cstat-no" title="statement not covered" > validateOptions: (opts): asserts opts is null | { customMessage: string } =&gt; {</span>
146
- <span class="cstat-no" title="statement not covered" > if (opts == null) return;</span>
145
+ validateOptions: (opts): asserts opts is null | { customMessage: string } =&gt; {
146
+ if (opts == null) return;
147
147
  &nbsp;
148
- <span class="cstat-no" title="statement not covered" > if (typeof opts !== "object") {</span>
149
- <span class="cstat-no" title="statement not covered" > throw new Error("options must be an object if provided");</span>
150
- <span class="cstat-no" title="statement not covered" > }</span>
148
+ if (typeof opts !== "object") {
149
+ throw new Error("options must be an object if provided");
150
+ }
151
151
  &nbsp;
152
- <span class="cstat-no" title="statement not covered" > const numKeys = Object.keys(opts).length;</span>
152
+ const numKeys = Object.keys(opts).length;
153
153
  &nbsp;
154
- <span class="cstat-no" title="statement not covered" > if (numKeys === 0) return;</span>
154
+ if (numKeys === 0) return;
155
155
  &nbsp;
156
- <span class="cstat-no" title="statement not covered" > if (Object.keys(opts).length &gt; 1 || !("customMessage" in opts)) {</span>
157
- <span class="cstat-no" title="statement not covered" > throw new Error("options must only have `customMessage` property");</span>
158
- <span class="cstat-no" title="statement not covered" > }</span>
156
+ if (Object.keys(opts).length &gt; 1 || !("customMessage" in opts)) {
157
+ throw new Error("options must only have `customMessage` property");
158
+ }
159
159
  &nbsp;
160
- <span class="cstat-no" title="statement not covered" > if (typeof opts.customMessage !== "string") {</span>
161
- <span class="cstat-no" title="statement not covered" > throw new Error("customMessage must be a string");</span>
162
- <span class="cstat-no" title="statement not covered" > }</span>
163
- <span class="cstat-no" title="statement not covered" > },</span>
164
- <span class="cstat-no" title="statement not covered" >});</span>
160
+ if (typeof opts.customMessage !== "string") {
161
+ throw new Error("customMessage must be a string");
162
+ }
163
+ },
164
+ });
165
165
  &nbsp;</pre></td></tr></table></pre>
166
166
 
167
167
  <div class='push'></div><!-- for sticky footer -->
@@ -169,7 +169,7 @@
169
169
  <div class='footer quiet pad2 space-top1 center small'>
170
170
  Code coverage generated by
171
171
  <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
172
- at 2025-04-02T20:08:01.942Z
172
+ at 2025-11-07T18:00:58.549Z
173
173
  </div>
174
174
  <script src="../prettify.js"></script>
175
175
  <script>