@conformetry/core 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 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,426 @@
1
+ # 👔 Conformetry Core
2
+
3
+ The shared contract every other [Conformetry](../conformetry-cli/README.md)
4
+ package builds on. It is the contracts leaf of the five-layer spine — `core <-
5
+ configuration <- analysis <- output <- cli` — so it declares types and holds
6
+ nothing executable: no service, no NestJS module, no dependency on anything
7
+ else in the conformetry graph. Importing a result type from here therefore
8
+ drags nothing behind it.
9
+
10
+ ```bash
11
+ npm install --save-dev @conformetry/core
12
+ ```
13
+
14
+ ## What it owns
15
+
16
+ | File | Responsibility |
17
+ | ---- | -------------- |
18
+ | `lib/differences.types.ts` | The structured `ConformetryDifference` shape, and the language and category unions that discriminate it |
19
+ | `lib/inventory.types.ts` | What discovery found, as the output layer renders it: templates, instances, and the pairings between them |
20
+ | `lib/runner.types.ts` | The `ConformetryLanguageValidator` contract and the document, payload, and result shapes it is spoken in |
21
+ | `lib/scoring.types.ts` | `InstanceScore`: how well one matched instance honours the template it matched |
22
+
23
+ The behavior these types describe lives above them. The difference and scoring
24
+ primitives, the file-existence pass, and every per-format validator are in
25
+ [`@conformetry/languages`](../conformetry-languages/README.md); the validator
26
+ envelope is in [`@conformetry/validation`](../conformetry-validation/README.md);
27
+ rendering is in [`@conformetry/output`](../conformetry-output/README.md).
28
+
29
+ "Language" here means a validator for one file format — TypeScript, JSON,
30
+ markdown, Python. The word "plugin" is reserved for the Nx plugin in
31
+ [`@conformetry/nx`](../conformetry-nx/README.md), and is deliberately not used
32
+ for these.
33
+
34
+ ## Writing a language validator
35
+
36
+ A validator supplies a descriptor and a single-document comparison. Extension
37
+ filtering, grouping differences under their file, and assembling the result are
38
+ handled once by `RunnerService` in `@conformetry/validation`, so a language
39
+ package contains only its comparison logic:
40
+
41
+ ```ts
42
+ @Injectable()
43
+ export class ExampleValidatorService implements ConformetryLanguageValidator {
44
+ public readonly descriptor = EXAMPLE_VALIDATOR_DESCRIPTOR;
45
+
46
+ public validateDocument(
47
+ document: PreparedValidationDocument,
48
+ ): DocumentValidationResult {
49
+ // compare document.renderedTemplate against document.instance
50
+ return { differences, totalWeight };
51
+ }
52
+ }
53
+ ```
54
+
55
+ ## Weight and score
56
+
57
+ A validator reports how much the template asked for alongside what it found.
58
+ `totalWeight` counts every requirement the comparison weighed — conforming ones
59
+ included, because leaving them out would score an instance only against the
60
+ parts of itself that are already wrong.
61
+
62
+ Each difference may carry a `weight`, defaulting to 1. It says how many
63
+ requirements that one finding stands in for: a validator reports a missing
64
+ class once, however many members it held, so weighing the finding by its
65
+ subtree is what keeps deleting a class from costing the same as deleting an
66
+ import. No per-kind weight table is needed — a class is worth more because it
67
+ contains more.
68
+
69
+ ```text
70
+ score = (totalWeight - sum(difference.weight ?? 1)) / totalWeight
71
+ ```
72
+
73
+ `ScoringService`, in `@conformetry/languages`, owns that arithmetic, including
74
+ the two cases worth getting right once: the default weight of a finding that
75
+ declares none, and an empty template whose denominator is zero and which
76
+ therefore conforms perfectly.
77
+
78
+ [`@conformetry/validation`](../conformetry-validation/README.md) drives the
79
+ registered validators; they are never responsible for discovering files or
80
+ loading configuration.
81
+
82
+ ## Structured differences
83
+
84
+ Differences carry the location on both sides — instance and template — along
85
+ with the expected value and a concrete `fix`. That last field is the point:
86
+ reports are meant to be actionable by whoever, or whatever, has to make the
87
+ file conform. Prefer populating `instanceLine`/`templateLine` (or
88
+ `instancePath` for document formats) over folding a location into the message.
89
+
90
+ ## Exports
91
+
92
+ Types only: `ConformetryDifference`, `ConformetryDifferenceLanguage`,
93
+ `ConformetryDifferenceType`, `ConformetryLanguageValidator`,
94
+ `DocumentValidationResult`, `InstanceScore`, `InventoriedInstance`,
95
+ `InventoriedPairing`, `InventoriedTemplate`, `LanguageValidatorDescriptor`,
96
+ `LanguageValidatorResult`, `PreparedValidationDocument`,
97
+ `PreparedValidationPayload`, and `ValidationFileResult`.
98
+
99
+ ## Test
100
+
101
+ ```bash
102
+ nx run conformetry-core:vitest
103
+ ```
104
+
105
+ One test, and it asserts the property that makes this package a leaf: the
106
+ module contributes nothing at runtime, so importing a result type from here
107
+ cannot drag a service or a NestJS module behind it. Exporting one value fails
108
+ it.
109
+
110
+ ## License
111
+
112
+ MIT — see [LICENSE](../../../../LICENSE).
113
+
114
+ ## 👔 Conformetry
115
+
116
+ This project was generated from the [nestjs-service-project](../../../../configuration/conformetry-templates/nestjs-service-project) conformetry template.
117
+
118
+ <!-- callidescope:start -->
119
+
120
+ ## 🔭 Callidescope
121
+
122
+ Call stacks traced through `packages/ic-suite/conformetry/conformetry-core`, deepest first. Each frame shows what it takes, what it returns, and what its documentation says.
123
+
124
+ | Measure | Value |
125
+ | --- | --- |
126
+ | Callables | 1 |
127
+ | Files | 11 |
128
+ | Calls traced | 0 |
129
+ | Call stacks | 0 |
130
+ | Deepest stack | 0 |
131
+ | Stacks through recursion | 0 |
132
+ | Unfollowable calls | 0 |
133
+
134
+ ### Limits
135
+
136
+ What this project is judged against, as declared in its own `callidescope.config.ts`.
137
+
138
+ | Limit | Value |
139
+ | --- | --- |
140
+ | `maximumDepth` | 1 |
141
+ | `maximumBreadth` | 1 |
142
+
143
+ ### Call stacks (depth)
144
+
145
+ None.
146
+
147
+ ### Breadth
148
+
149
+ None.
150
+ <!-- callidescope:end -->
151
+
152
+ ## 🕸️ Codependix
153
+
154
+ 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`.
155
+
156
+ ### Nx Neighborhood
157
+
158
+ <!-- codependix:start name="codependix-nx-projects" -->
159
+ ```mermaid
160
+ graph LR
161
+ conformetry_cli["conformetry-cli"]
162
+ conformetry_configuration["conformetry-configuration"]
163
+ conformetry_core["conformetry-core"]
164
+ conformetry_languages["conformetry-languages"]
165
+ conformetry_output["conformetry-output"]
166
+ conformetry_validation["conformetry-validation"]
167
+ conformetry_cli --> conformetry_core
168
+ conformetry_configuration --> conformetry_core
169
+ conformetry_languages --> conformetry_core
170
+ conformetry_output --> conformetry_core
171
+ conformetry_validation --> conformetry_core
172
+ classDef subject fill:#7c3aed,color:#fff,stroke:#4c1d95,stroke-width:2px
173
+ class conformetry_core subject
174
+ ```
175
+ <!-- codependix:end name="codependix-nx-projects" -->
176
+
177
+ ### NestJS Module Graph
178
+
179
+ <!-- codependix:start name="codependix-nestjs-modules" -->
180
+ ```mermaid
181
+ flowchart LR
182
+ ConformetryCoreModule
183
+ ```
184
+ <!-- codependix:end name="codependix-nestjs-modules" -->
185
+
186
+ ### File Imports
187
+
188
+ <!-- codependix:start name="codependix-file-imports" -->
189
+ ```mermaid
190
+ graph LR
191
+ file_callidescope_config_ts["callidescope.config.ts"]
192
+ file_codependix_config_ts["codependix.config.ts"]
193
+ file_codometer_config_ts["codometer.config.ts"]
194
+ file_eslint_config_ts["eslint.config.ts"]
195
+ file_src_index_ts["src/index.ts"]
196
+ file_src_index_unit_test_ts["src/index.unit.test.ts"]
197
+ file_src_modules_conformetry_core_conformetry_core_constants_ts["src/modules/conformetry-core/conformetry-core.constants.ts"]
198
+ file_src_modules_conformetry_core_conformetry_core_module_ts["src/modules/conformetry-core/conformetry-core.module.ts"]
199
+ file_src_modules_conformetry_core_conformetry_core_service_ts["src/modules/conformetry-core/conformetry-core.service.ts"]
200
+ file_src_modules_conformetry_core_conformetry_core_service_unit_test_ts["src/modules/conformetry-core/conformetry-core.service.unit.test.ts"]
201
+ file_src_modules_conformetry_core_conformetry_core_types_ts["src/modules/conformetry-core/conformetry-core.types.ts"]
202
+ file_testing_mocks_ts["testing/mocks.ts"]
203
+ file_testing_setup_ts["testing/setup.ts"]
204
+ file_vite_config_ts["vite.config.ts"]
205
+ file_vitest_config_ts["vitest.config.ts"]
206
+ file_src_index_unit_test_ts --> file_src_index_ts
207
+ file_src_modules_conformetry_core_conformetry_core_module_ts --> file_src_modules_conformetry_core_conformetry_core_service_ts
208
+ file_src_modules_conformetry_core_conformetry_core_service_unit_test_ts --> file_src_modules_conformetry_core_conformetry_core_service_ts
209
+ ```
210
+ <!-- codependix:end name="codependix-file-imports" -->
211
+
212
+ <!-- codometer:start -->
213
+
214
+ ## ⏲️ Codometer
215
+
216
+ ### Project
217
+
218
+ ![Lines of Code](https://img.shields.io/badge/Lines_of_Code-491-22c55e?style=flat-square)
219
+ ![Repository Size](https://img.shields.io/badge/Repository_Size-28.45_kB-6b7280?style=flat-square)
220
+ ![Folders](https://img.shields.io/badge/Folders-4-4a4a4a?style=flat-square)
221
+ ![Source Files](https://img.shields.io/badge/Source_Files-15-3178c6?style=flat-square)
222
+
223
+ ### Measured Targets
224
+
225
+ ![Compiled JavaScript Size](https://img.shields.io/badge/Compiled_JavaScript_Size-0.57_kB_gzip-6b7280?style=flat-square)
226
+
227
+ ### TypeScript
228
+
229
+ ![TypeScript Files](https://img.shields.io/badge/TypeScript_Files-15-3178c6?style=flat-square)
230
+ ![Interfaces](https://img.shields.io/badge/Interfaces-12-0ea5e9?style=flat-square)
231
+ ![Generic Declarations](https://img.shields.io/badge/Generic_Declarations-0-0369a1?style=flat-square)
232
+ ![Enums](https://img.shields.io/badge/Enums-0-f97316?style=flat-square)
233
+ ![Decorators](https://img.shields.io/badge/Decorators-2-db2777?style=flat-square)
234
+ ![Doc Comments](https://img.shields.io/badge/Doc_Comments-54-6366f1?style=flat-square)
235
+ ![Static Methods](https://img.shields.io/badge/Static_Methods-0-166534?style=flat-square)
236
+
237
+ ### JavaScript
238
+
239
+ ![JavaScript Files](https://img.shields.io/badge/JavaScript_Files-0-f7df1e?style=flat-square)
240
+ ![Test Files](https://img.shields.io/badge/Test_Files-2-10b981?style=flat-square)
241
+ ![External Packages](https://img.shields.io/badge/External_Packages-7-8b5cf6?style=flat-square)
242
+ ![Classes](https://img.shields.io/badge/Classes-2-7c3aed?style=flat-square)
243
+ ![Functions](https://img.shields.io/badge/Functions-13-16a34a?style=flat-square)
244
+ ![Methods](https://img.shields.io/badge/Methods-0-15803d?style=flat-square)
245
+ ![Sync Functions](https://img.shields.io/badge/Sync_Functions-12-4ade80?style=flat-square)
246
+ ![Async Functions](https://img.shields.io/badge/Async_Functions-1-059669?style=flat-square)
247
+ ![Constants](https://img.shields.io/badge/Constants-3-dc2626?style=flat-square)
248
+ ![Imports](https://img.shields.io/badge/Imports-21-0284c7?style=flat-square)
249
+ ![Exported Symbols](https://img.shields.io/badge/Exported_Symbols-18-ea580c?style=flat-square)
250
+ ![Comments](https://img.shields.io/badge/Comments-71-64748b?style=flat-square)
251
+ ![Comment Lines](https://img.shields.io/badge/Comment_Lines-174-475569?style=flat-square)
252
+ ![TODO Comments](https://img.shields.io/badge/TODO_Comments-2-ca8a04?style=flat-square)
253
+
254
+ ### Python
255
+
256
+ ![Python Files](https://img.shields.io/badge/Python_Files-0-3776ab?style=flat-square)
257
+ ![Python Lines](https://img.shields.io/badge/Python_Lines-0-4b8bbe?style=flat-square)
258
+ ![Python Classes](https://img.shields.io/badge/Python_Classes-0-7c3aed?style=flat-square)
259
+ ![Python Functions](https://img.shields.io/badge/Python_Functions-0-16a34a?style=flat-square)
260
+ ![Python Protocols](https://img.shields.io/badge/Python_Protocols-0-0ea5e9?style=flat-square)
261
+ ![Python Constants](https://img.shields.io/badge/Python_Constants-0-dc2626?style=flat-square)
262
+ ![Python Imports](https://img.shields.io/badge/Python_Imports-0-0284c7?style=flat-square)
263
+ ![Python Decorators](https://img.shields.io/badge/Python_Decorators-0-db2777?style=flat-square)
264
+ ![Docstrings](https://img.shields.io/badge/Docstrings-0-6366f1?style=flat-square)
265
+ ![Docstring Lines](https://img.shields.io/badge/Docstring_Lines-0-818cf8?style=flat-square)
266
+ ![Python Comments](https://img.shields.io/badge/Python_Comments-0-64748b?style=flat-square)
267
+ ![Python Comment Lines](https://img.shields.io/badge/Python_Comment_Lines-0-475569?style=flat-square)
268
+
269
+ ### JSON
270
+
271
+ ![JSON Files](https://img.shields.io/badge/JSON_Files-4-a16207?style=flat-square)
272
+ ![JSON Lines](https://img.shields.io/badge/JSON_Lines-161-ca8a04?style=flat-square)
273
+ ![JSON Objects](https://img.shields.io/badge/JSON_Objects-38-7c3aed?style=flat-square)
274
+ ![JSON Arrays](https://img.shields.io/badge/JSON_Arrays-13-8b5cf6?style=flat-square)
275
+ ![JSON Properties](https://img.shields.io/badge/JSON_Properties-98-0284c7?style=flat-square)
276
+ ![JSON Strings](https://img.shields.io/badge/JSON_Strings-86-16a34a?style=flat-square)
277
+ ![JSON Numbers](https://img.shields.io/badge/JSON_Numbers-1-059669?style=flat-square)
278
+ ![JSON Booleans](https://img.shields.io/badge/JSON_Booleans-7-0ea5e9?style=flat-square)
279
+ ![JSON Nulls](https://img.shields.io/badge/JSON_Nulls-0-64748b?style=flat-square)
280
+ ![JSON Items](https://img.shields.io/badge/JSON_Items-43-475569?style=flat-square)
281
+ ![JSON Nodes](https://img.shields.io/badge/JSON_Nodes-145-dc2626?style=flat-square)
282
+ ![JSON Max Depth](https://img.shields.io/badge/JSON_Max_Depth-5-ea580c?style=flat-square)
283
+
284
+ ### YAML
285
+
286
+ ![YAML Files](https://img.shields.io/badge/YAML_Files-0-cb171e?style=flat-square)
287
+ ![YAML Lines](https://img.shields.io/badge/YAML_Lines-0-e34c26?style=flat-square)
288
+ ![YAML Documents](https://img.shields.io/badge/YAML_Documents-0-f97316?style=flat-square)
289
+ ![YAML Mappings](https://img.shields.io/badge/YAML_Mappings-0-7c3aed?style=flat-square)
290
+ ![YAML Sequences](https://img.shields.io/badge/YAML_Sequences-0-8b5cf6?style=flat-square)
291
+ ![YAML Keys](https://img.shields.io/badge/YAML_Keys-0-0284c7?style=flat-square)
292
+ ![YAML Scalars](https://img.shields.io/badge/YAML_Scalars-0-16a34a?style=flat-square)
293
+ ![YAML Anchors](https://img.shields.io/badge/YAML_Anchors-0-059669?style=flat-square)
294
+ ![YAML Aliases](https://img.shields.io/badge/YAML_Aliases-0-10b981?style=flat-square)
295
+ ![YAML Comments](https://img.shields.io/badge/YAML_Comments-0-64748b?style=flat-square)
296
+ ![YAML Max Depth](https://img.shields.io/badge/YAML_Max_Depth-0-ea580c?style=flat-square)
297
+
298
+ ### TOML
299
+
300
+ ![TOML Files](https://img.shields.io/badge/TOML_Files-0-9c4221?style=flat-square)
301
+ ![TOML Lines](https://img.shields.io/badge/TOML_Lines-0-b45309?style=flat-square)
302
+ ![TOML Tables](https://img.shields.io/badge/TOML_Tables-0-7c3aed?style=flat-square)
303
+ ![TOML Array Tables](https://img.shields.io/badge/TOML_Array_Tables-0-8b5cf6?style=flat-square)
304
+ ![TOML Keys](https://img.shields.io/badge/TOML_Keys-0-0284c7?style=flat-square)
305
+ ![TOML Arrays](https://img.shields.io/badge/TOML_Arrays-0-16a34a?style=flat-square)
306
+ ![TOML Comments](https://img.shields.io/badge/TOML_Comments-0-64748b?style=flat-square)
307
+
308
+ ### Shell
309
+
310
+ ![Shell Files](https://img.shields.io/badge/Shell_Files-0-89e051?style=flat-square)
311
+ ![Shell Lines](https://img.shields.io/badge/Shell_Lines-0-4eaa25?style=flat-square)
312
+ ![Shell Functions](https://img.shields.io/badge/Shell_Functions-0-16a34a?style=flat-square)
313
+ ![Shell Variables](https://img.shields.io/badge/Shell_Variables-0-0284c7?style=flat-square)
314
+ ![Shell Exports](https://img.shields.io/badge/Shell_Exports-0-ea580c?style=flat-square)
315
+ ![Shell Conditionals](https://img.shields.io/badge/Shell_Conditionals-0-7c3aed?style=flat-square)
316
+ ![Shell Loops](https://img.shields.io/badge/Shell_Loops-0-8b5cf6?style=flat-square)
317
+ ![Shell Pipelines](https://img.shields.io/badge/Shell_Pipelines-0-059669?style=flat-square)
318
+ ![Shebangs](https://img.shields.io/badge/Shebangs-0-6b7280?style=flat-square)
319
+ ![Shell Comments](https://img.shields.io/badge/Shell_Comments-0-64748b?style=flat-square)
320
+ ![Shell Comment Lines](https://img.shields.io/badge/Shell_Comment_Lines-0-475569?style=flat-square)
321
+
322
+ ### SQL
323
+
324
+ ![SQL Files](https://img.shields.io/badge/SQL_Files-0-e38c00?style=flat-square)
325
+ ![SQL Lines](https://img.shields.io/badge/SQL_Lines-0-f29111?style=flat-square)
326
+ ![SQL Statements](https://img.shields.io/badge/SQL_Statements-0-7c3aed?style=flat-square)
327
+ ![SQL Selects](https://img.shields.io/badge/SQL_Selects-0-16a34a?style=flat-square)
328
+ ![SQL Inserts](https://img.shields.io/badge/SQL_Inserts-0-22c55e?style=flat-square)
329
+ ![SQL Updates](https://img.shields.io/badge/SQL_Updates-0-0ea5e9?style=flat-square)
330
+ ![SQL Deletes](https://img.shields.io/badge/SQL_Deletes-0-dc2626?style=flat-square)
331
+ ![SQL Creates](https://img.shields.io/badge/SQL_Creates-0-0284c7?style=flat-square)
332
+ ![SQL Joins](https://img.shields.io/badge/SQL_Joins-0-8b5cf6?style=flat-square)
333
+ ![SQL CTEs](https://img.shields.io/badge/SQL_CTEs-0-059669?style=flat-square)
334
+ ![SQL Comments](https://img.shields.io/badge/SQL_Comments-0-64748b?style=flat-square)
335
+
336
+ ### HCL
337
+
338
+ ![HCL Files](https://img.shields.io/badge/HCL_Files-0-844fba?style=flat-square)
339
+ ![HCL Lines](https://img.shields.io/badge/HCL_Lines-0-a78bfa?style=flat-square)
340
+ ![HCL Blocks](https://img.shields.io/badge/HCL_Blocks-0-7c3aed?style=flat-square)
341
+ ![HCL Resources](https://img.shields.io/badge/HCL_Resources-0-0284c7?style=flat-square)
342
+ ![HCL Variables](https://img.shields.io/badge/HCL_Variables-0-16a34a?style=flat-square)
343
+ ![HCL Outputs](https://img.shields.io/badge/HCL_Outputs-0-059669?style=flat-square)
344
+ ![HCL Attributes](https://img.shields.io/badge/HCL_Attributes-0-0ea5e9?style=flat-square)
345
+ ![HCL Interpolations](https://img.shields.io/badge/HCL_Interpolations-0-db2777?style=flat-square)
346
+ ![HCL Comments](https://img.shields.io/badge/HCL_Comments-0-64748b?style=flat-square)
347
+
348
+ ### CSS
349
+
350
+ ![CSS Files](https://img.shields.io/badge/CSS_Files-0-264de4?style=flat-square)
351
+ ![CSS Lines](https://img.shields.io/badge/CSS_Lines-0-2965f1?style=flat-square)
352
+ ![CSS Rules](https://img.shields.io/badge/CSS_Rules-0-7c3aed?style=flat-square)
353
+ ![CSS Selectors](https://img.shields.io/badge/CSS_Selectors-0-8b5cf6?style=flat-square)
354
+ ![CSS Declarations](https://img.shields.io/badge/CSS_Declarations-0-0284c7?style=flat-square)
355
+ ![CSS At Rules](https://img.shields.io/badge/CSS_At_Rules-0-f97316?style=flat-square)
356
+ ![CSS Media Queries](https://img.shields.io/badge/CSS_Media_Queries-0-ea580c?style=flat-square)
357
+ ![CSS Custom Properties](https://img.shields.io/badge/CSS_Custom_Properties-0-16a34a?style=flat-square)
358
+ ![CSS Comments](https://img.shields.io/badge/CSS_Comments-0-64748b?style=flat-square)
359
+
360
+ ### Conventions
361
+
362
+ ![Module Files](https://img.shields.io/badge/Module_Files-1-7c3aed?style=flat-square)
363
+ ![Service Files](https://img.shields.io/badge/Service_Files-1-0284c7?style=flat-square)
364
+ ![Command Files](https://img.shields.io/badge/Command_Files-0-16a34a?style=flat-square)
365
+ ![Constants Files](https://img.shields.io/badge/Constants_Files-1-ea580c?style=flat-square)
366
+ ![Types Files](https://img.shields.io/badge/Types_Files-1-db2777?style=flat-square)
367
+ ![Utilities Files](https://img.shields.io/badge/Utilities_Files-0-0ea5e9?style=flat-square)
368
+ ![TypeORM Entities](https://img.shields.io/badge/TypeORM_Entities-0-059669?style=flat-square)
369
+ ![Unit Tests](https://img.shields.io/badge/Unit_Tests-2-ca8a04?style=flat-square)
370
+ ![Integration Tests](https://img.shields.io/badge/Integration_Tests-0-7c3aed?style=flat-square)
371
+ ![End To End Tests](https://img.shields.io/badge/End_To_End_Tests-0-0284c7?style=flat-square)
372
+ ![CSS Comment Budget](https://img.shields.io/badge/CSS_Comment_Budget-0-16a34a?style=flat-square)
373
+ ![HCL Comment Budget](https://img.shields.io/badge/HCL_Comment_Budget-0-ea580c?style=flat-square)
374
+ ![Python Comment Budget](https://img.shields.io/badge/Python_Comment_Budget-0-db2777?style=flat-square)
375
+ ![SQL Comment Budget](https://img.shields.io/badge/SQL_Comment_Budget-0-0ea5e9?style=flat-square)
376
+ ![TOML Comment Budget](https://img.shields.io/badge/TOML_Comment_Budget-0-059669?style=flat-square)
377
+ ![TypeScript Comment Budget](https://img.shields.io/badge/TypeScript_Comment_Budget-0-ca8a04?style=flat-square)
378
+ ![YAML Comment Budget](https://img.shields.io/badge/YAML_Comment_Budget-0-7c3aed?style=flat-square)
379
+ ![Shell Comment Budget](https://img.shields.io/badge/Shell_Comment_Budget-0-0284c7?style=flat-square)
380
+
381
+ ### Jupyter
382
+
383
+ ![Notebooks](https://img.shields.io/badge/Notebooks-0-f37626?style=flat-square)
384
+ ![Notebook Cells](https://img.shields.io/badge/Notebook_Cells-0-e8a33d?style=flat-square)
385
+ ![Code Cells](https://img.shields.io/badge/Code_Cells-0-3776ab?style=flat-square)
386
+ ![Markdown Cells](https://img.shields.io/badge/Markdown_Cells-0-083fa1?style=flat-square)
387
+ ![Raw Cells](https://img.shields.io/badge/Raw_Cells-0-9ca3af?style=flat-square)
388
+ ![Executed Cells](https://img.shields.io/badge/Executed_Cells-0-16a34a?style=flat-square)
389
+ ![Cell Outputs](https://img.shields.io/badge/Cell_Outputs-0-059669?style=flat-square)
390
+ ![Notebook Code Lines](https://img.shields.io/badge/Notebook_Code_Lines-0-4b8bbe?style=flat-square)
391
+ ![Notebook Classes](https://img.shields.io/badge/Notebook_Classes-0-7c3aed?style=flat-square)
392
+ ![Notebook Functions](https://img.shields.io/badge/Notebook_Functions-0-22c55e?style=flat-square)
393
+ ![Notebook Imports](https://img.shields.io/badge/Notebook_Imports-0-0284c7?style=flat-square)
394
+ ![Notebook Decorators](https://img.shields.io/badge/Notebook_Decorators-0-db2777?style=flat-square)
395
+ ![Notebook Prose Lines](https://img.shields.io/badge/Notebook_Prose_Lines-0-1f6feb?style=flat-square)
396
+ ![Notebook Headings](https://img.shields.io/badge/Notebook_Headings-0-a78bfa?style=flat-square)
397
+ ![Notebook Links](https://img.shields.io/badge/Notebook_Links-0-10b981?style=flat-square)
398
+ ![Notebook Images](https://img.shields.io/badge/Notebook_Images-0-34d399?style=flat-square)
399
+ ![Notebook Code Blocks](https://img.shields.io/badge/Notebook_Code_Blocks-0-dc2626?style=flat-square)
400
+ ![Notebook Properties](https://img.shields.io/badge/Notebook_Properties-0-ca8a04?style=flat-square)
401
+ ![Notebook Nodes](https://img.shields.io/badge/Notebook_Nodes-0-a16207?style=flat-square)
402
+ ![Notebook Max Depth](https://img.shields.io/badge/Notebook_Max_Depth-0-ea580c?style=flat-square)
403
+
404
+ ### Markdown
405
+
406
+ ![Markdown Files](https://img.shields.io/badge/Markdown_Files-1-083fa1?style=flat-square)
407
+ ![Markdown Lines](https://img.shields.io/badge/Markdown_Lines-227-1f6feb?style=flat-square)
408
+ ![H1](https://img.shields.io/badge/H1-1-7c3aed?style=flat-square)
409
+ ![H2](https://img.shields.io/badge/H2-7-8b5cf6?style=flat-square)
410
+ ![H3](https://img.shields.io/badge/H3-12-a78bfa?style=flat-square)
411
+ ![H4](https://img.shields.io/badge/H4-0-c4b5fd?style=flat-square)
412
+ ![H5](https://img.shields.io/badge/H5-0-ddd6fe?style=flat-square)
413
+ ![H6](https://img.shields.io/badge/H6-0-ede9fe?style=flat-square)
414
+ ![Paragraphs](https://img.shields.io/badge/Paragraphs-46-64748b?style=flat-square)
415
+ ![Lists](https://img.shields.io/badge/Lists-6-16a34a?style=flat-square)
416
+ ![List Items](https://img.shields.io/badge/List_Items-25-22c55e?style=flat-square)
417
+ ![Task List Items](https://img.shields.io/badge/Task_List_Items-0-4ade80?style=flat-square)
418
+ ![Tables](https://img.shields.io/badge/Tables-2-0284c7?style=flat-square)
419
+ ![Table Rows](https://img.shields.io/badge/Table_Rows-10-0ea5e9?style=flat-square)
420
+ ![Links](https://img.shields.io/badge/Links-9-059669?style=flat-square)
421
+ ![Images](https://img.shields.io/badge/Images-0-10b981?style=flat-square)
422
+ ![Code Blocks](https://img.shields.io/badge/Code_Blocks-11-dc2626?style=flat-square)
423
+ ![Inline Code](https://img.shields.io/badge/Inline_Code-74-ef4444?style=flat-square)
424
+ ![Block Quotes](https://img.shields.io/badge/Block_Quotes-0-ca8a04?style=flat-square)
425
+ ![Thematic Breaks](https://img.shields.io/badge/Thematic_Breaks-0-a16207?style=flat-square)
426
+ <!-- codometer:end -->
@@ -0,0 +1,242 @@
1
+ /**
2
+ * TODO: Document the conformetryCore module.
3
+ */
4
+ export declare class ConformetryCoreModule {
5
+ }
6
+
7
+ /**
8
+ * TODO: Document the conformetryCore service.
9
+ */
10
+ export declare class ConformetryCoreService {
11
+ constructor();
12
+ }
13
+
14
+ /**
15
+ * A structured conformance error produced by any validator.
16
+ *
17
+ * Two discriminating fields identify the error category:
18
+ * - `differenceType` — what kind of element is missing
19
+ * - `language` — which validator / file format produced the error.
20
+ *
21
+ * All differences represent a *missing* or *mismatched* element; there is no
22
+ * separate action field. Consumers render these through `ReportingService`
23
+ * rather than formatting them ad hoc, so every validator reports identically.
24
+ */
25
+ export declare interface ConformetryDifference {
26
+ /** Actual value found in the instance (populated for value-mismatch differences). */
27
+ readonly actual?: string;
28
+ /** Category of missing element. */
29
+ readonly differenceType: ConformetryDifferenceType;
30
+ /** Snippet of the template content that should be present in the instance. */
31
+ readonly expected?: string;
32
+ /** One-line actionable suggestion for the reader (human or coding agent). */
33
+ readonly fix: string;
34
+ /** 1-based column number in the instance file where the error was detected. */
35
+ readonly instanceColumn?: number;
36
+ /** 1-based line number in the instance file where the error was detected. */
37
+ readonly instanceLine?: number;
38
+ /** JSON dot-notation path in the instance document, e.g. `"scripts.build[0]"`. */
39
+ readonly instancePath?: string;
40
+ /**
41
+ * File format of the validator that produced this error.
42
+ * Absent for `"file"` and `"directory"` differences.
43
+ */
44
+ readonly language?: ConformetryDifferenceLanguage;
45
+ /** Short human-readable description of what is missing. */
46
+ readonly message: string;
47
+ /** 1-based column number in the rendered template that defines the requirement. */
48
+ readonly templateColumn?: number;
49
+ /** 1-based line number in the rendered template that defines the requirement. */
50
+ readonly templateLine?: number;
51
+ /** JSON dot-notation path in the template document. */
52
+ readonly templatePath?: string;
53
+ /**
54
+ * How many template requirements this one finding accounts for.
55
+ *
56
+ * A validator reports a missing element once, however much of the template
57
+ * that element contained: deleting a class is one error, not one per member.
58
+ * The weight restores the proportion — a missing class stands in for its
59
+ * whole subtree, a missing import stands only for itself — so an instance's
60
+ * score reflects how much of the template is actually absent.
61
+ *
62
+ * Defaults to 1 when absent, which is right for any leaf requirement.
63
+ */
64
+ readonly weight?: number;
65
+ }
66
+
67
+ /**
68
+ * The language / file format processed by the validator that produced the
69
+ * error. Absent for `"file"` and `"directory"` differences, which are language
70
+ * agnostic and raised by the file-existence pass.
71
+ */
72
+ export declare type ConformetryDifferenceLanguage = "javascript" | "json" | "markdown" | "python" | "text" | "typescript";
73
+
74
+ /**
75
+ * Category of the element that caused the conformance failure.
76
+ *
77
+ * `"instance"` is the odd one out: it does not name a missing element inside a
78
+ * file but a directory or file the caller declared to be generated code, which
79
+ * conformetry could not attribute to any single template.
80
+ */
81
+ export declare type ConformetryDifferenceType = "code" | "comment" | "directory" | "file" | "instance";
82
+
83
+ /**
84
+ * A validator for one language or file format.
85
+ *
86
+ * Implementations supply only their descriptor and a single-document
87
+ * comparison. Extension filtering, result grouping, and result assembly are
88
+ * handled once by `RunnerService`, so no validator repeats that envelope.
89
+ *
90
+ * Not to be confused with an Nx plugin — this is the contract between
91
+ * `conformetry-validation` and the Language modules in `conformetry-languages`,
92
+ * such as its TypeScript module.
93
+ */
94
+ export declare interface ConformetryLanguageValidator {
95
+ readonly descriptor: LanguageValidatorDescriptor;
96
+ /**
97
+ * Compares one already-rendered template against its instance and returns
98
+ * every difference, plus how much was asked of the instance. Called only for
99
+ * documents whose extension this validator claims, so implementations never
100
+ * need to re-check the extension.
101
+ */
102
+ validateDocument(document: PreparedValidationDocument): DocumentValidationResult;
103
+ }
104
+
105
+ /**
106
+ * What comparing one document produced: the differences, and the size of the
107
+ * requirement the comparison weighed them against.
108
+ *
109
+ * The total is reported even when nothing is wrong. A conforming document is
110
+ * still evidence — it is the part of the instance that *did* honour its
111
+ * template — and leaving it out of the denominator would score an instance
112
+ * only against the files it got wrong.
113
+ */
114
+ export declare interface DocumentValidationResult {
115
+ readonly differences: ConformetryDifference[];
116
+ /** Combined weight of the template requirements this document imposes. */
117
+ readonly totalWeight: number;
118
+ }
119
+
120
+ /**
121
+ * How well one matched instance honours the template it was matched to.
122
+ *
123
+ * Lives in core rather than beside the orchestrator because reporting renders
124
+ * it and the orchestrator produces it, and a shape shared by two layers is
125
+ * exactly what the leaf package is for.
126
+ */
127
+ export declare interface InstanceScore {
128
+ /** Combined weight of the requirements this instance failed. */
129
+ readonly failedWeight: number;
130
+ readonly instancePath: string;
131
+ /** Whether the score reached the threshold that applies to this instance. */
132
+ readonly ok: boolean;
133
+ /** Share of the template's requirements honoured, from 0 to 1. */
134
+ readonly score: number;
135
+ readonly templateName: string;
136
+ /** The threshold that applied, after resolving every level. */
137
+ readonly threshold: number;
138
+ /** Combined weight of the requirements that were checked. */
139
+ readonly totalWeight: number;
140
+ }
141
+
142
+ /**
143
+ * One instance found on disk, paired with the templates that explain it.
144
+ *
145
+ * Lives in core for the same reason [[InstanceScore]] does: discovery produces
146
+ * it and the output layer renders it, so the shape belongs to neither side.
147
+ */
148
+ export declare interface InventoriedInstance {
149
+ /** Where the instance is, including its name stem. */
150
+ readonly path: string;
151
+ /** Templates that explain this instance, best fit first. */
152
+ readonly templates: InventoriedPairing[];
153
+ }
154
+
155
+ /**
156
+ * How well one template and one instance fit each other.
157
+ *
158
+ * The ratio is file overlap, not conformance: it says how much of a template's
159
+ * structure an instance has, never how faithfully those files honour it.
160
+ */
161
+ export declare interface InventoriedPairing {
162
+ readonly matchedFileCount: number;
163
+ /** Share of the template's files the instance already has, 0 to 1. */
164
+ readonly matchRatio: number;
165
+ /** The other side of the pairing — a template name or an instance path. */
166
+ readonly name: string;
167
+ readonly templateFileCount: number;
168
+ }
169
+
170
+ /** One declared template, paired with the instances it explains. */
171
+ export declare interface InventoriedTemplate {
172
+ readonly description: string;
173
+ /** Instances this template explains, empty when nothing matched it. */
174
+ readonly instances: InventoriedPairing[];
175
+ readonly name: string;
176
+ readonly templatePath: string;
177
+ }
178
+
179
+ /** Identifies a language validator and declares which files it claims. */
180
+ export declare interface LanguageValidatorDescriptor {
181
+ /** Human-readable summary shown in CLI help and reports. */
182
+ readonly description?: string;
183
+ /** Extensions this validator claims, including the leading dot. */
184
+ readonly fileExtensions: readonly string[];
185
+ /** Stable identifier, also usable as a `--languages` filter value. */
186
+ readonly name: string;
187
+ }
188
+
189
+ /** Outcome of running one language validator over a document set. */
190
+ export declare interface LanguageValidatorResult {
191
+ readonly checkedPaths: string[];
192
+ readonly fileResults: ValidationFileResult[];
193
+ readonly languageName: string;
194
+ readonly ok: boolean;
195
+ /**
196
+ * Combined weight of every document this validator claimed, conforming ones
197
+ * included — see `DocumentValidationResult.totalWeight`.
198
+ */
199
+ readonly totalWeight: number;
200
+ }
201
+
202
+ /**
203
+ * A template file paired with the instance file it governs, with the template
204
+ * already rendered against the project's substitutions. Producing these is
205
+ * `conformetry-configuration`'s job; validators only compare them.
206
+ *
207
+ * A document exists only when both sides are present on disk — missing files
208
+ * are reported by the file-existence pass before validators ever run.
209
+ */
210
+ export declare interface PreparedValidationDocument {
211
+ /** Basename of the instance file, used to pick a parser. */
212
+ readonly filename: string;
213
+ /** Verbatim contents of the instance file. */
214
+ readonly instance: string;
215
+ /** Absolute path to the instance file, used in error messages. */
216
+ readonly instanceFilePath: string;
217
+ /** Template contents after substitutions have been applied. */
218
+ readonly renderedTemplate: string;
219
+ /** Absolute path to the source template, used in error messages. */
220
+ readonly templateFilePath: string;
221
+ }
222
+
223
+ /** The document pairs discovered for one validation run. */
224
+ export declare interface PreparedValidationPayload {
225
+ readonly checkedPaths: string[];
226
+ readonly documents: PreparedValidationDocument[];
227
+ }
228
+
229
+ /**
230
+ * Every error found in one instance file, kept grouped by file so reports can
231
+ * print a per-file heading with its originating template.
232
+ */
233
+ export declare interface ValidationFileResult {
234
+ readonly differences: ConformetryDifference[];
235
+ readonly filename: string;
236
+ readonly instanceFilePath: string;
237
+ readonly templateFilePath: string;
238
+ /** Combined weight of the template requirements checked in this file. */
239
+ readonly totalWeight: number;
240
+ }
241
+
242
+ export { }
@@ -0,0 +1,30 @@
1
+ import { Injectable as e, Module as t } from "@nestjs/common";
2
+ //#region \0@oxc-project+runtime@0.151.0/helpers/esm/decorateMetadata.js
3
+ function n(e, t) {
4
+ if (typeof Reflect == "object" && typeof Reflect.metadata == "function") return Reflect.metadata(e, t);
5
+ }
6
+ //#endregion
7
+ //#region \0@oxc-project+runtime@0.151.0/helpers/esm/decorate.js
8
+ function r(e, t, n, r) {
9
+ var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
10
+ if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
11
+ 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);
12
+ return i > 3 && a && Object.defineProperty(t, n, a), a;
13
+ }
14
+ //#endregion
15
+ //#region packages/ic-suite/conformetry/conformetry-core/src/modules/conformetry-core/conformetry-core.service.ts
16
+ var i = class {
17
+ constructor() {}
18
+ };
19
+ i = r([e(), n("design:paramtypes", [])], i);
20
+ //#endregion
21
+ //#region packages/ic-suite/conformetry/conformetry-core/src/modules/conformetry-core/conformetry-core.module.ts
22
+ var a = class {};
23
+ a = r([t({
24
+ controllers: [],
25
+ exports: [i],
26
+ imports: [],
27
+ providers: [i]
28
+ })], a);
29
+ //#endregion
30
+ export { a as ConformetryCoreModule, i as ConformetryCoreService };
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "author": "Jimmy Paolini",
3
+ "bugs": {
4
+ "url": "https://github.com/Organizzolini/codebase/issues"
5
+ },
6
+ "dependencies": {
7
+ "@nestjs/common": "^11.1.21 || ^12.0.1",
8
+ "reflect-metadata": "^0.2.2"
9
+ },
10
+ "description": "Core types and structured contracts for the Conformetry code generation and conformance toolchain",
11
+ "devDependencies": {
12
+ "@golevelup/ts-vitest": "^4.0.0",
13
+ "@nestjs/testing": "^12.0.1",
14
+ "@nx/eslint-plugin": "^23.0.0",
15
+ "@swc/helpers": "^0.5.21",
16
+ "@types/node": "^26.5.1",
17
+ "@vitest/coverage-v8": "^5.0.0",
18
+ "vitest": "^5.0.0"
19
+ },
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/src/index.d.ts",
23
+ "default": "./dist/src/index.js"
24
+ },
25
+ "./package.json": "./package.json"
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "LICENSE",
30
+ "README.md"
31
+ ],
32
+ "homepage": "https://github.com/Organizzolini/codebase/tree/main/packages/ic-suite/conformetry/conformetry-core#readme",
33
+ "keywords": [
34
+ "code-generation",
35
+ "conformance",
36
+ "conformetry",
37
+ "contracts",
38
+ "templates",
39
+ "types"
40
+ ],
41
+ "license": "MIT",
42
+ "main": "./dist/src/index.js",
43
+ "name": "@conformetry/core",
44
+ "publishConfig": {
45
+ "access": "public",
46
+ "registry": "https://registry.npmjs.org"
47
+ },
48
+ "repository": {
49
+ "directory": "packages/ic-suite/conformetry/conformetry-core",
50
+ "type": "git",
51
+ "url": "git+https://github.com/Organizzolini/codebase.git"
52
+ },
53
+ "type": "module",
54
+ "typeCoverage": {
55
+ "atLeast": 100,
56
+ "strict": true
57
+ },
58
+ "types": "./dist/src/index.d.ts",
59
+ "version": "0.0.1"
60
+ }