@enhance-eng/archangel 0.1.1 → 0.3.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 +3 -3
- package/archangel.schema.json +308 -11
- package/index.d.ts +221 -58
- package/package.json +17 -8
package/README.md
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
Architecture tests for TypeScript, checked in milliseconds. You write
|
|
8
|
-
|
|
7
|
+
Architecture tests for TypeScript, checked in milliseconds. You write a table of what each part of
|
|
8
|
+
your code may import. Archangel tells you when the code breaks the table, and what to do about it. It checks
|
|
9
9
|
a large repository in about a second, so it can run in your editor as you type.
|
|
10
10
|
|
|
11
11
|
```sh
|
|
@@ -18,7 +18,7 @@ Archangel checks imports, import cycles, file and folder names, the files that f
|
|
|
18
18
|
and exports. It has presets for Feature-Sliced Design and Next.js, and you can write your own
|
|
19
19
|
conditions in TypeScript.
|
|
20
20
|
|
|
21
|
-
- [
|
|
21
|
+
- [Get started](https://github.com/enhance-labs-builds/archangel/blob/main/README.md#get-started)
|
|
22
22
|
- [Rules](https://github.com/enhance-labs-builds/archangel/blob/main/docs/rules.md)
|
|
23
23
|
- [Presets](https://github.com/enhance-labs-builds/archangel/blob/main/docs/presets.md)
|
|
24
24
|
- [Plugins](https://github.com/enhance-labs-builds/archangel/blob/main/docs/plugins.md)
|
package/archangel.schema.json
CHANGED
|
@@ -5,14 +5,32 @@
|
|
|
5
5
|
"description": "The elements of a repository, named sets of its files, and the rules between them. Archangel checks the same fields, with every problem at once.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"additionalProperties": false,
|
|
8
|
-
"required": [
|
|
9
|
-
"elements"
|
|
10
|
-
],
|
|
11
8
|
"properties": {
|
|
12
9
|
"$schema": {
|
|
13
10
|
"type": "string",
|
|
14
11
|
"description": "This schema, for editors; archangel ignores it."
|
|
15
12
|
},
|
|
13
|
+
"parts": {
|
|
14
|
+
"type": "object",
|
|
15
|
+
"description": "The parts of the code, by file pattern. A file is in one part at most.",
|
|
16
|
+
"minProperties": 1,
|
|
17
|
+
"additionalProperties": {
|
|
18
|
+
"oneOf": [
|
|
19
|
+
{
|
|
20
|
+
"type": "string",
|
|
21
|
+
"description": "A path pattern; `{name}` captures one instance, such as one feature."
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"type": "array",
|
|
25
|
+
"items": {
|
|
26
|
+
"type": "string"
|
|
27
|
+
},
|
|
28
|
+
"minItems": 1,
|
|
29
|
+
"description": "Several path patterns."
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
},
|
|
16
34
|
"elements": {
|
|
17
35
|
"type": "object",
|
|
18
36
|
"description": "The elements: parts of the code by file pattern, or packages, by name.",
|
|
@@ -51,6 +69,13 @@
|
|
|
51
69
|
]
|
|
52
70
|
}
|
|
53
71
|
},
|
|
72
|
+
"groups": {
|
|
73
|
+
"type": "object",
|
|
74
|
+
"description": "The same as `selectors`: named sets of files, which may overlap.",
|
|
75
|
+
"additionalProperties": {
|
|
76
|
+
"$ref": "#/definitions/selector"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
54
79
|
"selectors": {
|
|
55
80
|
"type": "object",
|
|
56
81
|
"description": "Named sets of files, which rules and other selectors use by name. A selector's name may not be an element's.",
|
|
@@ -58,6 +83,18 @@
|
|
|
58
83
|
"$ref": "#/definitions/selector"
|
|
59
84
|
}
|
|
60
85
|
},
|
|
86
|
+
"externals": {
|
|
87
|
+
"type": "object",
|
|
88
|
+
"description": "Named lists of outside packages, such as `pg`, `@aws-sdk/*` or `node:fs`.",
|
|
89
|
+
"additionalProperties": {
|
|
90
|
+
"type": "array",
|
|
91
|
+
"items": {
|
|
92
|
+
"type": "string"
|
|
93
|
+
},
|
|
94
|
+
"minItems": 1,
|
|
95
|
+
"description": "Package names. A package is in every set that lists it."
|
|
96
|
+
}
|
|
97
|
+
},
|
|
61
98
|
"rules": {
|
|
62
99
|
"type": "array",
|
|
63
100
|
"description": "The rules: a shorthand with `kind`, or a sentence of `files` and one condition.",
|
|
@@ -83,6 +120,10 @@
|
|
|
83
120
|
"type": "string",
|
|
84
121
|
"description": "Why the rule exists, shown with each violation."
|
|
85
122
|
},
|
|
123
|
+
"because": {
|
|
124
|
+
"type": "string",
|
|
125
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
126
|
+
},
|
|
86
127
|
"link": {
|
|
87
128
|
"type": "string",
|
|
88
129
|
"description": "Where to read more, shown with each violation."
|
|
@@ -129,6 +170,10 @@
|
|
|
129
170
|
"type": "string",
|
|
130
171
|
"description": "Why the rule exists, shown with each violation."
|
|
131
172
|
},
|
|
173
|
+
"because": {
|
|
174
|
+
"type": "string",
|
|
175
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
176
|
+
},
|
|
132
177
|
"link": {
|
|
133
178
|
"type": "string",
|
|
134
179
|
"description": "Where to read more, shown with each violation."
|
|
@@ -172,6 +217,10 @@
|
|
|
172
217
|
"type": "string",
|
|
173
218
|
"description": "Why the rule exists, shown with each violation."
|
|
174
219
|
},
|
|
220
|
+
"because": {
|
|
221
|
+
"type": "string",
|
|
222
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
223
|
+
},
|
|
175
224
|
"link": {
|
|
176
225
|
"type": "string",
|
|
177
226
|
"description": "Where to read more, shown with each violation."
|
|
@@ -203,6 +252,116 @@
|
|
|
203
252
|
}
|
|
204
253
|
}
|
|
205
254
|
},
|
|
255
|
+
{
|
|
256
|
+
"type": "object",
|
|
257
|
+
"description": "An import table: for each row, what its files may import. Each row is a rule named `<table>.<row>`.",
|
|
258
|
+
"additionalProperties": false,
|
|
259
|
+
"required": [
|
|
260
|
+
"kind",
|
|
261
|
+
"name",
|
|
262
|
+
"rows"
|
|
263
|
+
],
|
|
264
|
+
"properties": {
|
|
265
|
+
"kind": {
|
|
266
|
+
"const": "mayImport"
|
|
267
|
+
},
|
|
268
|
+
"name": {
|
|
269
|
+
"type": "string",
|
|
270
|
+
"description": "The table's name, which starts the name of each row. It has no colon and no slash."
|
|
271
|
+
},
|
|
272
|
+
"rows": {
|
|
273
|
+
"type": "object",
|
|
274
|
+
"description": "Each row: a part, a group or a kind, and what its files may import.",
|
|
275
|
+
"additionalProperties": {
|
|
276
|
+
"type": "array",
|
|
277
|
+
"items": {
|
|
278
|
+
"type": "string"
|
|
279
|
+
},
|
|
280
|
+
"description": "Names of rows, parts, groups and externals sets, or path patterns."
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
"files": {
|
|
284
|
+
"$ref": "#/definitions/selector",
|
|
285
|
+
"description": "The files whose imports the table judges. By default, the files of its rows."
|
|
286
|
+
},
|
|
287
|
+
"kinds": {
|
|
288
|
+
"type": "string",
|
|
289
|
+
"description": "The pattern that gives each file its kind, with the capture `{kind}`."
|
|
290
|
+
},
|
|
291
|
+
"within": {
|
|
292
|
+
"$ref": "#/definitions/side",
|
|
293
|
+
"description": "An area: the rows judge only imports whose target is in it."
|
|
294
|
+
},
|
|
295
|
+
"everyRowMayImport": {
|
|
296
|
+
"type": "array",
|
|
297
|
+
"items": {
|
|
298
|
+
"type": "string"
|
|
299
|
+
},
|
|
300
|
+
"description": "Cells that every row also has."
|
|
301
|
+
},
|
|
302
|
+
"mayNotImportItself": {
|
|
303
|
+
"type": "array",
|
|
304
|
+
"items": {
|
|
305
|
+
"type": "string"
|
|
306
|
+
},
|
|
307
|
+
"description": "The rows that do not permit their own name."
|
|
308
|
+
},
|
|
309
|
+
"because": {
|
|
310
|
+
"type": "string",
|
|
311
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
312
|
+
},
|
|
313
|
+
"reason": {
|
|
314
|
+
"type": "string",
|
|
315
|
+
"description": "Why the rule exists, shown with each violation."
|
|
316
|
+
},
|
|
317
|
+
"link": {
|
|
318
|
+
"type": "string",
|
|
319
|
+
"description": "Where to read more, shown with each violation."
|
|
320
|
+
},
|
|
321
|
+
"imports": {
|
|
322
|
+
"enum": [
|
|
323
|
+
"all",
|
|
324
|
+
"runtime",
|
|
325
|
+
"types"
|
|
326
|
+
],
|
|
327
|
+
"description": "Which imports the rule checks: all of them, those that stay at runtime, or type imports."
|
|
328
|
+
},
|
|
329
|
+
"names": {
|
|
330
|
+
"type": "array",
|
|
331
|
+
"items": {
|
|
332
|
+
"type": "string"
|
|
333
|
+
},
|
|
334
|
+
"minItems": 1,
|
|
335
|
+
"description": "Only imports that bring in one of these names."
|
|
336
|
+
},
|
|
337
|
+
"specifier": {
|
|
338
|
+
"enum": [
|
|
339
|
+
"relative",
|
|
340
|
+
"parent",
|
|
341
|
+
"alias",
|
|
342
|
+
"package"
|
|
343
|
+
],
|
|
344
|
+
"description": "Only imports whose specifier is written this way."
|
|
345
|
+
},
|
|
346
|
+
"dependency": {
|
|
347
|
+
"enum": [
|
|
348
|
+
"dev",
|
|
349
|
+
"undeclared"
|
|
350
|
+
],
|
|
351
|
+
"description": "Only imports of packages that the nearest package.json lists this way."
|
|
352
|
+
},
|
|
353
|
+
"instance": {
|
|
354
|
+
"enum": [
|
|
355
|
+
"same",
|
|
356
|
+
"different"
|
|
357
|
+
],
|
|
358
|
+
"description": "Only imports whose two ends compare this way, in the row's name."
|
|
359
|
+
},
|
|
360
|
+
"examples": {
|
|
361
|
+
"$ref": "#/definitions/examples"
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
},
|
|
206
365
|
{
|
|
207
366
|
"type": "object",
|
|
208
367
|
"description": "The files may not import the other side.",
|
|
@@ -224,6 +383,10 @@
|
|
|
224
383
|
"type": "string",
|
|
225
384
|
"description": "Why the rule exists, shown with each violation."
|
|
226
385
|
},
|
|
386
|
+
"because": {
|
|
387
|
+
"type": "string",
|
|
388
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
389
|
+
},
|
|
227
390
|
"link": {
|
|
228
391
|
"type": "string",
|
|
229
392
|
"description": "Where to read more, shown with each violation."
|
|
@@ -342,6 +505,10 @@
|
|
|
342
505
|
"type": "string",
|
|
343
506
|
"description": "Why the rule exists, shown with each violation."
|
|
344
507
|
},
|
|
508
|
+
"because": {
|
|
509
|
+
"type": "string",
|
|
510
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
511
|
+
},
|
|
345
512
|
"link": {
|
|
346
513
|
"type": "string",
|
|
347
514
|
"description": "Where to read more, shown with each violation."
|
|
@@ -358,8 +525,16 @@
|
|
|
358
525
|
"$ref": "#/definitions/examples"
|
|
359
526
|
},
|
|
360
527
|
"mayOnlyImport": {
|
|
361
|
-
"
|
|
362
|
-
|
|
528
|
+
"anyOf": [
|
|
529
|
+
{
|
|
530
|
+
"$ref": "#/definitions/side"
|
|
531
|
+
},
|
|
532
|
+
{
|
|
533
|
+
"type": "array",
|
|
534
|
+
"maxItems": 0
|
|
535
|
+
}
|
|
536
|
+
],
|
|
537
|
+
"description": "All that the files may import, besides each other. An empty list needs `within`."
|
|
363
538
|
},
|
|
364
539
|
"names": {
|
|
365
540
|
"type": "array",
|
|
@@ -392,6 +567,10 @@
|
|
|
392
567
|
"undeclared"
|
|
393
568
|
],
|
|
394
569
|
"description": "Only imports of packages that the importing file's nearest package.json lists only as development dependencies, or does not list at all."
|
|
570
|
+
},
|
|
571
|
+
"within": {
|
|
572
|
+
"$ref": "#/definitions/side",
|
|
573
|
+
"description": "The area: only imports whose other end is in it. On `mayOnlyImport` the target, and on `mayOnlyBeImportedBy` the importer."
|
|
395
574
|
}
|
|
396
575
|
}
|
|
397
576
|
},
|
|
@@ -416,6 +595,10 @@
|
|
|
416
595
|
"type": "string",
|
|
417
596
|
"description": "Why the rule exists, shown with each violation."
|
|
418
597
|
},
|
|
598
|
+
"because": {
|
|
599
|
+
"type": "string",
|
|
600
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
601
|
+
},
|
|
419
602
|
"link": {
|
|
420
603
|
"type": "string",
|
|
421
604
|
"description": "Where to read more, shown with each violation."
|
|
@@ -466,6 +649,10 @@
|
|
|
466
649
|
"undeclared"
|
|
467
650
|
],
|
|
468
651
|
"description": "Only imports of packages that the importing file's nearest package.json lists only as development dependencies, or does not list at all."
|
|
652
|
+
},
|
|
653
|
+
"within": {
|
|
654
|
+
"$ref": "#/definitions/side",
|
|
655
|
+
"description": "The area: only imports whose other end is in it. On `mayOnlyImport` the target, and on `mayOnlyBeImportedBy` the importer."
|
|
469
656
|
}
|
|
470
657
|
}
|
|
471
658
|
},
|
|
@@ -490,6 +677,10 @@
|
|
|
490
677
|
"type": "string",
|
|
491
678
|
"description": "Why the rule exists, shown with each violation."
|
|
492
679
|
},
|
|
680
|
+
"because": {
|
|
681
|
+
"type": "string",
|
|
682
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
683
|
+
},
|
|
493
684
|
"link": {
|
|
494
685
|
"type": "string",
|
|
495
686
|
"description": "Where to read more, shown with each violation."
|
|
@@ -504,9 +695,12 @@
|
|
|
504
695
|
},
|
|
505
696
|
{
|
|
506
697
|
"$ref": "#/definitions/namePattern"
|
|
698
|
+
},
|
|
699
|
+
{
|
|
700
|
+
"$ref": "#/definitions/nameList"
|
|
507
701
|
}
|
|
508
702
|
],
|
|
509
|
-
"description": "A style that the name, up to the first dot, must be in, or a name pattern that the full name, without the last extension, must match."
|
|
703
|
+
"description": "A style that the name, up to the first dot, must be in, or a name pattern that the full name, without the last extension, must match, or a list of them, of which one must match."
|
|
510
704
|
}
|
|
511
705
|
}
|
|
512
706
|
},
|
|
@@ -544,6 +738,10 @@
|
|
|
544
738
|
"type": "string",
|
|
545
739
|
"description": "Why the rule exists, shown with each violation."
|
|
546
740
|
},
|
|
741
|
+
"because": {
|
|
742
|
+
"type": "string",
|
|
743
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
744
|
+
},
|
|
547
745
|
"link": {
|
|
548
746
|
"type": "string",
|
|
549
747
|
"description": "Where to read more, shown with each violation."
|
|
@@ -558,9 +756,12 @@
|
|
|
558
756
|
},
|
|
559
757
|
{
|
|
560
758
|
"$ref": "#/definitions/namePattern"
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
"$ref": "#/definitions/nameList"
|
|
561
762
|
}
|
|
562
763
|
],
|
|
563
|
-
"description": "A style that each folder's name must be in, or a name pattern that it must match, which may use `{FolderName}` for the folder that holds it."
|
|
764
|
+
"description": "A style that each folder's name must be in, or a name pattern that it must match, which may use `{FolderName}` for the folder that holds it, or a list of them, of which one must match."
|
|
564
765
|
}
|
|
565
766
|
}
|
|
566
767
|
},
|
|
@@ -585,6 +786,10 @@
|
|
|
585
786
|
"type": "string",
|
|
586
787
|
"description": "Why the rule exists, shown with each violation."
|
|
587
788
|
},
|
|
789
|
+
"because": {
|
|
790
|
+
"type": "string",
|
|
791
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
792
|
+
},
|
|
588
793
|
"link": {
|
|
589
794
|
"type": "string",
|
|
590
795
|
"description": "Where to read more, shown with each violation."
|
|
@@ -645,6 +850,10 @@
|
|
|
645
850
|
"type": "string",
|
|
646
851
|
"description": "Why the rule exists, shown with each violation."
|
|
647
852
|
},
|
|
853
|
+
"because": {
|
|
854
|
+
"type": "string",
|
|
855
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
856
|
+
},
|
|
648
857
|
"link": {
|
|
649
858
|
"type": "string",
|
|
650
859
|
"description": "Where to read more, shown with each violation."
|
|
@@ -692,6 +901,10 @@
|
|
|
692
901
|
"type": "string",
|
|
693
902
|
"description": "Why the rule exists, shown with each violation."
|
|
694
903
|
},
|
|
904
|
+
"because": {
|
|
905
|
+
"type": "string",
|
|
906
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
907
|
+
},
|
|
695
908
|
"link": {
|
|
696
909
|
"type": "string",
|
|
697
910
|
"description": "Where to read more, shown with each violation."
|
|
@@ -739,6 +952,10 @@
|
|
|
739
952
|
"type": "string",
|
|
740
953
|
"description": "Why the rule exists, shown with each violation."
|
|
741
954
|
},
|
|
955
|
+
"because": {
|
|
956
|
+
"type": "string",
|
|
957
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
958
|
+
},
|
|
742
959
|
"link": {
|
|
743
960
|
"type": "string",
|
|
744
961
|
"description": "Where to read more, shown with each violation."
|
|
@@ -773,6 +990,10 @@
|
|
|
773
990
|
"type": "string",
|
|
774
991
|
"description": "Why the rule exists, shown with each violation."
|
|
775
992
|
},
|
|
993
|
+
"because": {
|
|
994
|
+
"type": "string",
|
|
995
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
996
|
+
},
|
|
776
997
|
"link": {
|
|
777
998
|
"type": "string",
|
|
778
999
|
"description": "Where to read more, shown with each violation."
|
|
@@ -807,6 +1028,10 @@
|
|
|
807
1028
|
"type": "string",
|
|
808
1029
|
"description": "Why the rule exists, shown with each violation."
|
|
809
1030
|
},
|
|
1031
|
+
"because": {
|
|
1032
|
+
"type": "string",
|
|
1033
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
1034
|
+
},
|
|
810
1035
|
"link": {
|
|
811
1036
|
"type": "string",
|
|
812
1037
|
"description": "Where to read more, shown with each violation."
|
|
@@ -851,6 +1076,10 @@
|
|
|
851
1076
|
"type": "string",
|
|
852
1077
|
"description": "Why the rule exists, shown with each violation."
|
|
853
1078
|
},
|
|
1079
|
+
"because": {
|
|
1080
|
+
"type": "string",
|
|
1081
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
1082
|
+
},
|
|
854
1083
|
"link": {
|
|
855
1084
|
"type": "string",
|
|
856
1085
|
"description": "Where to read more, shown with each violation."
|
|
@@ -885,6 +1114,10 @@
|
|
|
885
1114
|
"type": "string",
|
|
886
1115
|
"description": "Why the rule exists, shown with each violation."
|
|
887
1116
|
},
|
|
1117
|
+
"because": {
|
|
1118
|
+
"type": "string",
|
|
1119
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
1120
|
+
},
|
|
888
1121
|
"link": {
|
|
889
1122
|
"type": "string",
|
|
890
1123
|
"description": "Where to read more, shown with each violation."
|
|
@@ -923,6 +1156,10 @@
|
|
|
923
1156
|
"type": "string",
|
|
924
1157
|
"description": "Why the rule exists, shown with each violation."
|
|
925
1158
|
},
|
|
1159
|
+
"because": {
|
|
1160
|
+
"type": "string",
|
|
1161
|
+
"description": "The same as `reason`: why the rule exists. A rule has one of the two."
|
|
1162
|
+
},
|
|
926
1163
|
"link": {
|
|
927
1164
|
"type": "string",
|
|
928
1165
|
"description": "Where to read more, shown with each violation."
|
|
@@ -1000,13 +1237,29 @@
|
|
|
1000
1237
|
"accepted": {
|
|
1001
1238
|
"type": "array",
|
|
1002
1239
|
"items": {
|
|
1003
|
-
"
|
|
1240
|
+
"anyOf": [
|
|
1241
|
+
{
|
|
1242
|
+
"type": "string",
|
|
1243
|
+
"description": "One line, such as `src/a.ts imports src/b.ts`, for which archangel writes the files."
|
|
1244
|
+
},
|
|
1245
|
+
{
|
|
1246
|
+
"$ref": "#/definitions/exampleFiles"
|
|
1247
|
+
}
|
|
1248
|
+
]
|
|
1004
1249
|
}
|
|
1005
1250
|
},
|
|
1006
1251
|
"rejected": {
|
|
1007
1252
|
"type": "array",
|
|
1008
1253
|
"items": {
|
|
1009
|
-
"
|
|
1254
|
+
"anyOf": [
|
|
1255
|
+
{
|
|
1256
|
+
"type": "string",
|
|
1257
|
+
"description": "One line, such as `src/a.ts imports src/b.ts`, for which archangel writes the files."
|
|
1258
|
+
},
|
|
1259
|
+
{
|
|
1260
|
+
"$ref": "#/definitions/exampleFiles"
|
|
1261
|
+
}
|
|
1262
|
+
]
|
|
1010
1263
|
}
|
|
1011
1264
|
}
|
|
1012
1265
|
}
|
|
@@ -1186,7 +1439,51 @@
|
|
|
1186
1439
|
"namePattern": {
|
|
1187
1440
|
"type": "string",
|
|
1188
1441
|
"minLength": 1,
|
|
1189
|
-
"description": "A name: text, `*` for any text, and `{FileName}`, `{fileName}`, `{file-name}`, `{file_name}` or `{FILE_NAME}` for the file's name in each style, or the same spellings of `{FolderName}` for the name of the folder that holds it."
|
|
1442
|
+
"description": "A name: text, `*` for any text or no text, and `{FileName}`, `{fileName}`, `{file-name}`, `{file_name}` or `{FILE_NAME}` for the file's name in each style, or the same spellings of `{FolderName}` for the name of the folder that holds it."
|
|
1443
|
+
},
|
|
1444
|
+
"nameList": {
|
|
1445
|
+
"type": "array",
|
|
1446
|
+
"minItems": 1,
|
|
1447
|
+
"items": {
|
|
1448
|
+
"anyOf": [
|
|
1449
|
+
{
|
|
1450
|
+
"$ref": "#/definitions/style"
|
|
1451
|
+
},
|
|
1452
|
+
{
|
|
1453
|
+
"$ref": "#/definitions/namePattern"
|
|
1454
|
+
}
|
|
1455
|
+
]
|
|
1456
|
+
},
|
|
1457
|
+
"description": "The names that a `mustBeNamed` rule permits. One entry must match."
|
|
1458
|
+
}
|
|
1459
|
+
},
|
|
1460
|
+
"anyOf": [
|
|
1461
|
+
{
|
|
1462
|
+
"properties": {
|
|
1463
|
+
"parts": true
|
|
1464
|
+
},
|
|
1465
|
+
"required": [
|
|
1466
|
+
"parts"
|
|
1467
|
+
]
|
|
1468
|
+
},
|
|
1469
|
+
{
|
|
1470
|
+
"properties": {
|
|
1471
|
+
"elements": true
|
|
1472
|
+
},
|
|
1473
|
+
"required": [
|
|
1474
|
+
"elements"
|
|
1475
|
+
]
|
|
1476
|
+
},
|
|
1477
|
+
{
|
|
1478
|
+
"properties": {
|
|
1479
|
+
"rules": {
|
|
1480
|
+
"type": "array",
|
|
1481
|
+
"minItems": 1
|
|
1482
|
+
}
|
|
1483
|
+
},
|
|
1484
|
+
"required": [
|
|
1485
|
+
"rules"
|
|
1486
|
+
]
|
|
1190
1487
|
}
|
|
1191
|
-
|
|
1488
|
+
]
|
|
1192
1489
|
}
|
package/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// The types of an archangel config. They check, as the config is written, that every rule names a
|
|
2
|
-
// declared
|
|
3
|
-
// rule names
|
|
4
|
-
// left to archangel, because checking them here makes TypeScript infer mutable
|
|
2
|
+
// declared part or group, that a sentence has exactly one condition, that a table's cells name
|
|
3
|
+
// something, and that an isolate rule names a part with a capture such as `{feature}`. The names
|
|
4
|
+
// inside `groups` are left to archangel, because checking them here makes TypeScript infer mutable
|
|
5
|
+
// lists for them. `parts` and `elements` are two spellings of one key, as are `groups` and
|
|
6
|
+
// `selectors`, and `because` and `reason`: a config uses one spelling of each.
|
|
5
7
|
|
|
6
8
|
import type { AnyCondition, Plugin } from './plugin.js';
|
|
7
9
|
|
|
@@ -29,6 +31,14 @@ type Captures<S> = S extends string
|
|
|
29
31
|
: false
|
|
30
32
|
: false;
|
|
31
33
|
|
|
34
|
+
/** The named sets of outside packages. */
|
|
35
|
+
export type Externals = Readonly<Record<string, readonly string[]>>;
|
|
36
|
+
|
|
37
|
+
/** Each externals set, as the package element it reads as. */
|
|
38
|
+
type ExternalElements<X extends Externals> = {
|
|
39
|
+
readonly [K in keyof X]: { readonly packages: readonly string[] };
|
|
40
|
+
};
|
|
41
|
+
|
|
32
42
|
/** The name of a declared element. */
|
|
33
43
|
export type ElementName<E extends Elements> = Extract<keyof E, string>;
|
|
34
44
|
|
|
@@ -99,21 +109,35 @@ export type Side<E extends Elements, S extends Selectors> =
|
|
|
99
109
|
/** Files by path, relative to the config folder, with their text. */
|
|
100
110
|
export type ExampleFiles = Readonly<Record<string, string>>;
|
|
101
111
|
|
|
102
|
-
/**
|
|
103
|
-
export
|
|
112
|
+
/** A one-line example, such as `'src/a.ts imports src/b.ts'`, or the files of an example. */
|
|
113
|
+
export type Example = string | ExampleFiles;
|
|
114
|
+
|
|
115
|
+
/** What the examples of a rule hold. */
|
|
116
|
+
export interface Examples {
|
|
117
|
+
/** Examples that the rule must accept. */
|
|
118
|
+
readonly accepted?: readonly Example[];
|
|
119
|
+
/** Examples that the rule must reject. */
|
|
120
|
+
readonly rejected?: readonly Example[];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Why a rule exists, shown with each violation. A rule has one of the two spellings. */
|
|
124
|
+
type Because =
|
|
125
|
+
| { readonly because?: string; readonly reason?: never }
|
|
126
|
+
| { readonly reason?: string; readonly because?: never };
|
|
127
|
+
|
|
128
|
+
/** What every rule may have, and its reason. */
|
|
129
|
+
export type RuleOptions = CommonOptions & Because;
|
|
130
|
+
|
|
131
|
+
/** What every rule may have, without its reason. */
|
|
132
|
+
export interface CommonOptions {
|
|
104
133
|
/** The rule's name, for exceptions and the baseline; each rule gives a default. */
|
|
105
134
|
readonly name?: string;
|
|
106
|
-
/** Why the rule exists, shown with each violation. */
|
|
107
|
-
readonly reason?: string;
|
|
108
135
|
/** Where to read more, shown with each violation. */
|
|
109
136
|
readonly link?: string;
|
|
110
137
|
/** Which imports the rule checks: all of them, those that stay at runtime, or type imports. */
|
|
111
138
|
readonly imports?: 'all' | 'runtime' | 'types';
|
|
112
|
-
/**
|
|
113
|
-
readonly examples?:
|
|
114
|
-
readonly accepted?: readonly ExampleFiles[];
|
|
115
|
-
readonly rejected?: readonly ExampleFiles[];
|
|
116
|
-
};
|
|
139
|
+
/** Examples that the rule must accept and must reject, which `archangel test` checks. */
|
|
140
|
+
readonly examples?: Examples;
|
|
117
141
|
}
|
|
118
142
|
|
|
119
143
|
/**
|
|
@@ -153,12 +177,15 @@ export interface ImportLimits {
|
|
|
153
177
|
export type NameStyle = 'kebab-case' | 'camelCase' | 'PascalCase' | 'snake_case' | 'SCREAMING_SNAKE_CASE';
|
|
154
178
|
|
|
155
179
|
/**
|
|
156
|
-
* A name: text, `*` for any text, and `{FileName}`, `{fileName}`, `{file-name}`, `{file_name}` or
|
|
180
|
+
* A name: text, `*` for any text or no text, and `{FileName}`, `{fileName}`, `{file-name}`, `{file_name}` or
|
|
157
181
|
* `{FILE_NAME}` for the file's name in each style, or the same spellings of `{FolderName}` for the
|
|
158
182
|
* name of the folder that holds it.
|
|
159
183
|
*/
|
|
160
184
|
export type NamePattern = string;
|
|
161
185
|
|
|
186
|
+
/** One name that a `mustBeNamed` rule permits: a style or a name pattern. */
|
|
187
|
+
export type NameEntry = NameStyle | (NamePattern & {});
|
|
188
|
+
|
|
162
189
|
type Conditions<Other> = {
|
|
163
190
|
/** The files may not import the other side. */
|
|
164
191
|
readonly mayNotImport: Other;
|
|
@@ -168,9 +195,9 @@ type Conditions<Other> = {
|
|
|
168
195
|
readonly mayOnlyBeImportedBy: Other;
|
|
169
196
|
/**
|
|
170
197
|
* The name, up to the first dot, is in a style, or the full name, without the last extension,
|
|
171
|
-
* matches a name pattern.
|
|
198
|
+
* matches a name pattern. In a list, one entry must match.
|
|
172
199
|
*/
|
|
173
|
-
readonly mustBeNamed:
|
|
200
|
+
readonly mustBeNamed: NameEntry | readonly [NameEntry, ...NameEntry[]];
|
|
174
201
|
/**
|
|
175
202
|
* Each instance of `files`, an element with a capture, has a file that matches the pattern, or
|
|
176
203
|
* one of the patterns.
|
|
@@ -197,15 +224,21 @@ type NoLimits = { readonly [K in keyof ImportLimits]?: never };
|
|
|
197
224
|
|
|
198
225
|
type NoChains = { readonly transitively?: false; readonly stopAt?: never };
|
|
199
226
|
|
|
227
|
+
type NoArea = { readonly within?: never };
|
|
228
|
+
|
|
229
|
+
/** The area whose imports an import condition judges: an import outside it passes the rule. */
|
|
230
|
+
type Area<E extends Elements, S extends Selectors> = { readonly within?: Side<E, S> };
|
|
231
|
+
|
|
200
232
|
/** A rule written as a sentence: `files`, and exactly one condition. */
|
|
201
|
-
export type Sentence<E extends Elements, S extends Selectors> = Omit<
|
|
233
|
+
export type Sentence<E extends Elements, S extends Selectors> = Omit<CommonOptions, 'imports'> & Because & {
|
|
202
234
|
readonly kind?: never;
|
|
203
235
|
/** The files the rule is about. */
|
|
204
236
|
readonly files: Files<E, S>;
|
|
205
237
|
} & (
|
|
206
|
-
| (Only<Side<E, S>, 'mayNotImport'> & ImportLimits & NoChains & Pick<
|
|
238
|
+
| (Only<Side<E, S>, 'mayNotImport'> & ImportLimits & NoChains & NoArea & Pick<CommonOptions, 'imports'>)
|
|
207
239
|
| (Only<Side<E, S>, 'mayNotImport'> &
|
|
208
|
-
NoLimits &
|
|
240
|
+
NoLimits &
|
|
241
|
+
NoArea & {
|
|
209
242
|
/** Follow chains of imports, not only direct ones. */
|
|
210
243
|
readonly transitively: true;
|
|
211
244
|
/** Files where a chain ends, such as `{ directive: 'use server' }`. */
|
|
@@ -213,24 +246,25 @@ export type Sentence<E extends Elements, S extends Selectors> = Omit<RuleOptions
|
|
|
213
246
|
/** A chain of type imports never runs, so a transitive rule checks no type imports. */
|
|
214
247
|
readonly imports?: 'all' | 'runtime';
|
|
215
248
|
})
|
|
216
|
-
| (Only<Side<E, S>, 'mayOnlyImport'> & ImportLimits & NoChains & Pick<
|
|
249
|
+
| (Only<Side<E, S>, 'mayOnlyImport'> & ImportLimits & NoChains & Area<E, S> & Pick<CommonOptions, 'imports'>)
|
|
217
250
|
| (Only<Side<E, S>, 'mayOnlyBeImportedBy'> &
|
|
218
251
|
ImportLimits &
|
|
219
252
|
NoChains &
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
| (Only<Side<E, S>, '
|
|
223
|
-
| (Only<Side<E, S>, '
|
|
224
|
-
| (Only<Side<E, S>, '
|
|
225
|
-
| (Only<Side<E, S>, '
|
|
226
|
-
| (Only<Side<E, S>, '
|
|
227
|
-
| (Only<Side<E, S>, '
|
|
253
|
+
Area<E, S> &
|
|
254
|
+
Pick<CommonOptions, 'imports'>)
|
|
255
|
+
| (Only<Side<E, S>, 'mustBeNamed'> & NoLimits & NoChains & NoArea & NoImports)
|
|
256
|
+
| (Only<Side<E, S>, 'mustContain'> & NoLimits & NoChains & NoArea & NoImports)
|
|
257
|
+
| (Only<Side<E, S>, 'mustNotExist'> & NoLimits & NoChains & NoArea & NoImports)
|
|
258
|
+
| (Only<Side<E, S>, 'mustExport'> & NoLimits & NoChains & NoArea & NoImports)
|
|
259
|
+
| (Only<Side<E, S>, 'mayNotExport'> & NoLimits & NoChains & NoArea & NoImports)
|
|
260
|
+
| (Only<Side<E, S>, 'mustOnlyReExport'> & NoLimits & NoChains & NoArea & NoImports)
|
|
261
|
+
| (Only<Side<E, S>, 'noCycles'> & NoLimits & NoChains & NoArea & Pick<CommonOptions, 'imports'>)
|
|
228
262
|
);
|
|
229
263
|
|
|
230
264
|
type NoImports = { readonly imports?: never };
|
|
231
265
|
|
|
232
266
|
/** A rule about folders: `folders`, and `mustBeNamed` or `mustContain`. */
|
|
233
|
-
export type FolderSentence = Omit<
|
|
267
|
+
export type FolderSentence = Omit<CommonOptions, 'imports'> & Because & {
|
|
234
268
|
readonly kind?: never;
|
|
235
269
|
readonly files?: never;
|
|
236
270
|
/**
|
|
@@ -241,6 +275,7 @@ export type FolderSentence = Omit<RuleOptions, 'imports'> & {
|
|
|
241
275
|
readonly folders: string | readonly string[];
|
|
242
276
|
} & NoLimits &
|
|
243
277
|
NoChains &
|
|
278
|
+
NoArea &
|
|
244
279
|
NoImports &
|
|
245
280
|
(
|
|
246
281
|
| (Only<never, 'mustBeNamed'>)
|
|
@@ -249,7 +284,7 @@ export type FolderSentence = Omit<RuleOptions, 'imports'> & {
|
|
|
249
284
|
);
|
|
250
285
|
|
|
251
286
|
/** A sentence of a rule of several sentences: the rule holds its name, reason and examples. */
|
|
252
|
-
type InnerSentence<T> = T extends unknown ? Omit<T, 'name' | 'reason' | 'link' | 'examples' | 'imports'> : never;
|
|
287
|
+
type InnerSentence<T> = T extends unknown ? Omit<T, 'name' | 'reason' | 'because' | 'link' | 'examples' | 'imports'> : never;
|
|
253
288
|
|
|
254
289
|
/** A shorthand as one sentence of a rule of several sentences. */
|
|
255
290
|
type InnerShorthand<E extends Elements> =
|
|
@@ -258,7 +293,7 @@ type InnerShorthand<E extends Elements> =
|
|
|
258
293
|
| { readonly kind: 'entry'; readonly element: NoInfer<ElementName<E>>; readonly files: readonly string[] };
|
|
259
294
|
|
|
260
295
|
/** A rule of several sentences, broken when any of them is, which needs a name. */
|
|
261
|
-
export type SeveralSentences<E extends Elements, S extends Selectors> = Omit<
|
|
296
|
+
export type SeveralSentences<E extends Elements, S extends Selectors> = Omit<CommonOptions, 'name'> & Because & {
|
|
262
297
|
readonly kind?: never;
|
|
263
298
|
readonly files?: never;
|
|
264
299
|
/** The rule's name, for exceptions and the baseline. */
|
|
@@ -279,21 +314,95 @@ export type ConditionName<P extends Plugins> = {
|
|
|
279
314
|
: never;
|
|
280
315
|
}[Extract<keyof P, string>];
|
|
281
316
|
|
|
317
|
+
/** The conditions of the `fsd` preset, which a config that extends it can use with its own files. */
|
|
318
|
+
export type FsdConditionName = `fsd/${
|
|
319
|
+
| 'typo-in-layer-name'
|
|
320
|
+
| 'ambiguous-slice-names'
|
|
321
|
+
| 'inconsistent-naming'
|
|
322
|
+
| 'insignificant-slice'
|
|
323
|
+
| 'repetitive-naming'
|
|
324
|
+
| 'excessive-slicing'
|
|
325
|
+
| 'shared-lib-grouping'}`;
|
|
326
|
+
|
|
282
327
|
/** A rule that uses a plugin's condition, whose options the condition's schema checks. */
|
|
283
328
|
export type PluginRule<E extends Elements, S extends Selectors, P extends Plugins> = Omit<
|
|
284
|
-
|
|
329
|
+
CommonOptions,
|
|
285
330
|
'imports'
|
|
286
|
-
> & {
|
|
331
|
+
> & Because & NoArea & {
|
|
287
332
|
readonly kind?: never;
|
|
288
333
|
/** The files whose records the condition sees. */
|
|
289
334
|
readonly files: Files<E, S>;
|
|
290
335
|
/** The condition, as `<plugin>/<condition>`. */
|
|
291
|
-
readonly plugin: NoInfer<ConditionName<P
|
|
336
|
+
readonly plugin: NoInfer<ConditionName<P>> | FsdConditionName;
|
|
292
337
|
/** The options, which the condition's JSON Schema checks when the config loads. */
|
|
293
338
|
readonly options?: unknown;
|
|
294
339
|
};
|
|
295
340
|
|
|
296
|
-
/** A
|
|
341
|
+
/** A word for a table or a row: any text with no colon and no slash. */
|
|
342
|
+
type NoSeparator<T extends string> = T extends `${string}:${string}` | `${string}/${string}`
|
|
343
|
+
? 'the name of a table or a row has no colon or slash'
|
|
344
|
+
: T;
|
|
345
|
+
|
|
346
|
+
/** The name of a table. */
|
|
347
|
+
export type TableName<T extends string> = NoSeparator<T>;
|
|
348
|
+
|
|
349
|
+
/** What a table's rows are, before their names are checked. */
|
|
350
|
+
export type TableRows = Readonly<Record<string, readonly string[]>>;
|
|
351
|
+
|
|
352
|
+
/** What a cell may name: a row, a declared name, or a path pattern. */
|
|
353
|
+
type TableCell<Row extends string, Declared extends string> = Row | Declared | PathPattern;
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* The rows `R`, with each cell checked, and each row name checked against `Key`, the row names that
|
|
357
|
+
* the table permits.
|
|
358
|
+
*/
|
|
359
|
+
type CheckedRows<R extends TableRows, Key extends string, Declared extends string> = {
|
|
360
|
+
readonly [Row in keyof R]: Row extends string
|
|
361
|
+
? Row extends NoSeparator<Row>
|
|
362
|
+
? Row extends Key
|
|
363
|
+
? readonly TableCell<Extract<keyof R, string>, Declared>[]
|
|
364
|
+
: 'a row of a table without kinds is a declared part or group'
|
|
365
|
+
: NoSeparator<Row>
|
|
366
|
+
: never;
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
/** A name that a table can use as a row without kinds: a part or a group, not a set of packages. */
|
|
370
|
+
type RowName<E extends Elements, S extends Selectors> = FileElementName<E> | Extract<keyof S, string>;
|
|
371
|
+
|
|
372
|
+
/** Every name that a cell can use. */
|
|
373
|
+
type DeclaredName<E extends Elements, S extends Selectors> = ElementName<E> | Extract<keyof S, string>;
|
|
374
|
+
|
|
375
|
+
/** The options of a table with the rows `R`. */
|
|
376
|
+
export type TableOptions<E extends Elements, S extends Selectors, Row extends string> = Omit<CommonOptions, 'name'> &
|
|
377
|
+
Because &
|
|
378
|
+
ImportLimits & {
|
|
379
|
+
/** The files that the table judges as importers; without it, every file with a row. */
|
|
380
|
+
readonly files?: Files<E, S>;
|
|
381
|
+
/** The area whose imports the table judges, and without it, the whole repository. */
|
|
382
|
+
readonly within?: Side<E, S>;
|
|
383
|
+
/** Cells that every row has, such as a file that all code may use. */
|
|
384
|
+
readonly everyRowMayImport?: readonly TableCell<NoInfer<Row>, DeclaredName<E, S>>[];
|
|
385
|
+
/** Rows that may not import their own name, in the same instance or in another. */
|
|
386
|
+
readonly mayNotImportItself?: readonly NoInfer<Row>[];
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
/** A table, as an object. Archangel checks its names when the config loads. */
|
|
390
|
+
export type TableRule = RuleOptions &
|
|
391
|
+
ImportLimits & {
|
|
392
|
+
readonly kind: 'mayImport';
|
|
393
|
+
readonly name: string;
|
|
394
|
+
readonly rows: TableRows;
|
|
395
|
+
readonly kinds?: string;
|
|
396
|
+
readonly files?: unknown;
|
|
397
|
+
readonly within?: unknown;
|
|
398
|
+
readonly everyRowMayImport?: readonly string[];
|
|
399
|
+
readonly mayNotImportItself?: readonly string[];
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
/** A rule's body when its name comes first. */
|
|
403
|
+
type Body<T> = T extends unknown ? Omit<T, 'name'> & { readonly name?: never } : never;
|
|
404
|
+
|
|
405
|
+
/** A rule, as an object: one of the three shorthands, a table, a sentence, or a plugin rule. */
|
|
297
406
|
export type Rule<E extends Elements, S extends Selectors = {}, P extends Plugins = {}> =
|
|
298
407
|
| (RuleOptions & { readonly kind: 'layers'; readonly order: readonly NoInfer<ElementName<E>>[] })
|
|
299
408
|
| (RuleOptions & { readonly kind: 'isolate'; readonly element: NoInfer<CapturedElement<E>> })
|
|
@@ -302,6 +411,7 @@ export type Rule<E extends Elements, S extends Selectors = {}, P extends Plugins
|
|
|
302
411
|
readonly element: NoInfer<ElementName<E>>;
|
|
303
412
|
readonly files: readonly string[];
|
|
304
413
|
})
|
|
414
|
+
| TableRule
|
|
305
415
|
| Sentence<E, S>
|
|
306
416
|
| FolderSentence
|
|
307
417
|
| SeveralSentences<E, S>
|
|
@@ -333,6 +443,26 @@ export interface RuleBuilders<
|
|
|
333
443
|
files: string | readonly string[],
|
|
334
444
|
options?: RuleOptions & Named<N, X>,
|
|
335
445
|
): Rule<E, S, P>;
|
|
446
|
+
/** A table of what each row may import, whose rows are kinds of file, parts or groups. */
|
|
447
|
+
mayImport<const T extends string, const R extends TableRows>(
|
|
448
|
+
name: TableName<T>,
|
|
449
|
+
rows: R & CheckedRows<R, string, DeclaredName<E, S>>,
|
|
450
|
+
options: TableOptions<E, S, Extract<keyof R, string>> & {
|
|
451
|
+
/** The pattern that gives a file its kind, such as `**\/*.{kind}.ts`. */
|
|
452
|
+
readonly kinds: string;
|
|
453
|
+
},
|
|
454
|
+
): Rule<E, S, P>;
|
|
455
|
+
/** A table whose rows are all parts or groups. */
|
|
456
|
+
mayImport<const T extends string, const R extends TableRows>(
|
|
457
|
+
name: TableName<T>,
|
|
458
|
+
rows: R & CheckedRows<R, RowName<E, S>, DeclaredName<E, S>>,
|
|
459
|
+
options?: TableOptions<E, S, Extract<keyof R, string>> & { readonly kinds?: never },
|
|
460
|
+
): Rule<E, S, P>;
|
|
461
|
+
/** A rule with its name first: `files`, or `folders`, and exactly one condition. */
|
|
462
|
+
rule<const N extends string = string>(
|
|
463
|
+
name: OwnRuleName<N, X>,
|
|
464
|
+
sentence: Body<Sentence<E, S> | FolderSentence | SeveralSentences<E, S> | PluginRule<E, S, P>>,
|
|
465
|
+
): Rule<E, S, P>;
|
|
336
466
|
/** A rule as a sentence: `files`, or `folders`, and exactly one condition or plugin condition. */
|
|
337
467
|
rule<const N extends string = string>(
|
|
338
468
|
sentence: (Sentence<E, S> | FolderSentence | SeveralSentences<E, S> | PluginRule<E, S, P>) &
|
|
@@ -351,8 +481,11 @@ export interface Preset<X extends string = string> {
|
|
|
351
481
|
readonly package?: string;
|
|
352
482
|
/** The folder the preset applies to, relative to the config folder. */
|
|
353
483
|
readonly root?: string;
|
|
484
|
+
readonly parts?: Elements;
|
|
354
485
|
readonly elements?: Elements;
|
|
486
|
+
readonly groups?: Selectors;
|
|
355
487
|
readonly selectors?: Selectors;
|
|
488
|
+
readonly externals?: Externals;
|
|
356
489
|
readonly plugins?: Plugins;
|
|
357
490
|
/** The rules, each with a name. */
|
|
358
491
|
readonly rules?: readonly unknown[] | ((builders: RuleBuilders<Elements, Selectors, Plugins>) => readonly unknown[]);
|
|
@@ -377,36 +510,65 @@ export declare function nextjs<const X extends string = 'nextjs'>(options?: {
|
|
|
377
510
|
readonly root?: string;
|
|
378
511
|
}): Preset<X>;
|
|
379
512
|
|
|
513
|
+
/** The parts of the code, by file pattern. A part holds files, so it has no packages. */
|
|
514
|
+
export type PartSpecs = Readonly<Record<string, string | readonly string[]>>;
|
|
515
|
+
|
|
516
|
+
/** One spelling of the parts of the code. */
|
|
517
|
+
type PartsKey<E extends Elements> =
|
|
518
|
+
| {
|
|
519
|
+
/** The parts of the code, by file pattern. Each file is in one part. */
|
|
520
|
+
readonly parts?: E & PartSpecs;
|
|
521
|
+
readonly elements?: never;
|
|
522
|
+
}
|
|
523
|
+
| {
|
|
524
|
+
/** The same as `parts`, which may also hold packages. */
|
|
525
|
+
readonly elements?: E;
|
|
526
|
+
readonly parts?: never;
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
/** One spelling of the named sets of files. */
|
|
530
|
+
type GroupsKey<S extends Selectors> =
|
|
531
|
+
| {
|
|
532
|
+
/** Named sets of files, which can cross parts, and which rules use by name. */
|
|
533
|
+
readonly groups?: S;
|
|
534
|
+
readonly selectors?: never;
|
|
535
|
+
}
|
|
536
|
+
| {
|
|
537
|
+
/** The same as `groups`. */
|
|
538
|
+
readonly selectors?: S;
|
|
539
|
+
readonly groups?: never;
|
|
540
|
+
};
|
|
541
|
+
|
|
380
542
|
/**
|
|
381
|
-
* An archangel config, which extends the presets named in `X
|
|
382
|
-
* names in `
|
|
543
|
+
* An archangel config, which extends the presets named in `X`, names its own rules with the names
|
|
544
|
+
* in `N`, and names the sets of outside packages in `O`.
|
|
383
545
|
*/
|
|
384
|
-
export
|
|
546
|
+
export type Config<
|
|
385
547
|
E extends Elements,
|
|
386
548
|
S extends Selectors = {},
|
|
387
549
|
P extends Plugins = {},
|
|
388
550
|
X extends string = string,
|
|
389
551
|
N extends string = string,
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
}
|
|
552
|
+
O extends Externals = {},
|
|
553
|
+
> = PartsKey<E> &
|
|
554
|
+
GroupsKey<S> & {
|
|
555
|
+
/** Named sets of outside packages, such as `{ driver: ['pg', '@aws-sdk/*', 'node:fs'] }`. */
|
|
556
|
+
readonly externals?: O;
|
|
557
|
+
/** Lines in `.gitignore` syntax that remove files from the check. */
|
|
558
|
+
readonly ignore?: readonly string[];
|
|
559
|
+
/** Specifiers that may stay unresolved, each with the reason; a specifier may end in `*`. */
|
|
560
|
+
readonly allowUnresolved?: Readonly<Record<string, string>>;
|
|
561
|
+
/** The plugins, by the name the rules use them by, as `plugin: '<name>/<condition>'`. */
|
|
562
|
+
readonly plugins?: P;
|
|
563
|
+
/** The presets the config extends; the config's own rules replace preset rules of one name. */
|
|
564
|
+
readonly extends?: readonly Preset<X>[];
|
|
565
|
+
/** Rule or table names to turn off after the presets are merged, such as `fsd/insignificant-slice`. */
|
|
566
|
+
readonly off?: readonly string[];
|
|
567
|
+
/** The rules, or a function that builds them. */
|
|
568
|
+
readonly rules?:
|
|
569
|
+
| readonly (Rule<E & ExternalElements<O>, S, P> & Named<N, X>)[]
|
|
570
|
+
| ((builders: RuleBuilders<E & ExternalElements<O>, S, P, X>) => readonly (Rule<E & ExternalElements<O>, S, P> & Named<N, X>)[]);
|
|
571
|
+
};
|
|
410
572
|
|
|
411
573
|
/** Declares an archangel config, with types that check its names as it is written. */
|
|
412
574
|
export declare function defineConfig<
|
|
@@ -415,4 +577,5 @@ export declare function defineConfig<
|
|
|
415
577
|
const P extends Plugins = {},
|
|
416
578
|
const X extends string = never,
|
|
417
579
|
const N extends string = string,
|
|
418
|
-
|
|
580
|
+
const O extends Externals = {},
|
|
581
|
+
>(config: Config<E, S, P, X, N, O>): Config<E, S, P, string, string, O>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enhance-eng/archangel",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Make architecture verifiable. Architecture tests for TypeScript, checked in milliseconds: imports, cycles, names, folder structure and exports.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"architecture",
|
|
@@ -53,12 +53,21 @@
|
|
|
53
53
|
"pluralize": "8.0.0"
|
|
54
54
|
},
|
|
55
55
|
"optionalDependencies": {
|
|
56
|
-
"@enhance-eng/archangel-darwin-arm64": "0.
|
|
57
|
-
"@enhance-eng/archangel-darwin-x64": "0.
|
|
58
|
-
"@enhance-eng/archangel-linux-arm64-gnu": "0.
|
|
59
|
-
"@enhance-eng/archangel-linux-arm64-musl": "0.
|
|
60
|
-
"@enhance-eng/archangel-linux-x64-gnu": "0.
|
|
61
|
-
"@enhance-eng/archangel-linux-x64-musl": "0.
|
|
62
|
-
"@enhance-eng/archangel-win32-x64": "0.
|
|
56
|
+
"@enhance-eng/archangel-darwin-arm64": "0.3.0",
|
|
57
|
+
"@enhance-eng/archangel-darwin-x64": "0.3.0",
|
|
58
|
+
"@enhance-eng/archangel-linux-arm64-gnu": "0.3.0",
|
|
59
|
+
"@enhance-eng/archangel-linux-arm64-musl": "0.3.0",
|
|
60
|
+
"@enhance-eng/archangel-linux-x64-gnu": "0.3.0",
|
|
61
|
+
"@enhance-eng/archangel-linux-x64-musl": "0.3.0",
|
|
62
|
+
"@enhance-eng/archangel-win32-x64": "0.3.0"
|
|
63
|
+
},
|
|
64
|
+
"tsd": {
|
|
65
|
+
"compilerOptions": {
|
|
66
|
+
"paths": {
|
|
67
|
+
"@enhance-eng/archangel": [
|
|
68
|
+
"./index.d.ts"
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
63
72
|
}
|
|
64
73
|
}
|