@conformetry/validation 0.0.1
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/LICENSE +21 -0
- package/README.md +515 -0
- package/dist/src/index.d.ts +302 -0
- package/dist/src/index.js +278 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jimmy Paolini
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
# 👔 Conformetry Validation
|
|
2
|
+
|
|
3
|
+
The validation orchestrator for [Conformetry](../conformetry-cli/README.md):
|
|
4
|
+
it matches instances to templates, checks the declared files exist, routes
|
|
5
|
+
each document to the validator that claims its extension, and deduplicates
|
|
6
|
+
what comes back.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install --save-dev @conformetry/validation
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { ValidationService } from "@conformetry/validation";
|
|
16
|
+
|
|
17
|
+
const result = validationService.validate({
|
|
18
|
+
instances, // from DiscoveryService.findInstances
|
|
19
|
+
templates, // from DiscoveryService.collectTemplate
|
|
20
|
+
languageNames: ["typescript"], // optional filter
|
|
21
|
+
threshold: 0.9, // optional run-level conformance floor
|
|
22
|
+
});
|
|
23
|
+
// → { ok, fileResults, checkedPaths, scores, unmatched }
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Instances arrive from the caller. This package used to scan the workspace for
|
|
27
|
+
`project.json` files and infer scope from generator name suffixes, which made a
|
|
28
|
+
generic package depend on one repository's layout.
|
|
29
|
+
|
|
30
|
+
## Order of checks
|
|
31
|
+
|
|
32
|
+
1. **Files exist.** Every file the matched template declares is checked first,
|
|
33
|
+
whatever its extension. A missing file cannot be compared, and reporting it
|
|
34
|
+
once is clearer than every language reporting it in turn. See
|
|
35
|
+
[`@conformetry/languages`](../conformetry-languages/README.md), whose
|
|
36
|
+
`FilesService` owns that pass.
|
|
37
|
+
2. **Documents compare.** Each validator sees only the documents whose
|
|
38
|
+
extensions it claims.
|
|
39
|
+
|
|
40
|
+
Instances that matched no template are reported alongside the content
|
|
41
|
+
differences rather than skipped, so one report covers both "this file is wrong"
|
|
42
|
+
and "conformetry cannot tell what this path was generated from".
|
|
43
|
+
|
|
44
|
+
## Scoring
|
|
45
|
+
|
|
46
|
+
Each matched instance is scored by how much of its template it honours, and
|
|
47
|
+
passes when that reaches the threshold resolved for it — the instance group's,
|
|
48
|
+
else the generator's, else the run's, else a perfect `1`.
|
|
49
|
+
|
|
50
|
+
Scores are taken **before** deduplication. Deduplication decides which template
|
|
51
|
+
gets to _print_ a shared file's finding, which is a reporting concern; a score
|
|
52
|
+
answers how well one instance honours its own template, so collapsing the
|
|
53
|
+
report must not change it.
|
|
54
|
+
|
|
55
|
+
`ok` is `false` when any instance falls below its threshold, or when any
|
|
56
|
+
instance matched no template at all — an unmatched path has no template to be
|
|
57
|
+
held to, so no threshold could excuse it.
|
|
58
|
+
|
|
59
|
+
## Language resolution
|
|
60
|
+
|
|
61
|
+
Which languages a run needs is
|
|
62
|
+
[`@conformetry/languages`](../conformetry-languages/README.md)'s question, not
|
|
63
|
+
this package's. `LanguagesService` is injected, asked which engines claim the
|
|
64
|
+
extensions the run's templates declare, and its answer is what `validate`
|
|
65
|
+
dispatches over. An extension no language claims is compared line by line by
|
|
66
|
+
the text fallback, so no template file goes unchecked.
|
|
67
|
+
|
|
68
|
+
Nothing is imported on demand any more. That mechanism bought install-time
|
|
69
|
+
optionality nobody was spending — the fallback makes every run need the
|
|
70
|
+
package regardless — so the specifier registry, the module loader, and the
|
|
71
|
+
`loadLanguageModule` option went with it. The trade-off, and the three
|
|
72
|
+
alternatives weighed against it, are recorded in
|
|
73
|
+
[ADR 0006](../../../../docs/adr/0006-hold-every-conformetry-language-in-one-package.md).
|
|
74
|
+
|
|
75
|
+
## Exports
|
|
76
|
+
|
|
77
|
+
`ValidationService`, `ValidationDeduplicationService`,
|
|
78
|
+
`ValidationFindingsService`, `ValidationScoringService`, `ValidationModule`,
|
|
79
|
+
and the `RunValidationArguments`, `RunValidationResult`, and
|
|
80
|
+
`InstanceFileResults` types.
|
|
81
|
+
|
|
82
|
+
## Test
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
nx run conformetry-validation:vitest
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT — see [LICENSE](../../../../LICENSE).
|
|
91
|
+
|
|
92
|
+
## 👔 Conformetry
|
|
93
|
+
|
|
94
|
+
This project was generated from the [nestjs-service-project](../../../../configuration/conformetry-templates/nestjs-service-project) conformetry template.
|
|
95
|
+
|
|
96
|
+
<!-- callidescope:start -->
|
|
97
|
+
|
|
98
|
+
## 🔭 Callidescope
|
|
99
|
+
|
|
100
|
+
Call stacks traced through `packages/ic-suite/conformetry/conformetry-validation`, deepest first. Each frame shows what it takes, what it returns, and what its documentation says.
|
|
101
|
+
|
|
102
|
+
| Measure | Value |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| Callables | 43 |
|
|
105
|
+
| Files | 18 |
|
|
106
|
+
| Calls traced | 43 |
|
|
107
|
+
| Call stacks | 0 |
|
|
108
|
+
| Deepest stack | 0 |
|
|
109
|
+
| Stacks through recursion | 0 |
|
|
110
|
+
| Unfollowable calls | 1 |
|
|
111
|
+
|
|
112
|
+
### Limits
|
|
113
|
+
|
|
114
|
+
What this project is judged against, as declared in its own `callidescope.config.ts`.
|
|
115
|
+
|
|
116
|
+
| Limit | Value |
|
|
117
|
+
| --- | --- |
|
|
118
|
+
| `maximumDepth` | 13 |
|
|
119
|
+
| `maximumBreadth` | 10 |
|
|
120
|
+
|
|
121
|
+
### Call stacks (depth)
|
|
122
|
+
|
|
123
|
+
None.
|
|
124
|
+
|
|
125
|
+
### Breadth
|
|
126
|
+
|
|
127
|
+
| Callable | Breadth | Calls directly | Location |
|
|
128
|
+
| --- | --- | --- | --- |
|
|
129
|
+
| `ValidationService.validate` | 10 | `ConfigurationService.matchInstances`, `ValidationService.selectValidators`, `LanguagesService.resolveValidators`, `ValidationService.readTemplateExtensions`, `ValidationService.map(…)`, `ValidationScoringService.scoreInstances`, `ValidationDeduplicationService.deduplicate`, `ValidationFindingsService.buildUnmatchedResults`, `ValidationService.map(…)`, `ValidationService.every(…)` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation.service.ts:136` |
|
|
130
|
+
| `ValidationService.validateInstance` | 6 | `ConfigurationService.prepareDocuments`, `ValidationService.flatMap(…)`, `FilesService.checkInstanceFiles`, `ValidationService.map(…)`, `ValidationService.flatMap(…)`, `ValidationService.reduce(…)` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation.service.ts:87` |
|
|
131
|
+
| `RunnerService.runValidator` | 4 | `RunnerService.map(…)`, `RunnerService.filter(…)`, `RunnerService.filter(…)`, `RunnerService.reduce(…)` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/runner/runner.service.ts:81` |
|
|
132
|
+
|
|
133
|
+
<details>
|
|
134
|
+
<summary>17 more callables</summary>
|
|
135
|
+
|
|
136
|
+
| Callable | Breadth | Calls directly | Location |
|
|
137
|
+
| --- | --- | --- | --- |
|
|
138
|
+
| `ValidationScoringService.scoreInstance` | 4 | `ValidationScoringService.reduce(…)`, `ScoringService.calculateScore`, `ValidationScoringService.resolveThreshold`, `ValidationScoringService.resolveInstancePath` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation-scoring.service.ts:74` |
|
|
139
|
+
| `ValidationDeduplicationService.deduplicate` | 2 | `ValidationDeduplicationService.selectOwners`, `ValidationDeduplicationService.flatMap(…)` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation-deduplication.service.ts:90` |
|
|
140
|
+
| `ValidationFindingsService.buildUnmatchedResults` | 2 | `ValidationFindingsService.resolveTemplatesRootPath`, `ValidationFindingsService.map(…)` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation-findings.service.ts:68` |
|
|
141
|
+
| `ValidationScoringService.scoreInstances` | 2 | `ValidationScoringService.scoreInstance`, `ValidationScoringService.resolveScoreKey` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation-scoring.service.ts:111` |
|
|
142
|
+
| `RunnerService.filter(…)` | 1 | `RunnerService.claimsDocument` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/runner/runner.service.ts:85` |
|
|
143
|
+
| `RunnerService.map(…)` | 1 | `RunnerService.validateDocument` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/runner/runner.service.ts:88` |
|
|
144
|
+
| `ValidationDeduplicationService.selectOwners` | 1 | `ValidationDeduplicationService.compareInstances` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation-deduplication.service.ts:57` |
|
|
145
|
+
| `ValidationDeduplicationService.flatMap(…)` | 1 | `ValidationDeduplicationService.filter(…)` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation-deduplication.service.ts:94` |
|
|
146
|
+
| `ValidationDeduplicationService.filter(…)` | 1 | `ValidationDeduplicationService.resolveFindingKey` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation-deduplication.service.ts:95` |
|
|
147
|
+
| `ValidationFindingsService.resolveTemplatesRootPath` | 1 | `ValidationFindingsService.map(…)` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation-findings.service.ts:57` |
|
|
148
|
+
| `ValidationFindingsService.map(…)` | 1 | `ValidationFindingsService.describeReason` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation-findings.service.ts:74` |
|
|
149
|
+
| `ValidationScoringService.reduce(…)` | 1 | `ScoringService.sumWeights` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation-scoring.service.ts:75` |
|
|
150
|
+
| `ValidationService.readTemplateExtensions` | 1 | `ValidationService.flatMap(…)` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation.service.ts:50` |
|
|
151
|
+
| `ValidationService.flatMap(…)` | 1 | `ValidationService.map(…)` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation.service.ts:53` |
|
|
152
|
+
| `ValidationService.selectValidators` | 1 | `ValidationService.filter(…)` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation.service.ts:63` |
|
|
153
|
+
| `ValidationService.map(…)` | 1 | `RunnerService.runValidator` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation.service.ts:100` |
|
|
154
|
+
| `ValidationService.map(…)` | 1 | `ValidationService.validateInstance` | `packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation.service.ts:147` |
|
|
155
|
+
|
|
156
|
+
</details>
|
|
157
|
+
<!-- callidescope:end -->
|
|
158
|
+
|
|
159
|
+
## 🕸️ Codependix
|
|
160
|
+
|
|
161
|
+
Dependency graphs exported by [codependix](https://github.com/Organizzolini/codebase/tree/main/packages/ic-suite/codependix/codependix-cli), regenerated by `nx run codebase:codependix:write`.
|
|
162
|
+
|
|
163
|
+
### Nx Neighborhood
|
|
164
|
+
|
|
165
|
+
<!-- codependix:start name="codependix-nx-projects" -->
|
|
166
|
+
```mermaid
|
|
167
|
+
graph LR
|
|
168
|
+
conformetry_cli["conformetry-cli"]
|
|
169
|
+
conformetry_configuration["conformetry-configuration"]
|
|
170
|
+
conformetry_core["conformetry-core"]
|
|
171
|
+
conformetry_examples["conformetry-examples"]
|
|
172
|
+
conformetry_languages["conformetry-languages"]
|
|
173
|
+
conformetry_nx["conformetry-nx"]
|
|
174
|
+
conformetry_validation["conformetry-validation"]
|
|
175
|
+
conformetry_cli --> conformetry_validation
|
|
176
|
+
conformetry_examples --> conformetry_validation
|
|
177
|
+
conformetry_nx --> conformetry_validation
|
|
178
|
+
conformetry_validation --> conformetry_configuration
|
|
179
|
+
conformetry_validation --> conformetry_core
|
|
180
|
+
conformetry_validation --> conformetry_languages
|
|
181
|
+
classDef subject fill:#7c3aed,color:#fff,stroke:#4c1d95,stroke-width:2px
|
|
182
|
+
class conformetry_validation subject
|
|
183
|
+
```
|
|
184
|
+
<!-- codependix:end name="codependix-nx-projects" -->
|
|
185
|
+
|
|
186
|
+
### NestJS Module Graph
|
|
187
|
+
|
|
188
|
+
<!-- codependix:start name="codependix-nestjs-modules" -->
|
|
189
|
+
```mermaid
|
|
190
|
+
flowchart LR
|
|
191
|
+
ConfigurationModule
|
|
192
|
+
DifferencesModule
|
|
193
|
+
FilesModule
|
|
194
|
+
InputModule
|
|
195
|
+
InstanceDiscoveryModule
|
|
196
|
+
InstanceGroupModule
|
|
197
|
+
JsonModule
|
|
198
|
+
JupyterModule
|
|
199
|
+
LanguagesModule
|
|
200
|
+
MarkdownModule
|
|
201
|
+
PythonModule
|
|
202
|
+
RenderingModule
|
|
203
|
+
RunnerModule
|
|
204
|
+
ScoringModule
|
|
205
|
+
TemplateDiscoveryModule
|
|
206
|
+
TextModule
|
|
207
|
+
TypescriptModule
|
|
208
|
+
ValidationModule
|
|
209
|
+
ConfigurationModule --> InputModule
|
|
210
|
+
ConfigurationModule --> InstanceDiscoveryModule
|
|
211
|
+
ConfigurationModule --> InstanceGroupModule
|
|
212
|
+
ConfigurationModule --> RenderingModule
|
|
213
|
+
ConfigurationModule --> TemplateDiscoveryModule
|
|
214
|
+
FilesModule --> ConfigurationModule
|
|
215
|
+
FilesModule --> DifferencesModule
|
|
216
|
+
InstanceDiscoveryModule --> InstanceGroupModule
|
|
217
|
+
InstanceDiscoveryModule --> RenderingModule
|
|
218
|
+
InstanceDiscoveryModule --> TemplateDiscoveryModule
|
|
219
|
+
JsonModule --> ScoringModule
|
|
220
|
+
JupyterModule --> JsonModule
|
|
221
|
+
JupyterModule --> MarkdownModule
|
|
222
|
+
JupyterModule --> PythonModule
|
|
223
|
+
LanguagesModule --> JsonModule
|
|
224
|
+
LanguagesModule --> JupyterModule
|
|
225
|
+
LanguagesModule --> MarkdownModule
|
|
226
|
+
LanguagesModule --> PythonModule
|
|
227
|
+
LanguagesModule --> TextModule
|
|
228
|
+
LanguagesModule --> TypescriptModule
|
|
229
|
+
MarkdownModule --> ScoringModule
|
|
230
|
+
PythonModule --> DifferencesModule
|
|
231
|
+
PythonModule --> ScoringModule
|
|
232
|
+
TemplateDiscoveryModule --> RenderingModule
|
|
233
|
+
TypescriptModule --> ScoringModule
|
|
234
|
+
ValidationModule --> ConfigurationModule
|
|
235
|
+
ValidationModule --> FilesModule
|
|
236
|
+
ValidationModule --> LanguagesModule
|
|
237
|
+
ValidationModule --> RunnerModule
|
|
238
|
+
ValidationModule --> ScoringModule
|
|
239
|
+
```
|
|
240
|
+
<!-- codependix:end name="codependix-nestjs-modules" -->
|
|
241
|
+
|
|
242
|
+
### File Imports
|
|
243
|
+
|
|
244
|
+
<!-- codependix:start name="codependix-file-imports" -->
|
|
245
|
+
```mermaid
|
|
246
|
+
graph LR
|
|
247
|
+
file_callidescope_config_ts["callidescope.config.ts"]
|
|
248
|
+
file_codependix_config_ts["codependix.config.ts"]
|
|
249
|
+
file_codometer_config_ts["codometer.config.ts"]
|
|
250
|
+
file_eslint_config_ts["eslint.config.ts"]
|
|
251
|
+
file_src_index_ts["src/index.ts"]
|
|
252
|
+
file_src_modules_runner_runner_constants_ts["src/modules/runner/runner.constants.ts"]
|
|
253
|
+
file_src_modules_runner_runner_module_ts["src/modules/runner/runner.module.ts"]
|
|
254
|
+
file_src_modules_runner_runner_module_unit_test_ts["src/modules/runner/runner.module.unit.test.ts"]
|
|
255
|
+
file_src_modules_runner_runner_service_ts["src/modules/runner/runner.service.ts"]
|
|
256
|
+
file_src_modules_runner_runner_service_unit_test_ts["src/modules/runner/runner.service.unit.test.ts"]
|
|
257
|
+
file_src_modules_runner_runner_types_ts["src/modules/runner/runner.types.ts"]
|
|
258
|
+
file_src_modules_validation_validation_deduplication_service_ts["src/modules/validation/validation-deduplication.service.ts"]
|
|
259
|
+
file_src_modules_validation_validation_deduplication_service_unit_test_ts["src/modules/validation/validation-deduplication.service.unit.test.ts"]
|
|
260
|
+
file_src_modules_validation_validation_findings_service_ts["src/modules/validation/validation-findings.service.ts"]
|
|
261
|
+
file_src_modules_validation_validation_findings_service_unit_test_ts["src/modules/validation/validation-findings.service.unit.test.ts"]
|
|
262
|
+
file_src_modules_validation_validation_scoring_service_ts["src/modules/validation/validation-scoring.service.ts"]
|
|
263
|
+
file_src_modules_validation_validation_scoring_service_unit_test_ts["src/modules/validation/validation-scoring.service.unit.test.ts"]
|
|
264
|
+
file_src_modules_validation_validation_constants_ts["src/modules/validation/validation.constants.ts"]
|
|
265
|
+
file_src_modules_validation_validation_module_ts["src/modules/validation/validation.module.ts"]
|
|
266
|
+
file_src_modules_validation_validation_service_ts["src/modules/validation/validation.service.ts"]
|
|
267
|
+
file_src_modules_validation_validation_service_unit_test_ts["src/modules/validation/validation.service.unit.test.ts"]
|
|
268
|
+
file_src_modules_validation_validation_types_ts["src/modules/validation/validation.types.ts"]
|
|
269
|
+
file_testing_mocks_ts["testing/mocks.ts"]
|
|
270
|
+
file_testing_setup_ts["testing/setup.ts"]
|
|
271
|
+
file_vite_config_ts["vite.config.ts"]
|
|
272
|
+
file_vitest_config_ts["vitest.config.ts"]
|
|
273
|
+
file_src_modules_runner_runner_module_ts --> file_src_modules_runner_runner_service_ts
|
|
274
|
+
file_src_modules_runner_runner_module_unit_test_ts --> file_src_modules_runner_runner_module_ts
|
|
275
|
+
file_src_modules_runner_runner_module_unit_test_ts --> file_src_modules_runner_runner_service_ts
|
|
276
|
+
file_src_modules_runner_runner_service_ts --> file_src_modules_runner_runner_types_ts
|
|
277
|
+
file_src_modules_runner_runner_service_unit_test_ts --> file_src_modules_runner_runner_service_ts
|
|
278
|
+
file_src_modules_validation_validation_deduplication_service_ts --> file_src_modules_validation_validation_constants_ts
|
|
279
|
+
file_src_modules_validation_validation_deduplication_service_ts --> file_src_modules_validation_validation_types_ts
|
|
280
|
+
file_src_modules_validation_validation_deduplication_service_unit_test_ts --> file_src_modules_validation_validation_deduplication_service_ts
|
|
281
|
+
file_src_modules_validation_validation_deduplication_service_unit_test_ts --> file_src_modules_validation_validation_types_ts
|
|
282
|
+
file_src_modules_validation_validation_findings_service_unit_test_ts --> file_src_modules_validation_validation_findings_service_ts
|
|
283
|
+
file_src_modules_validation_validation_scoring_service_ts --> file_src_modules_validation_validation_constants_ts
|
|
284
|
+
file_src_modules_validation_validation_scoring_service_ts --> file_src_modules_validation_validation_types_ts
|
|
285
|
+
file_src_modules_validation_validation_scoring_service_unit_test_ts --> file_src_modules_validation_validation_scoring_service_ts
|
|
286
|
+
file_src_modules_validation_validation_module_ts --> file_src_modules_runner_runner_module_ts
|
|
287
|
+
file_src_modules_validation_validation_module_ts --> file_src_modules_validation_validation_deduplication_service_ts
|
|
288
|
+
file_src_modules_validation_validation_module_ts --> file_src_modules_validation_validation_findings_service_ts
|
|
289
|
+
file_src_modules_validation_validation_module_ts --> file_src_modules_validation_validation_scoring_service_ts
|
|
290
|
+
file_src_modules_validation_validation_module_ts --> file_src_modules_validation_validation_service_ts
|
|
291
|
+
file_src_modules_validation_validation_service_ts --> file_src_modules_runner_runner_service_ts
|
|
292
|
+
file_src_modules_validation_validation_service_ts --> file_src_modules_validation_validation_deduplication_service_ts
|
|
293
|
+
file_src_modules_validation_validation_service_ts --> file_src_modules_validation_validation_findings_service_ts
|
|
294
|
+
file_src_modules_validation_validation_service_ts --> file_src_modules_validation_validation_scoring_service_ts
|
|
295
|
+
file_src_modules_validation_validation_service_ts --> file_src_modules_validation_validation_types_ts
|
|
296
|
+
file_src_modules_validation_validation_service_unit_test_ts --> file_src_modules_validation_validation_module_ts
|
|
297
|
+
file_src_modules_validation_validation_service_unit_test_ts --> file_src_modules_validation_validation_service_ts
|
|
298
|
+
```
|
|
299
|
+
<!-- codependix:end name="codependix-file-imports" -->
|
|
300
|
+
|
|
301
|
+
<!-- codometer:start -->
|
|
302
|
+
|
|
303
|
+
## ⏲️ Codometer
|
|
304
|
+
|
|
305
|
+
### Project
|
|
306
|
+
|
|
307
|
+

|
|
308
|
+

|
|
309
|
+

|
|
310
|
+

|
|
311
|
+
|
|
312
|
+
### Measured Targets
|
|
313
|
+
|
|
314
|
+

|
|
315
|
+
|
|
316
|
+
### TypeScript
|
|
317
|
+
|
|
318
|
+

|
|
319
|
+

|
|
320
|
+

|
|
321
|
+

|
|
322
|
+

|
|
323
|
+

|
|
324
|
+

|
|
325
|
+
|
|
326
|
+
### JavaScript
|
|
327
|
+
|
|
328
|
+

|
|
329
|
+

|
|
330
|
+

|
|
331
|
+

|
|
332
|
+

|
|
333
|
+

|
|
334
|
+

|
|
335
|
+

|
|
336
|
+

|
|
337
|
+

|
|
338
|
+

|
|
339
|
+

|
|
340
|
+

|
|
341
|
+

|
|
342
|
+
|
|
343
|
+
### Python
|
|
344
|
+
|
|
345
|
+

|
|
346
|
+

|
|
347
|
+

|
|
348
|
+

|
|
349
|
+

|
|
350
|
+

|
|
351
|
+

|
|
352
|
+

|
|
353
|
+

|
|
354
|
+

|
|
355
|
+

|
|
356
|
+

|
|
357
|
+
|
|
358
|
+
### JSON
|
|
359
|
+
|
|
360
|
+

|
|
361
|
+

|
|
362
|
+

|
|
363
|
+

|
|
364
|
+

|
|
365
|
+

|
|
366
|
+

|
|
367
|
+

|
|
368
|
+

|
|
369
|
+

|
|
370
|
+

|
|
371
|
+

|
|
372
|
+
|
|
373
|
+
### YAML
|
|
374
|
+
|
|
375
|
+

|
|
376
|
+

|
|
377
|
+

|
|
378
|
+

|
|
379
|
+

|
|
380
|
+

|
|
381
|
+

|
|
382
|
+

|
|
383
|
+

|
|
384
|
+

|
|
385
|
+

|
|
386
|
+
|
|
387
|
+
### TOML
|
|
388
|
+
|
|
389
|
+

|
|
390
|
+

|
|
391
|
+

|
|
392
|
+

|
|
393
|
+

|
|
394
|
+

|
|
395
|
+

|
|
396
|
+
|
|
397
|
+
### Shell
|
|
398
|
+
|
|
399
|
+

|
|
400
|
+

|
|
401
|
+

|
|
402
|
+

|
|
403
|
+

|
|
404
|
+

|
|
405
|
+

|
|
406
|
+

|
|
407
|
+

|
|
408
|
+

|
|
409
|
+

|
|
410
|
+
|
|
411
|
+
### SQL
|
|
412
|
+
|
|
413
|
+

|
|
414
|
+

|
|
415
|
+

|
|
416
|
+

|
|
417
|
+

|
|
418
|
+

|
|
419
|
+

|
|
420
|
+

|
|
421
|
+

|
|
422
|
+

|
|
423
|
+

|
|
424
|
+
|
|
425
|
+
### HCL
|
|
426
|
+
|
|
427
|
+

|
|
428
|
+

|
|
429
|
+

|
|
430
|
+

|
|
431
|
+

|
|
432
|
+

|
|
433
|
+

|
|
434
|
+

|
|
435
|
+

|
|
436
|
+
|
|
437
|
+
### CSS
|
|
438
|
+
|
|
439
|
+

|
|
440
|
+

|
|
441
|
+

|
|
442
|
+

|
|
443
|
+

|
|
444
|
+

|
|
445
|
+

|
|
446
|
+

|
|
447
|
+

|
|
448
|
+
|
|
449
|
+
### Conventions
|
|
450
|
+
|
|
451
|
+

|
|
452
|
+

|
|
453
|
+

|
|
454
|
+

|
|
455
|
+

|
|
456
|
+

|
|
457
|
+

|
|
458
|
+

|
|
459
|
+

|
|
460
|
+

|
|
461
|
+

|
|
462
|
+

|
|
463
|
+

|
|
464
|
+

|
|
465
|
+

|
|
466
|
+

|
|
467
|
+

|
|
468
|
+

|
|
469
|
+
|
|
470
|
+
### Jupyter
|
|
471
|
+
|
|
472
|
+

|
|
473
|
+

|
|
474
|
+

|
|
475
|
+

|
|
476
|
+

|
|
477
|
+

|
|
478
|
+

|
|
479
|
+

|
|
480
|
+

|
|
481
|
+

|
|
482
|
+

|
|
483
|
+

|
|
484
|
+

|
|
485
|
+

|
|
486
|
+

|
|
487
|
+

|
|
488
|
+

|
|
489
|
+

|
|
490
|
+

|
|
491
|
+

|
|
492
|
+
|
|
493
|
+
### Markdown
|
|
494
|
+
|
|
495
|
+

|
|
496
|
+

|
|
497
|
+

|
|
498
|
+

|
|
499
|
+

|
|
500
|
+

|
|
501
|
+

|
|
502
|
+

|
|
503
|
+

|
|
504
|
+

|
|
505
|
+

|
|
506
|
+

|
|
507
|
+

|
|
508
|
+

|
|
509
|
+

|
|
510
|
+

|
|
511
|
+

|
|
512
|
+

|
|
513
|
+

|
|
514
|
+

|
|
515
|
+
<!-- codometer:end -->
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { ConfigurationService } from '@conformetry/configuration';
|
|
2
|
+
import { ConformetryLanguageValidator } from '@conformetry/core';
|
|
3
|
+
import { FilesService } from '@conformetry/languages';
|
|
4
|
+
import { Instance } from '@conformetry/configuration';
|
|
5
|
+
import { InstanceScore } from '@conformetry/core';
|
|
6
|
+
import { LanguagesService } from '@conformetry/languages';
|
|
7
|
+
import { LanguageValidatorResult } from '@conformetry/core';
|
|
8
|
+
import { MatchedInstance } from '@conformetry/configuration';
|
|
9
|
+
import { PreparedValidationDocument } from '@conformetry/core';
|
|
10
|
+
import { ScoringService } from '@conformetry/languages';
|
|
11
|
+
import { TemplateDefinition } from '@conformetry/configuration';
|
|
12
|
+
import { UnmatchedInstance } from '@conformetry/configuration';
|
|
13
|
+
import { ValidationFileResult } from '@conformetry/core';
|
|
14
|
+
|
|
15
|
+
/** Every finding one matched instance produced, kept with the instance. */
|
|
16
|
+
export declare interface InstanceFileResults {
|
|
17
|
+
readonly fileResults: ValidationFileResult[];
|
|
18
|
+
readonly instance: MatchedInstance;
|
|
19
|
+
/** Combined weight of everything this instance's template asked for. */
|
|
20
|
+
readonly totalWeight: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Arguments for running one language validator over a prepared document set. */
|
|
24
|
+
export declare interface RunLanguageValidatorArguments {
|
|
25
|
+
readonly checkedPaths: string[];
|
|
26
|
+
readonly documents: PreparedValidationDocument[];
|
|
27
|
+
readonly validator: ConformetryLanguageValidator;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Owns the shared envelope for running a language validator.
|
|
32
|
+
*
|
|
33
|
+
* Imported by `conformetry-validation`, the one consumer that drives the
|
|
34
|
+
* Languages. The Languages themselves implement the contract in
|
|
35
|
+
* `runner.types.ts` without importing this module — including the Jupyter
|
|
36
|
+
* Language, which composes its siblings directly rather than through the
|
|
37
|
+
* runner.
|
|
38
|
+
*/
|
|
39
|
+
export declare class RunnerModule {
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Runs a language validator over a prepared document set.
|
|
44
|
+
*
|
|
45
|
+
* This is the shared envelope every language package used to reimplement:
|
|
46
|
+
* select the documents this validator claims, compare each one, group the
|
|
47
|
+
* differences under their file, and assemble the result. Centralizing it means a
|
|
48
|
+
* language package contains only its comparison logic, and that every
|
|
49
|
+
* validator reports its outcome identically.
|
|
50
|
+
*/
|
|
51
|
+
export declare class RunnerService {
|
|
52
|
+
constructor();
|
|
53
|
+
/**
|
|
54
|
+
* Returns whether a validator claims a document, by matching the instance
|
|
55
|
+
* file's extension against the validator descriptor.
|
|
56
|
+
*/
|
|
57
|
+
private claimsDocument;
|
|
58
|
+
/** Compares one document and keeps its findings with its requirement size. */
|
|
59
|
+
private validateDocument;
|
|
60
|
+
/**
|
|
61
|
+
* Selects the documents a validator claims and returns its aggregated
|
|
62
|
+
* result.
|
|
63
|
+
*
|
|
64
|
+
* Documents the validator does not claim are skipped silently — several
|
|
65
|
+
* validators run over the same document set and each takes only its own
|
|
66
|
+
* extensions.
|
|
67
|
+
*
|
|
68
|
+
* Every claimed document contributes its weight, but only the failing ones
|
|
69
|
+
* are kept as file results. Reports should list faults, not files; scores
|
|
70
|
+
* need the whole denominator. Dropping clean documents before totalling
|
|
71
|
+
* would score an instance against only the parts of itself that are wrong,
|
|
72
|
+
* which reads as near-zero for an instance with one bad file among twenty.
|
|
73
|
+
*/
|
|
74
|
+
runValidator(args: RunLanguageValidatorArguments): LanguageValidatorResult;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Arguments for one validation run. */
|
|
78
|
+
export declare interface RunValidationArguments {
|
|
79
|
+
/**
|
|
80
|
+
* The directories and files to validate. Callers expand their own globs —
|
|
81
|
+
* an Nx plugin filters by project tags, the CLI reads the config — so this
|
|
82
|
+
* package never needs to know what a workspace is.
|
|
83
|
+
*/
|
|
84
|
+
readonly instances: Instance[];
|
|
85
|
+
/**
|
|
86
|
+
* Language names (`typescript`, `json`, …) to restrict the run to. Every
|
|
87
|
+
* language runs when this is absent or empty.
|
|
88
|
+
*/
|
|
89
|
+
readonly languageNames?: string[];
|
|
90
|
+
/**
|
|
91
|
+
* The templates instances are matched against. Supplied rather than read
|
|
92
|
+
* from a root directory, because a template's location is a property of the
|
|
93
|
+
* generator that owns it.
|
|
94
|
+
*/
|
|
95
|
+
readonly templates: TemplateDefinition[];
|
|
96
|
+
/**
|
|
97
|
+
* Lowest score any instance may have, unless its template or its instance
|
|
98
|
+
* group says otherwise. The weakest of the three levels.
|
|
99
|
+
*/
|
|
100
|
+
readonly threshold?: number;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** The outcome of one validation run. */
|
|
104
|
+
export declare interface RunValidationResult {
|
|
105
|
+
/** Every directory that was compared against a template. */
|
|
106
|
+
readonly checkedPaths: string[];
|
|
107
|
+
readonly fileResults: ValidationFileResult[];
|
|
108
|
+
readonly ok: boolean;
|
|
109
|
+
/** One score per matched instance, in the order they were matched. */
|
|
110
|
+
readonly scores: InstanceScore[];
|
|
111
|
+
/**
|
|
112
|
+
* Instances that matched no template, or matched two equally well. These
|
|
113
|
+
* are findings in their own right: a glob is the caller asserting the path
|
|
114
|
+
* is an instance, so matching nothing means the instance has drifted or the
|
|
115
|
+
* glob is wrong.
|
|
116
|
+
*/
|
|
117
|
+
readonly unmatched: UnmatchedInstance[];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Arguments for scoring one matched instance. */
|
|
121
|
+
export declare interface ScoreInstanceArguments {
|
|
122
|
+
readonly fileResults: ValidationFileResult[];
|
|
123
|
+
readonly instance: MatchedInstance;
|
|
124
|
+
/** Run-level threshold, from a `--threshold` flag. The weakest level. */
|
|
125
|
+
readonly runThreshold?: number | undefined;
|
|
126
|
+
readonly totalWeight: number;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** Arguments for scoring every matched instance of a run. */
|
|
130
|
+
export declare interface ScoreInstancesArguments {
|
|
131
|
+
readonly groups: InstanceFileResults[];
|
|
132
|
+
/** Run-level threshold, from a `--threshold` flag. The weakest level. */
|
|
133
|
+
readonly runThreshold?: number | undefined;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Collapses the findings of overlapping instances into one report.
|
|
138
|
+
*
|
|
139
|
+
* One file is usually covered by several instances — `logger.service.ts` is
|
|
140
|
+
* reached by the project glob, the module glob, and the service-file glob —
|
|
141
|
+
* and each of those matches a different template. Reporting all three would
|
|
142
|
+
* print the same defect three times, phrased against templates of wildly
|
|
143
|
+
* different size.
|
|
144
|
+
*/
|
|
145
|
+
export declare class ValidationDeduplicationService {
|
|
146
|
+
constructor();
|
|
147
|
+
/**
|
|
148
|
+
* Orders two instances by template size, then template name.
|
|
149
|
+
*
|
|
150
|
+
* Smallest wins, because the smallest template that still explains the file
|
|
151
|
+
* is the narrowest thing the reader has to fix: `nestjs-service-file` says
|
|
152
|
+
* "this service file is wrong", `nestjs-service-project` says "this project
|
|
153
|
+
* of eighteen files is wrong" about the same line.
|
|
154
|
+
*/
|
|
155
|
+
private compareInstances;
|
|
156
|
+
/** Keys a finding by the instance and template file pair it came from. */
|
|
157
|
+
private resolveFindingKey;
|
|
158
|
+
/** Picks, for each instance file, the group whose template is smallest. */
|
|
159
|
+
private selectOwners;
|
|
160
|
+
/**
|
|
161
|
+
* Returns one finding per instance file, taken from the smallest template
|
|
162
|
+
* that reported it, with duplicate instance/template pairs collapsed.
|
|
163
|
+
*
|
|
164
|
+
* Known property, not a bug: a file is reported against exactly one
|
|
165
|
+
* template, so a requirement unique to a larger template goes unreported for
|
|
166
|
+
* files a smaller template also covers. That is acceptable while the
|
|
167
|
+
* overlapping templates share their file contents, and is the price of not
|
|
168
|
+
* printing the same defect three times.
|
|
169
|
+
*/
|
|
170
|
+
deduplicate(groups: InstanceFileResults[]): ValidationFileResult[];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Turns instances that matched no template into ordinary findings.
|
|
175
|
+
*
|
|
176
|
+
* Silence would be the wrong answer here. A glob is the author asserting that
|
|
177
|
+
* a path holds generated code, so a path matching nothing means either the
|
|
178
|
+
* instance drifted past recognition or the glob is wrong — both worth saying
|
|
179
|
+
* out loud, and both invisible if unmatched instances were merely skipped.
|
|
180
|
+
*/
|
|
181
|
+
export declare class ValidationFindingsService {
|
|
182
|
+
constructor();
|
|
183
|
+
/** Describes why an instance could not be attributed to one template. */
|
|
184
|
+
private describeReason;
|
|
185
|
+
/**
|
|
186
|
+
* The directory the templates share, used as the "template" line of an
|
|
187
|
+
* unmatched finding — there is no single template to point at, and the set
|
|
188
|
+
* they were drawn from is the most useful thing to name.
|
|
189
|
+
*/
|
|
190
|
+
private resolveTemplatesRootPath;
|
|
191
|
+
/** Builds one finding per unmatched instance, in instance order. */
|
|
192
|
+
buildUnmatchedResults(args: {
|
|
193
|
+
templates: TemplateDefinition[];
|
|
194
|
+
unmatched: UnmatchedInstance[];
|
|
195
|
+
}): ValidationFileResult[];
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Orchestrates a validation run across the languages it resolves.
|
|
200
|
+
*
|
|
201
|
+
* `LanguagesModule` is imported rather than the languages being handed in:
|
|
202
|
+
* every run needs the Fallback, so there was never a run that carried fewer
|
|
203
|
+
* than all of them.
|
|
204
|
+
*/
|
|
205
|
+
export declare class ValidationModule {
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Scores each matched instance and decides whether it clears its threshold.
|
|
210
|
+
*
|
|
211
|
+
* Scoring is deliberately separate from the report. Deduplication picks which
|
|
212
|
+
* template gets to *print* a shared file's finding, but a score answers a
|
|
213
|
+
* different question — how much of this instance's own template it honours —
|
|
214
|
+
* so it is taken from what validation found before any of that is collapsed.
|
|
215
|
+
*/
|
|
216
|
+
export declare class ValidationScoringService {
|
|
217
|
+
private readonly scoringService;
|
|
218
|
+
constructor(scoringService: ScoringService);
|
|
219
|
+
/**
|
|
220
|
+
* The instance's own directory.
|
|
221
|
+
*
|
|
222
|
+
* `Instance.path` is the directory the template's tree is laid *over* — the
|
|
223
|
+
* parent — so every module in a project shares it. Joining the name stem is
|
|
224
|
+
* what tells `aspects` from `ephemeris`, and without it every module of a
|
|
225
|
+
* project collapses onto one score.
|
|
226
|
+
*/
|
|
227
|
+
private resolveInstancePath;
|
|
228
|
+
/** Keys a score by the instance and template it describes. */
|
|
229
|
+
private resolveScoreKey;
|
|
230
|
+
/**
|
|
231
|
+
* Resolves which threshold applies, narrowest level first.
|
|
232
|
+
*
|
|
233
|
+
* An instance group is more specific than the generator that owns it, and
|
|
234
|
+
* the generator is more specific than a flag covering the whole run. The
|
|
235
|
+
* built-in default applies only when nothing else has an opinion, which is
|
|
236
|
+
* why no earlier level may be pre-filled with it.
|
|
237
|
+
*/
|
|
238
|
+
resolveThreshold(args: ScoreInstanceArguments): number;
|
|
239
|
+
/** Scores one matched instance against the threshold that applies to it. */
|
|
240
|
+
scoreInstance(args: ScoreInstanceArguments): InstanceScore;
|
|
241
|
+
/**
|
|
242
|
+
* Scores every matched instance, reporting each instance and template pair
|
|
243
|
+
* once.
|
|
244
|
+
*
|
|
245
|
+
* The same directory is matched repeatedly when several generators declare
|
|
246
|
+
* overlapping globs — `src/modules/*` belongs to more than one template — so
|
|
247
|
+
* without this the summary prints the same score several times over. A
|
|
248
|
+
* genuine tie against two *different* templates is kept: those are two real
|
|
249
|
+
* requirements the instance answers to.
|
|
250
|
+
*
|
|
251
|
+
* When two groups claim the same instance with different thresholds, the
|
|
252
|
+
* strictest wins. Nothing makes one group more specific than another, so
|
|
253
|
+
* order would otherwise decide it; letting the strictest win at least means
|
|
254
|
+
* adding a lenient group can never silently relax a bar someone else set.
|
|
255
|
+
*/
|
|
256
|
+
scoreInstances(args: ScoreInstancesArguments): InstanceScore[];
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Runs a full conformetry validation: match instances to templates, check the
|
|
261
|
+
* files exist, then compare contents language by language.
|
|
262
|
+
*
|
|
263
|
+
* The instances arrive from the caller. This package used to scan the
|
|
264
|
+
* workspace for `project.json` files and infer scope from generator name
|
|
265
|
+
* suffixes, which made a generic package depend on one repository's layout.
|
|
266
|
+
*/
|
|
267
|
+
export declare class ValidationService {
|
|
268
|
+
private readonly configurationService;
|
|
269
|
+
private readonly filesService;
|
|
270
|
+
private readonly languagesService;
|
|
271
|
+
private readonly runnerService;
|
|
272
|
+
private readonly validationDeduplicationService;
|
|
273
|
+
private readonly validationFindingsService;
|
|
274
|
+
private readonly validationScoringService;
|
|
275
|
+
constructor(configurationService: ConfigurationService, filesService: FilesService, languagesService: LanguagesService, runnerService: RunnerService, validationDeduplicationService: ValidationDeduplicationService, validationFindingsService: ValidationFindingsService, validationScoringService: ValidationScoringService);
|
|
276
|
+
/** Every distinct file extension the matched templates declare. */
|
|
277
|
+
private readTemplateExtensions;
|
|
278
|
+
/** Narrows the resolved validators to the names the caller asked for. */
|
|
279
|
+
private selectValidators;
|
|
280
|
+
/**
|
|
281
|
+
* Checks one instance's files exist, then compares the documents whose
|
|
282
|
+
* extensions the selected validators claim.
|
|
283
|
+
*
|
|
284
|
+
* File existence comes first because a missing file cannot be compared, and
|
|
285
|
+
* reporting it once is clearer than every language reporting it in turn.
|
|
286
|
+
*/
|
|
287
|
+
private validateInstance;
|
|
288
|
+
/**
|
|
289
|
+
* Validates every instance and returns the differences found.
|
|
290
|
+
*
|
|
291
|
+
* Instances that matched no template are reported alongside the content
|
|
292
|
+
* differences rather than skipped, so one report covers both "this file is
|
|
293
|
+
* wrong" and "conformetry cannot tell what this path was generated from".
|
|
294
|
+
*
|
|
295
|
+
* Synchronous, because resolving the languages was the only step that ever
|
|
296
|
+
* waited on anything: they were imported on demand, and now they are
|
|
297
|
+
* injected.
|
|
298
|
+
*/
|
|
299
|
+
validate(args: RunValidationArguments): RunValidationResult;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export { }
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { Injectable as e, Module as t } from "@nestjs/common";
|
|
2
|
+
import n from "node:path";
|
|
3
|
+
import { FilesModule as r, FilesService as i, LanguagesModule as a, LanguagesService as o, ScoringModule as s, ScoringService as c } from "@conformetry/languages";
|
|
4
|
+
import { ConfigurationModule as l, ConfigurationService as u } from "@conformetry/configuration";
|
|
5
|
+
//#region \0@oxc-project+runtime@0.151.0/helpers/esm/decorateMetadata.js
|
|
6
|
+
function d(e, t) {
|
|
7
|
+
if (typeof Reflect == "object" && typeof Reflect.metadata == "function") return Reflect.metadata(e, t);
|
|
8
|
+
}
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region \0@oxc-project+runtime@0.151.0/helpers/esm/decorate.js
|
|
11
|
+
function f(e, t, n, r) {
|
|
12
|
+
var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
|
|
13
|
+
if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
|
|
14
|
+
else for (var s = e.length - 1; s >= 0; s--) (o = e[s]) && (a = (i < 3 ? o(a) : i > 3 ? o(t, n, a) : o(t, n)) || a);
|
|
15
|
+
return i > 3 && a && Object.defineProperty(t, n, a), a;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region packages/ic-suite/conformetry/conformetry-validation/src/modules/runner/runner.service.ts
|
|
19
|
+
var p = class {
|
|
20
|
+
constructor() {}
|
|
21
|
+
claimsDocument(e) {
|
|
22
|
+
let t = n.extname(e.document.filename);
|
|
23
|
+
return e.validator.descriptor.fileExtensions.includes(t);
|
|
24
|
+
}
|
|
25
|
+
validateDocument(e) {
|
|
26
|
+
let { differences: t, totalWeight: n } = e.validator.validateDocument(e.document);
|
|
27
|
+
return {
|
|
28
|
+
differences: t,
|
|
29
|
+
filename: e.document.filename,
|
|
30
|
+
instanceFilePath: e.document.instanceFilePath,
|
|
31
|
+
templateFilePath: e.document.templateFilePath,
|
|
32
|
+
totalWeight: n
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
runValidator(e) {
|
|
36
|
+
let t = e.documents.filter((t) => this.claimsDocument({
|
|
37
|
+
document: t,
|
|
38
|
+
validator: e.validator
|
|
39
|
+
})).map((t) => this.validateDocument({
|
|
40
|
+
document: t,
|
|
41
|
+
validator: e.validator
|
|
42
|
+
})), n = t.filter((e) => e.differences.length > 0);
|
|
43
|
+
return {
|
|
44
|
+
checkedPaths: e.checkedPaths,
|
|
45
|
+
fileResults: n,
|
|
46
|
+
languageName: e.validator.descriptor.name,
|
|
47
|
+
ok: n.length === 0,
|
|
48
|
+
totalWeight: t.reduce((e, t) => e + t.totalWeight, 0)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
p = f([e(), d("design:paramtypes", [])], p);
|
|
53
|
+
//#endregion
|
|
54
|
+
//#region packages/ic-suite/conformetry/conformetry-validation/src/modules/runner/runner.module.ts
|
|
55
|
+
var m = class {};
|
|
56
|
+
m = f([t({
|
|
57
|
+
controllers: [],
|
|
58
|
+
exports: [p],
|
|
59
|
+
imports: [],
|
|
60
|
+
providers: [p]
|
|
61
|
+
})], m);
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation-deduplication.service.ts
|
|
64
|
+
var h = class {
|
|
65
|
+
constructor() {}
|
|
66
|
+
compareInstances(e, t) {
|
|
67
|
+
return e.template.filePaths.length === t.template.filePaths.length ? e.template.name.localeCompare(t.template.name) : e.template.filePaths.length - t.template.filePaths.length;
|
|
68
|
+
}
|
|
69
|
+
resolveFindingKey(e) {
|
|
70
|
+
return [e.instanceFilePath, e.templateFilePath].join("\0");
|
|
71
|
+
}
|
|
72
|
+
selectOwners(e) {
|
|
73
|
+
let t = /* @__PURE__ */ new Map();
|
|
74
|
+
for (let n of e) for (let e of n.fileResults) {
|
|
75
|
+
let r = t.get(e.instanceFilePath);
|
|
76
|
+
(r === void 0 || this.compareInstances(n.instance, r) < 0) && t.set(e.instanceFilePath, n.instance);
|
|
77
|
+
}
|
|
78
|
+
return t;
|
|
79
|
+
}
|
|
80
|
+
deduplicate(e) {
|
|
81
|
+
let t = this.selectOwners(e), n = /* @__PURE__ */ new Set();
|
|
82
|
+
return e.flatMap((e) => e.fileResults.filter((r) => {
|
|
83
|
+
if (t.get(r.instanceFilePath) !== e.instance) return !1;
|
|
84
|
+
let i = this.resolveFindingKey(r);
|
|
85
|
+
return !n.has(i) && (n.add(i), !0);
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
h = f([e(), d("design:paramtypes", [])], h);
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation-findings.service.ts
|
|
92
|
+
var g = class {
|
|
93
|
+
constructor() {}
|
|
94
|
+
describeReason(e) {
|
|
95
|
+
if (e.reason === "ambiguous") {
|
|
96
|
+
let t = e.tiedTemplateNames.join(", ");
|
|
97
|
+
return {
|
|
98
|
+
fix: `Give the templates ${t} distinguishing files, or narrow the instance glob so only one applies.`,
|
|
99
|
+
message: `Ambiguous instance: matches ${t} equally well`
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
fix: "Regenerate the instance from its template, or remove it from the instance globs if it is not generated code.",
|
|
104
|
+
message: "Unmatched instance: no template explains this path"
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
resolveTemplatesRootPath(e) {
|
|
108
|
+
return e.map((e) => n.dirname(e.directoryPath)).toSorted()[0] ?? "";
|
|
109
|
+
}
|
|
110
|
+
buildUnmatchedResults(e) {
|
|
111
|
+
let t = this.resolveTemplatesRootPath(e.templates);
|
|
112
|
+
return e.unmatched.map((e) => {
|
|
113
|
+
let r = n.join(e.instance.path, e.instance.nameStem);
|
|
114
|
+
return {
|
|
115
|
+
differences: [{
|
|
116
|
+
differenceType: "instance",
|
|
117
|
+
...this.describeReason({
|
|
118
|
+
reason: e.reason,
|
|
119
|
+
tiedTemplateNames: e.tiedTemplateNames
|
|
120
|
+
})
|
|
121
|
+
}],
|
|
122
|
+
filename: e.instance.nameStem,
|
|
123
|
+
instanceFilePath: r,
|
|
124
|
+
templateFilePath: t,
|
|
125
|
+
totalWeight: 0
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
g = f([e(), d("design:paramtypes", [])], g);
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation-scoring.service.ts
|
|
133
|
+
var _ = class {
|
|
134
|
+
scoringService;
|
|
135
|
+
constructor(e) {
|
|
136
|
+
this.scoringService = e;
|
|
137
|
+
}
|
|
138
|
+
resolveInstancePath(e) {
|
|
139
|
+
return n.join(e.instance.path, e.instance.nameStem);
|
|
140
|
+
}
|
|
141
|
+
resolveScoreKey(e) {
|
|
142
|
+
return [e.instancePath, e.templateName].join("\0");
|
|
143
|
+
}
|
|
144
|
+
resolveThreshold(e) {
|
|
145
|
+
return e.instance.instance.threshold ?? e.instance.template.threshold ?? e.runThreshold ?? 1;
|
|
146
|
+
}
|
|
147
|
+
scoreInstance(e) {
|
|
148
|
+
let t = e.fileResults.reduce((e, t) => e + this.scoringService.sumWeights(t.differences), 0), n = e.totalWeight, r = this.scoringService.calculateScore({
|
|
149
|
+
failedWeight: t,
|
|
150
|
+
totalWeight: n
|
|
151
|
+
}), i = this.resolveThreshold(e);
|
|
152
|
+
return {
|
|
153
|
+
failedWeight: t,
|
|
154
|
+
instancePath: this.resolveInstancePath(e.instance),
|
|
155
|
+
ok: r >= i,
|
|
156
|
+
score: r,
|
|
157
|
+
templateName: e.instance.template.name,
|
|
158
|
+
threshold: i,
|
|
159
|
+
totalWeight: n
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
scoreInstances(e) {
|
|
163
|
+
let t = /* @__PURE__ */ new Map();
|
|
164
|
+
for (let n of e.groups) {
|
|
165
|
+
let r = this.scoreInstance({
|
|
166
|
+
fileResults: n.fileResults,
|
|
167
|
+
instance: n.instance,
|
|
168
|
+
runThreshold: e.runThreshold,
|
|
169
|
+
totalWeight: n.totalWeight
|
|
170
|
+
}), i = this.resolveScoreKey(r), a = t.get(i);
|
|
171
|
+
(a === void 0 || r.threshold > a.threshold) && t.set(i, r);
|
|
172
|
+
}
|
|
173
|
+
return [...t.values()];
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
_ = f([e(), d("design:paramtypes", [c === void 0 ? Object : c])], _);
|
|
177
|
+
//#endregion
|
|
178
|
+
//#region packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation.service.ts
|
|
179
|
+
var v = class {
|
|
180
|
+
configurationService;
|
|
181
|
+
filesService;
|
|
182
|
+
languagesService;
|
|
183
|
+
runnerService;
|
|
184
|
+
validationDeduplicationService;
|
|
185
|
+
validationFindingsService;
|
|
186
|
+
validationScoringService;
|
|
187
|
+
constructor(e, t, n, r, i, a, o) {
|
|
188
|
+
this.configurationService = e, this.filesService = t, this.languagesService = n, this.runnerService = r, this.validationDeduplicationService = i, this.validationFindingsService = a, this.validationScoringService = o;
|
|
189
|
+
}
|
|
190
|
+
readTemplateExtensions(e) {
|
|
191
|
+
return [...new Set(e.flatMap((e) => e.template.filePaths.map((e) => n.extname(e))))];
|
|
192
|
+
}
|
|
193
|
+
selectValidators(e) {
|
|
194
|
+
let { languageNames: t } = e;
|
|
195
|
+
return t === void 0 || t.length === 0 ? e.validators : e.validators.filter((e) => t.includes(e.descriptor.name));
|
|
196
|
+
}
|
|
197
|
+
validateInstance(e) {
|
|
198
|
+
let [t] = this.configurationService.prepareDocuments({
|
|
199
|
+
fileExtensions: e.validators.flatMap((e) => [...e.descriptor.fileExtensions]),
|
|
200
|
+
instances: [e.instance]
|
|
201
|
+
}), n = this.filesService.checkInstanceFiles({ instances: [e.instance] }), r = e.validators.map((n) => this.runnerService.runValidator({
|
|
202
|
+
checkedPaths: [e.instance.instance.path],
|
|
203
|
+
documents: t?.documents ?? [],
|
|
204
|
+
validator: n
|
|
205
|
+
}));
|
|
206
|
+
return {
|
|
207
|
+
fileResults: [...n.fileResults, ...r.flatMap((e) => e.fileResults)],
|
|
208
|
+
instance: e.instance,
|
|
209
|
+
totalWeight: r.reduce((e, t) => e + t.totalWeight, n.totalWeight)
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
validate(e) {
|
|
213
|
+
let { matched: t, unmatched: n } = this.configurationService.matchInstances({
|
|
214
|
+
instances: e.instances,
|
|
215
|
+
templates: e.templates
|
|
216
|
+
}), r = this.selectValidators({
|
|
217
|
+
languageNames: e.languageNames,
|
|
218
|
+
validators: this.languagesService.resolveValidators({ extensions: this.readTemplateExtensions(t) })
|
|
219
|
+
}), i = t.map((e) => this.validateInstance({
|
|
220
|
+
instance: e,
|
|
221
|
+
validators: r
|
|
222
|
+
})), a = this.validationScoringService.scoreInstances({
|
|
223
|
+
groups: i,
|
|
224
|
+
runThreshold: e.threshold
|
|
225
|
+
}), o = [...this.validationDeduplicationService.deduplicate(i), ...this.validationFindingsService.buildUnmatchedResults({
|
|
226
|
+
templates: e.templates,
|
|
227
|
+
unmatched: n
|
|
228
|
+
})];
|
|
229
|
+
return {
|
|
230
|
+
checkedPaths: t.map((e) => e.instance.path),
|
|
231
|
+
fileResults: o,
|
|
232
|
+
ok: n.length === 0 && a.every((e) => e.ok),
|
|
233
|
+
scores: a,
|
|
234
|
+
unmatched: n
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
v = f([e(), d("design:paramtypes", [
|
|
239
|
+
u === void 0 ? Object : u,
|
|
240
|
+
i === void 0 ? Object : i,
|
|
241
|
+
o === void 0 ? Object : o,
|
|
242
|
+
p === void 0 ? Object : p,
|
|
243
|
+
h === void 0 ? Object : h,
|
|
244
|
+
g === void 0 ? Object : g,
|
|
245
|
+
_ === void 0 ? Object : _
|
|
246
|
+
])], v);
|
|
247
|
+
//#endregion
|
|
248
|
+
//#region packages/ic-suite/conformetry/conformetry-validation/src/modules/validation/validation.module.ts
|
|
249
|
+
var y = class {};
|
|
250
|
+
y = f([t({
|
|
251
|
+
controllers: [],
|
|
252
|
+
exports: [
|
|
253
|
+
l,
|
|
254
|
+
r,
|
|
255
|
+
a,
|
|
256
|
+
m,
|
|
257
|
+
s,
|
|
258
|
+
h,
|
|
259
|
+
g,
|
|
260
|
+
_,
|
|
261
|
+
v
|
|
262
|
+
],
|
|
263
|
+
imports: [
|
|
264
|
+
l,
|
|
265
|
+
r,
|
|
266
|
+
a,
|
|
267
|
+
m,
|
|
268
|
+
s
|
|
269
|
+
],
|
|
270
|
+
providers: [
|
|
271
|
+
h,
|
|
272
|
+
g,
|
|
273
|
+
_,
|
|
274
|
+
v
|
|
275
|
+
]
|
|
276
|
+
})], y);
|
|
277
|
+
//#endregion
|
|
278
|
+
export { m as RunnerModule, p as RunnerService, h as ValidationDeduplicationService, g as ValidationFindingsService, y as ValidationModule, _ as ValidationScoringService, v as ValidationService };
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": "Jimmy Paolini",
|
|
3
|
+
"bugs": {
|
|
4
|
+
"url": "https://github.com/Organizzolini/codebase/issues"
|
|
5
|
+
},
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@conformetry/configuration": "0.0.1",
|
|
8
|
+
"@conformetry/core": "0.0.1",
|
|
9
|
+
"@conformetry/languages": "0.0.1",
|
|
10
|
+
"@nestjs/common": "^11.1.21 || ^12.0.1",
|
|
11
|
+
"reflect-metadata": "^0.2.2"
|
|
12
|
+
},
|
|
13
|
+
"description": "Template matching, existence verification, and conformance validation orchestrator for Conformetry",
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@golevelup/ts-vitest": "^4.0.0",
|
|
16
|
+
"@nestjs/testing": "^12.0.1",
|
|
17
|
+
"@nx/eslint-plugin": "^23.0.0",
|
|
18
|
+
"@swc/helpers": "^0.5.21",
|
|
19
|
+
"@types/node": "^26.5.1",
|
|
20
|
+
"@vitest/coverage-v8": "^5.0.0",
|
|
21
|
+
"typescript": "^6.0.3",
|
|
22
|
+
"vitest": "^5.0.0"
|
|
23
|
+
},
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/src/index.d.ts",
|
|
27
|
+
"default": "./dist/src/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./package.json": "./package.json"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"LICENSE",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"homepage": "https://github.com/Organizzolini/codebase/tree/main/packages/ic-suite/conformetry/conformetry-validation#readme",
|
|
37
|
+
"keywords": [
|
|
38
|
+
"conformance",
|
|
39
|
+
"conformetry",
|
|
40
|
+
"matching",
|
|
41
|
+
"orchestration",
|
|
42
|
+
"validation"
|
|
43
|
+
],
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"main": "./dist/src/index.js",
|
|
46
|
+
"name": "@conformetry/validation",
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public",
|
|
49
|
+
"registry": "https://registry.npmjs.org"
|
|
50
|
+
},
|
|
51
|
+
"repository": {
|
|
52
|
+
"directory": "packages/ic-suite/conformetry/conformetry-validation",
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://github.com/Organizzolini/codebase.git"
|
|
55
|
+
},
|
|
56
|
+
"type": "module",
|
|
57
|
+
"typeCoverage": {
|
|
58
|
+
"atLeast": 100,
|
|
59
|
+
"strict": true
|
|
60
|
+
},
|
|
61
|
+
"types": "./dist/src/index.d.ts",
|
|
62
|
+
"version": "0.0.1"
|
|
63
|
+
}
|