@coinagerie/output 0.0.0-stage → 0.0.2
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/CHANGELOG.md +20 -0
- package/LICENSE +21 -0
- package/README.md +441 -2
- package/dist/src/index.d.ts +273 -0
- package/dist/src/index.js +301 -0
- package/package.json +58 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
## 0.0.2 (2026-11-04)
|
|
2
|
+
|
|
3
|
+
### 🧱 Updated Dependencies
|
|
4
|
+
|
|
5
|
+
- Updated coinagerie-configuration to 0.0.2
|
|
6
|
+
- Updated coinagerie-core to 0.0.2
|
|
7
|
+
|
|
8
|
+
## 0.0.1 (2026-11-04)
|
|
9
|
+
|
|
10
|
+
### 🚀 Features
|
|
11
|
+
|
|
12
|
+
- **coinagerie:** 📦️ publish coinagerie to npm ([#2088](https://github.com/organizzolini/codebase/pull/2088), [#1793](https://github.com/organizzolini/codebase/issues/1793))
|
|
13
|
+
- **configuration,coinagerie:** ✨ adopt coinagerie with a root glossary ([#1888](https://github.com/organizzolini/codebase/pull/1888), [#1785](https://github.com/organizzolini/codebase/issues/1785))
|
|
14
|
+
- **coinagerie:** ✨ write json glossaries and override configuration with flags ([#1880](https://github.com/organizzolini/codebase/pull/1880), [#1766](https://github.com/organizzolini/codebase/issues/1766))
|
|
15
|
+
- **coinagerie:** ✨ build a markdown glossary from typescript ([#1875](https://github.com/organizzolini/codebase/pull/1875), [#1755](https://github.com/organizzolini/codebase/issues/1755))
|
|
16
|
+
|
|
17
|
+
### 🧱 Updated Dependencies
|
|
18
|
+
|
|
19
|
+
- Updated coinagerie-configuration to 0.0.1
|
|
20
|
+
- Updated coinagerie-core to 0.0.1
|
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
CHANGED
|
@@ -1,3 +1,442 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @coinagerie/output
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@coinagerie/output)
|
|
4
|
+
|
|
5
|
+
Renders and parses the markdown and JSON glossaries coinagerie writes, and compares them with the vocabulary of the codebase to name the words that are missing or stale.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @coinagerie/output
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Test
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
nx run coinagerie-output:vitest
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 👔 Conformetry
|
|
18
|
+
|
|
19
|
+
This project was generated from the [nestjs-service-project](../../configuration/conformetry-templates/nestjs-service-project) conformetry template.
|
|
20
|
+
|
|
21
|
+
<!-- coinagerie:start -->
|
|
22
|
+
|
|
23
|
+
## 🪙 Coinagerie
|
|
24
|
+
|
|
25
|
+
The words this package uses that the root glossary does not define, regenerated with `nx run coinagerie-output:coinagerie-check:write`.
|
|
26
|
+
|
|
27
|
+
- **anchor**:
|
|
28
|
+
- **boundary**:
|
|
29
|
+
- **breadth**:
|
|
30
|
+
- **bullet**:
|
|
31
|
+
- **comparison**:
|
|
32
|
+
- **continuation**:
|
|
33
|
+
- **deliver**:
|
|
34
|
+
- **delivery**:
|
|
35
|
+
- **destination**:
|
|
36
|
+
- **flush**:
|
|
37
|
+
- **glossary**:
|
|
38
|
+
- **hand**:
|
|
39
|
+
- **lone**:
|
|
40
|
+
- **malformed**:
|
|
41
|
+
- **preamble**:
|
|
42
|
+
- **reconcile**:
|
|
43
|
+
- **refuse**:
|
|
44
|
+
- **reload**:
|
|
45
|
+
- **splice**:
|
|
46
|
+
- **stale**:
|
|
47
|
+
- **structural**:
|
|
48
|
+
- **tokenize**:
|
|
49
|
+
- **unmock**:
|
|
50
|
+
- **unsorted**:
|
|
51
|
+
- **vocabulary**:
|
|
52
|
+
|
|
53
|
+
<!-- coinagerie:end -->
|
|
54
|
+
|
|
55
|
+
<!-- callidescope:start -->
|
|
56
|
+
|
|
57
|
+
## 🔭 Callidescope
|
|
58
|
+
|
|
59
|
+
Call stacks traced through `projects/ic-suite/coinagerie/coinagerie-output`, deepest first. Each frame shows what it takes, what it returns, and what its documentation says.
|
|
60
|
+
|
|
61
|
+
| Measure | Value |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| Callables | 53 |
|
|
64
|
+
| Files | 24 |
|
|
65
|
+
| Calls traced | 69 |
|
|
66
|
+
| Call stacks | 0 |
|
|
67
|
+
| Deepest stack | 0 |
|
|
68
|
+
| Stacks through recursion | 0 |
|
|
69
|
+
| Unfollowable calls | 0 |
|
|
70
|
+
|
|
71
|
+
### Limits
|
|
72
|
+
|
|
73
|
+
What this project is judged against, as declared in its own `callidescope.config.ts`.
|
|
74
|
+
|
|
75
|
+
| Limit | Value |
|
|
76
|
+
| --- | --- |
|
|
77
|
+
| `maximumDepth` | 10 |
|
|
78
|
+
| `maximumBreadth` | 4 |
|
|
79
|
+
|
|
80
|
+
### Call stacks (depth)
|
|
81
|
+
|
|
82
|
+
None.
|
|
83
|
+
|
|
84
|
+
### Breadth
|
|
85
|
+
|
|
86
|
+
| Callable | Breadth | Calls directly | Location |
|
|
87
|
+
| --- | --- | --- | --- |
|
|
88
|
+
| `JsonService.parse` | 4 | `JsonService.parseJson`, `JsonService.isObject`, `JsonService.fail`, `JsonService.refuseDuplicates` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/json/json.service.ts:176` |
|
|
89
|
+
| `DeliveryService.contentFor` | 4 | `JsonService.write`, `MarkdownService.write`, `DeliveryService.handlerFor`, `ComparisonService.reconcile` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/delivery/delivery.service.ts:55` |
|
|
90
|
+
| `MarkdownService.readDescription` | 3 | `MarkdownService.findAnchors`, `MarkdownService.findIndex(…)`, `MarkdownService.filter(…)` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/markdown/markdown.service.ts:156` |
|
|
91
|
+
|
|
92
|
+
<details>
|
|
93
|
+
<summary>30 more callables</summary>
|
|
94
|
+
|
|
95
|
+
| Callable | Breadth | Calls directly | Location |
|
|
96
|
+
| --- | --- | --- | --- |
|
|
97
|
+
| `MarkdownService.parse` | 3 | `MarkdownService.findAnchors`, `MarkdownService.forEach(…)`, `MarkdownService.flush` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/markdown/markdown.service.ts:212` |
|
|
98
|
+
| `MarkdownService.write` | 3 | `MarkdownService.splice`, `MarkdownService.render`, `MarkdownService.readDescription` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/markdown/markdown.service.ts:300` |
|
|
99
|
+
| `DeliveryService.map(…)` | 3 | `JsonService.read`, `MarkdownService.read`, `DeliveryService.handlerFor` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/delivery/delivery.service.ts:84` |
|
|
100
|
+
| `ComparisonService.compare` | 2 | `ComparisonService.filter(…)`, `ComparisonService.filter(…)` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/comparison/comparison.service.ts:26` |
|
|
101
|
+
| `JsonService.endOfToken` | 2 | `JsonService.endOfString`, `JsonService.isBoundary` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/json/json.service.ts:46` |
|
|
102
|
+
| `JsonService.refuseDuplicates` | 2 | `JsonService.tokenize`, `JsonService.fail` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/json/json.service.ts:108` |
|
|
103
|
+
| `JsonService.render` | 2 | `JsonService.map(…)`, `JsonService.toSorted(…)` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/json/json.service.ts:215` |
|
|
104
|
+
| `MarkdownService.findAnchors` | 2 | `MarkdownService.indexesOf`, `MarkdownService.fail` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/markdown/markdown.service.ts:64` |
|
|
105
|
+
| `MarkdownService.readBullet` | 2 | `MarkdownService.fail`, `MarkdownService.flush` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/markdown/markdown.service.ts:110` |
|
|
106
|
+
| `MarkdownService.readContinuation` | 2 | `MarkdownService.fail`, `MarkdownService.from(…)` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/markdown/markdown.service.ts:136` |
|
|
107
|
+
| `MarkdownService.readLine` | 2 | `MarkdownService.readBullet`, `MarkdownService.readContinuation` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/markdown/markdown.service.ts:173` |
|
|
108
|
+
| `MarkdownService.render` | 2 | `MarkdownService.map(…)`, `MarkdownService.toSorted(…)` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/markdown/markdown.service.ts:245` |
|
|
109
|
+
| `DeliveryService.check` | 2 | `DeliveryService.map(…)`, `DeliveryService.readAll` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/delivery/delivery.service.ts:102` |
|
|
110
|
+
| `DeliveryService.write` | 2 | `DeliveryService.map(…)`, `DeliveryService.readAll` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/delivery/delivery.service.ts:113` |
|
|
111
|
+
| `DeliveryService.map(…)` | 2 | `DeliveryService.contentFor`, `DeliveryService.differenceOf` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/delivery/delivery.service.ts:114` |
|
|
112
|
+
| `ComparisonService.reconcile` | 1 | `ComparisonService.map(…)` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/comparison/comparison.service.ts:42` |
|
|
113
|
+
| `JsonService.fail` | 1 | `MalformedGlossaryError.constructor` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/json/json.service.ts:67` |
|
|
114
|
+
| `JsonService.parseJson` | 1 | `JsonService.fail` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/json/json.service.ts:90` |
|
|
115
|
+
| `JsonService.tokenize` | 1 | `JsonService.endOfToken` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/json/json.service.ts:150` |
|
|
116
|
+
| `JsonService.read` | 1 | `JsonService.parse` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/json/json.service.ts:202` |
|
|
117
|
+
| `JsonService.write` | 1 | `JsonService.render` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/json/json.service.ts:227` |
|
|
118
|
+
| `MarkdownService.fail` | 1 | `MalformedGlossaryError.constructor` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/markdown/markdown.service.ts:50` |
|
|
119
|
+
| `MarkdownService.indexesOf` | 1 | `MarkdownService.flatMap(…)` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/markdown/markdown.service.ts:68` |
|
|
120
|
+
| `MarkdownService.forEach(…)` | 1 | `MarkdownService.readLine` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/markdown/markdown.service.ts:228` |
|
|
121
|
+
| `MarkdownService.read` | 1 | `MarkdownService.parse` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/markdown/markdown.service.ts:237` |
|
|
122
|
+
| `MarkdownService.map(…)` | 1 | `MarkdownService.renderBullet` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/markdown/markdown.service.ts:253` |
|
|
123
|
+
| `MarkdownService.splice` | 1 | `MarkdownService.findAnchors` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/markdown/markdown.service.ts:269` |
|
|
124
|
+
| `DeliveryService.differenceOf` | 1 | `ComparisonService.compare` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/delivery/delivery.service.ts:64` |
|
|
125
|
+
| `DeliveryService.readAll` | 1 | `DeliveryService.map(…)` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/delivery/delivery.service.ts:83` |
|
|
126
|
+
| `DeliveryService.map(…)` | 1 | `DeliveryService.differenceOf` | `projects/ic-suite/coinagerie/coinagerie-output/src/modules/delivery/delivery.service.ts:103` |
|
|
127
|
+
|
|
128
|
+
</details>
|
|
129
|
+
<!-- callidescope:end -->
|
|
130
|
+
|
|
131
|
+
## 🕸️ Codependix
|
|
132
|
+
|
|
133
|
+
Dependency graphs exported by [codependix](https://github.com/Organizzolini/codebase/tree/main/projects/ic-suite/codependix/codependix-cli), regenerated by `nx run configuration:codependix:write`.
|
|
134
|
+
|
|
135
|
+
### Nx Neighborhood
|
|
136
|
+
|
|
137
|
+
<!-- codependix:start name="codependix-nx-projects" -->
|
|
138
|
+
```mermaid
|
|
139
|
+
graph LR
|
|
140
|
+
coinagerie_cli["coinagerie-cli"]
|
|
141
|
+
coinagerie_configuration["coinagerie-configuration"]
|
|
142
|
+
coinagerie_core["coinagerie-core"]
|
|
143
|
+
coinagerie_output["coinagerie-output"]
|
|
144
|
+
coinagerie_cli --> coinagerie_output
|
|
145
|
+
coinagerie_output --> coinagerie_configuration
|
|
146
|
+
coinagerie_output --> coinagerie_core
|
|
147
|
+
classDef subject fill:#7c3aed,color:#fff,stroke:#4c1d95,stroke-width:2px
|
|
148
|
+
class coinagerie_output subject
|
|
149
|
+
```
|
|
150
|
+
<!-- codependix:end name="codependix-nx-projects" -->
|
|
151
|
+
|
|
152
|
+
### NestJS Module Graph
|
|
153
|
+
|
|
154
|
+
<!-- codependix:start name="codependix-nestjs-modules" -->
|
|
155
|
+
```mermaid
|
|
156
|
+
flowchart LR
|
|
157
|
+
ComparisonModule
|
|
158
|
+
DeliveryModule
|
|
159
|
+
JsonModule
|
|
160
|
+
MarkdownModule
|
|
161
|
+
DeliveryModule --> ComparisonModule
|
|
162
|
+
DeliveryModule --> JsonModule
|
|
163
|
+
DeliveryModule --> MarkdownModule
|
|
164
|
+
```
|
|
165
|
+
<!-- codependix:end name="codependix-nestjs-modules" -->
|
|
166
|
+
|
|
167
|
+
### File Imports
|
|
168
|
+
|
|
169
|
+
<!-- codependix:start name="codependix-file-imports" -->
|
|
170
|
+
```mermaid
|
|
171
|
+
graph LR
|
|
172
|
+
file_callidescope_config_ts["callidescope.config.ts"]
|
|
173
|
+
file_codependix_config_ts["codependix.config.ts"]
|
|
174
|
+
file_codometer_config_ts["codometer.config.ts"]
|
|
175
|
+
file_coinagerie_config_ts["coinagerie.config.ts"]
|
|
176
|
+
file_eslint_config_ts["eslint.config.ts"]
|
|
177
|
+
file_src_index_ts["src/index.ts"]
|
|
178
|
+
file_src_index_unit_test_ts["src/index.unit.test.ts"]
|
|
179
|
+
file_src_modules_comparison_comparison_constants_ts["src/modules/comparison/comparison.constants.ts"]
|
|
180
|
+
file_src_modules_comparison_comparison_module_ts["src/modules/comparison/comparison.module.ts"]
|
|
181
|
+
file_src_modules_comparison_comparison_service_ts["src/modules/comparison/comparison.service.ts"]
|
|
182
|
+
file_src_modules_comparison_comparison_service_unit_test_ts["src/modules/comparison/comparison.service.unit.test.ts"]
|
|
183
|
+
file_src_modules_comparison_comparison_types_ts["src/modules/comparison/comparison.types.ts"]
|
|
184
|
+
file_src_modules_delivery_delivery_constants_ts["src/modules/delivery/delivery.constants.ts"]
|
|
185
|
+
file_src_modules_delivery_delivery_module_ts["src/modules/delivery/delivery.module.ts"]
|
|
186
|
+
file_src_modules_delivery_delivery_service_ts["src/modules/delivery/delivery.service.ts"]
|
|
187
|
+
file_src_modules_delivery_delivery_service_unit_test_ts["src/modules/delivery/delivery.service.unit.test.ts"]
|
|
188
|
+
file_src_modules_delivery_delivery_types_ts["src/modules/delivery/delivery.types.ts"]
|
|
189
|
+
file_src_modules_json_json_constants_ts["src/modules/json/json.constants.ts"]
|
|
190
|
+
file_src_modules_json_json_module_ts["src/modules/json/json.module.ts"]
|
|
191
|
+
file_src_modules_json_json_service_ts["src/modules/json/json.service.ts"]
|
|
192
|
+
file_src_modules_json_json_service_unit_test_ts["src/modules/json/json.service.unit.test.ts"]
|
|
193
|
+
file_src_modules_json_json_types_ts["src/modules/json/json.types.ts"]
|
|
194
|
+
file_src_modules_markdown_markdown_constants_ts["src/modules/markdown/markdown.constants.ts"]
|
|
195
|
+
file_src_modules_markdown_markdown_module_ts["src/modules/markdown/markdown.module.ts"]
|
|
196
|
+
file_src_modules_markdown_markdown_service_ts["src/modules/markdown/markdown.service.ts"]
|
|
197
|
+
file_src_modules_markdown_markdown_service_unit_test_ts["src/modules/markdown/markdown.service.unit.test.ts"]
|
|
198
|
+
file_src_modules_markdown_markdown_types_ts["src/modules/markdown/markdown.types.ts"]
|
|
199
|
+
file_testing_mocks_ts["testing/mocks.ts"]
|
|
200
|
+
file_testing_setup_ts["testing/setup.ts"]
|
|
201
|
+
file_vite_config_ts["vite.config.ts"]
|
|
202
|
+
file_vitest_config_ts["vitest.config.ts"]
|
|
203
|
+
file_src_index_unit_test_ts --> file_src_index_ts
|
|
204
|
+
file_src_modules_comparison_comparison_module_ts --> file_src_modules_comparison_comparison_service_ts
|
|
205
|
+
file_src_modules_comparison_comparison_service_ts --> file_src_modules_comparison_comparison_types_ts
|
|
206
|
+
file_src_modules_comparison_comparison_service_unit_test_ts --> file_src_modules_comparison_comparison_service_ts
|
|
207
|
+
file_src_modules_delivery_delivery_module_ts --> file_src_modules_comparison_comparison_module_ts
|
|
208
|
+
file_src_modules_delivery_delivery_module_ts --> file_src_modules_delivery_delivery_service_ts
|
|
209
|
+
file_src_modules_delivery_delivery_module_ts --> file_src_modules_json_json_module_ts
|
|
210
|
+
file_src_modules_delivery_delivery_module_ts --> file_src_modules_markdown_markdown_module_ts
|
|
211
|
+
file_src_modules_delivery_delivery_service_ts --> file_src_modules_comparison_comparison_service_ts
|
|
212
|
+
file_src_modules_delivery_delivery_service_ts --> file_src_modules_delivery_delivery_types_ts
|
|
213
|
+
file_src_modules_delivery_delivery_service_ts --> file_src_modules_json_json_service_ts
|
|
214
|
+
file_src_modules_delivery_delivery_service_ts --> file_src_modules_markdown_markdown_service_ts
|
|
215
|
+
file_src_modules_delivery_delivery_service_unit_test_ts --> file_src_modules_comparison_comparison_module_ts
|
|
216
|
+
file_src_modules_delivery_delivery_service_unit_test_ts --> file_src_modules_delivery_delivery_service_ts
|
|
217
|
+
file_src_modules_delivery_delivery_service_unit_test_ts --> file_src_modules_json_json_module_ts
|
|
218
|
+
file_src_modules_delivery_delivery_service_unit_test_ts --> file_src_modules_markdown_markdown_module_ts
|
|
219
|
+
file_src_modules_json_json_module_ts --> file_src_modules_json_json_service_ts
|
|
220
|
+
file_src_modules_json_json_service_ts --> file_src_modules_delivery_delivery_types_ts
|
|
221
|
+
file_src_modules_json_json_service_ts --> file_src_modules_json_json_constants_ts
|
|
222
|
+
file_src_modules_json_json_service_ts --> file_src_modules_json_json_types_ts
|
|
223
|
+
file_src_modules_json_json_service_unit_test_ts --> file_src_modules_json_json_service_ts
|
|
224
|
+
file_src_modules_markdown_markdown_module_ts --> file_src_modules_markdown_markdown_service_ts
|
|
225
|
+
file_src_modules_markdown_markdown_service_ts --> file_src_modules_delivery_delivery_types_ts
|
|
226
|
+
file_src_modules_markdown_markdown_service_ts --> file_src_modules_markdown_markdown_constants_ts
|
|
227
|
+
file_src_modules_markdown_markdown_service_ts --> file_src_modules_markdown_markdown_types_ts
|
|
228
|
+
file_src_modules_markdown_markdown_service_unit_test_ts --> file_src_modules_markdown_markdown_service_ts
|
|
229
|
+
```
|
|
230
|
+
<!-- codependix:end name="codependix-file-imports" -->
|
|
231
|
+
|
|
232
|
+
<!-- codometer:start -->
|
|
233
|
+
|
|
234
|
+
## ⏲️ Codometer
|
|
235
|
+
|
|
236
|
+
### Project
|
|
237
|
+
|
|
238
|
+

|
|
239
|
+

|
|
240
|
+

|
|
241
|
+

|
|
242
|
+
|
|
243
|
+
### TypeScript
|
|
244
|
+
|
|
245
|
+

|
|
246
|
+

|
|
247
|
+

|
|
248
|
+

|
|
249
|
+

|
|
250
|
+

|
|
251
|
+

|
|
252
|
+
|
|
253
|
+
### JavaScript
|
|
254
|
+
|
|
255
|
+

|
|
256
|
+

|
|
257
|
+

|
|
258
|
+

|
|
259
|
+

|
|
260
|
+

|
|
261
|
+

|
|
262
|
+

|
|
263
|
+

|
|
264
|
+

|
|
265
|
+

|
|
266
|
+

|
|
267
|
+

|
|
268
|
+

|
|
269
|
+
|
|
270
|
+
### Python
|
|
271
|
+
|
|
272
|
+

|
|
273
|
+

|
|
274
|
+

|
|
275
|
+

|
|
276
|
+

|
|
277
|
+

|
|
278
|
+

|
|
279
|
+

|
|
280
|
+

|
|
281
|
+

|
|
282
|
+

|
|
283
|
+

|
|
284
|
+
|
|
285
|
+
### JSON
|
|
286
|
+
|
|
287
|
+

|
|
288
|
+

|
|
289
|
+

|
|
290
|
+

|
|
291
|
+

|
|
292
|
+

|
|
293
|
+

|
|
294
|
+

|
|
295
|
+

|
|
296
|
+

|
|
297
|
+

|
|
298
|
+

|
|
299
|
+
|
|
300
|
+
### YAML
|
|
301
|
+
|
|
302
|
+

|
|
303
|
+

|
|
304
|
+

|
|
305
|
+

|
|
306
|
+

|
|
307
|
+

|
|
308
|
+

|
|
309
|
+

|
|
310
|
+

|
|
311
|
+

|
|
312
|
+

|
|
313
|
+
|
|
314
|
+
### TOML
|
|
315
|
+
|
|
316
|
+

|
|
317
|
+

|
|
318
|
+

|
|
319
|
+

|
|
320
|
+

|
|
321
|
+

|
|
322
|
+

|
|
323
|
+
|
|
324
|
+
### Shell
|
|
325
|
+
|
|
326
|
+

|
|
327
|
+

|
|
328
|
+

|
|
329
|
+

|
|
330
|
+

|
|
331
|
+

|
|
332
|
+

|
|
333
|
+

|
|
334
|
+

|
|
335
|
+

|
|
336
|
+

|
|
337
|
+
|
|
338
|
+
### SQL
|
|
339
|
+
|
|
340
|
+

|
|
341
|
+

|
|
342
|
+

|
|
343
|
+

|
|
344
|
+

|
|
345
|
+

|
|
346
|
+

|
|
347
|
+

|
|
348
|
+

|
|
349
|
+

|
|
350
|
+

|
|
351
|
+
|
|
352
|
+
### HCL
|
|
353
|
+
|
|
354
|
+

|
|
355
|
+

|
|
356
|
+

|
|
357
|
+

|
|
358
|
+

|
|
359
|
+

|
|
360
|
+

|
|
361
|
+

|
|
362
|
+

|
|
363
|
+
|
|
364
|
+
### CSS
|
|
365
|
+
|
|
366
|
+

|
|
367
|
+

|
|
368
|
+

|
|
369
|
+

|
|
370
|
+

|
|
371
|
+

|
|
372
|
+

|
|
373
|
+

|
|
374
|
+

|
|
375
|
+
|
|
376
|
+
### Conventions
|
|
377
|
+
|
|
378
|
+

|
|
379
|
+

|
|
380
|
+

|
|
381
|
+

|
|
382
|
+

|
|
383
|
+

|
|
384
|
+

|
|
385
|
+

|
|
386
|
+

|
|
387
|
+

|
|
388
|
+

|
|
389
|
+

|
|
390
|
+

|
|
391
|
+

|
|
392
|
+

|
|
393
|
+

|
|
394
|
+

|
|
395
|
+

|
|
396
|
+
|
|
397
|
+
### Jupyter
|
|
398
|
+
|
|
399
|
+

|
|
400
|
+

|
|
401
|
+

|
|
402
|
+

|
|
403
|
+

|
|
404
|
+

|
|
405
|
+

|
|
406
|
+

|
|
407
|
+

|
|
408
|
+

|
|
409
|
+

|
|
410
|
+

|
|
411
|
+

|
|
412
|
+

|
|
413
|
+

|
|
414
|
+

|
|
415
|
+

|
|
416
|
+

|
|
417
|
+

|
|
418
|
+

|
|
419
|
+
|
|
420
|
+
### Markdown
|
|
421
|
+
|
|
422
|
+

|
|
423
|
+

|
|
424
|
+

|
|
425
|
+

|
|
426
|
+

|
|
427
|
+

|
|
428
|
+

|
|
429
|
+

|
|
430
|
+

|
|
431
|
+

|
|
432
|
+

|
|
433
|
+

|
|
434
|
+

|
|
435
|
+

|
|
436
|
+

|
|
437
|
+

|
|
438
|
+

|
|
439
|
+

|
|
440
|
+

|
|
441
|
+

|
|
442
|
+
<!-- codometer:end -->
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { Glossary } from '@coinagerie/core';
|
|
2
|
+
import { GlossaryDifference } from '@coinagerie/core';
|
|
3
|
+
import { ResolvedCoinagerieOutput } from '@coinagerie/configuration';
|
|
4
|
+
|
|
5
|
+
/** How a glossary disagrees with the vocabulary; both lists sorted. */
|
|
6
|
+
export declare interface Comparison {
|
|
7
|
+
/** Words the vocabulary has that the glossary does not list. */
|
|
8
|
+
missing: string[];
|
|
9
|
+
/** Words the glossary lists that the vocabulary no longer has. */
|
|
10
|
+
stale: string[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Provides the comparison of a glossary with the codebase's vocabulary.
|
|
15
|
+
*/
|
|
16
|
+
export declare class ComparisonModule {
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Compares a glossary with the codebase's vocabulary, and reconciles one to
|
|
21
|
+
* the other. Only words are compared: an empty definition is never a
|
|
22
|
+
* disagreement.
|
|
23
|
+
*/
|
|
24
|
+
export declare class ComparisonService {
|
|
25
|
+
constructor();
|
|
26
|
+
/** The words missing from the glossary and the words stale in it. */
|
|
27
|
+
compare(words: string[], glossary: Glossary): Comparison;
|
|
28
|
+
/**
|
|
29
|
+
* The glossary as `--write` leaves it: exactly the vocabulary, sorted, each
|
|
30
|
+
* word keeping the definition it had and a new word starting empty. Stale
|
|
31
|
+
* words are dropped with their definitions.
|
|
32
|
+
*/
|
|
33
|
+
reconcile(words: string[], glossary: Glossary): Glossary;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** What `check` and `write` are asked to do. */
|
|
37
|
+
export declare interface DeliverArguments {
|
|
38
|
+
destinations: ResolvedCoinagerieOutput[];
|
|
39
|
+
/** The codebase's vocabulary, sorted and de-duplicated. */
|
|
40
|
+
words: string[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Provides checking and writing every glossary destination, wired to every
|
|
45
|
+
* format a destination can be written in.
|
|
46
|
+
*/
|
|
47
|
+
export declare class DeliveryModule {
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** How one destination differed, and whether `write` changed its file. */
|
|
51
|
+
export declare interface DeliveryResult extends GlossaryDifference {
|
|
52
|
+
/** False when the file already held exactly what would be written. */
|
|
53
|
+
written: boolean;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Checks and writes every configured glossary destination.
|
|
58
|
+
*
|
|
59
|
+
* Every destination is read and parsed before any is written, so one that
|
|
60
|
+
* cannot be parsed stops the run with every file untouched. Destinations are
|
|
61
|
+
* independent: each is compared with the vocabulary alone, and no definition
|
|
62
|
+
* is ever copied from one to another.
|
|
63
|
+
*/
|
|
64
|
+
export declare class DeliveryService {
|
|
65
|
+
private readonly comparisonService;
|
|
66
|
+
constructor(comparisonService: ComparisonService, jsonService: JsonService, markdownService: MarkdownService);
|
|
67
|
+
/**
|
|
68
|
+
* Each destination type to the format that reads and writes it. A record
|
|
69
|
+
* rather than a map, so adding a destination type fails to compile until
|
|
70
|
+
* its format is registered here.
|
|
71
|
+
*/
|
|
72
|
+
private readonly handlers;
|
|
73
|
+
/** What a destination's file holds once written with exactly the words. */
|
|
74
|
+
private contentFor;
|
|
75
|
+
/** How one read destination differs from the vocabulary. */
|
|
76
|
+
private differenceOf;
|
|
77
|
+
/** The format a destination is written in. */
|
|
78
|
+
private handlerFor;
|
|
79
|
+
/** Reads and parses every destination, throwing before anything is written. */
|
|
80
|
+
private readAll;
|
|
81
|
+
/**
|
|
82
|
+
* How each destination differs from the vocabulary, writing nothing. A
|
|
83
|
+
* destination that does not exist yet is missing every word.
|
|
84
|
+
*/
|
|
85
|
+
check(args: DeliverArguments): GlossaryDifference[];
|
|
86
|
+
/**
|
|
87
|
+
* Rewrites every destination to hold exactly the vocabulary, keeping every
|
|
88
|
+
* definition still in use. A file already holding exactly that is not
|
|
89
|
+
* touched, so a second write changes nothing.
|
|
90
|
+
*/
|
|
91
|
+
write(args: DeliverArguments): DeliveryResult[];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* What every glossary format provides to delivery: reading a glossary out of
|
|
96
|
+
* a file's content, and writing one back into it.
|
|
97
|
+
*
|
|
98
|
+
* `read` is handed `undefined` for a file that does not exist, returns
|
|
99
|
+
* `undefined` when the content holds no glossary yet, and throws
|
|
100
|
+
* `MalformedGlossaryError` when it holds one it cannot fully parse. `write`
|
|
101
|
+
* returns the file's whole new content, keeping whatever else the file held.
|
|
102
|
+
*/
|
|
103
|
+
export declare interface GlossaryFormatHandler {
|
|
104
|
+
read(content: string | undefined, filePath: string): Glossary | undefined;
|
|
105
|
+
write(args: WriteGlossaryArguments): string;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Provides the JSON glossary format: rendering and strictly parsing a flat
|
|
110
|
+
* object of words and definitions.
|
|
111
|
+
*/
|
|
112
|
+
export declare class JsonModule {
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Renders and parses the JSON glossary: a flat object sorted by word, each
|
|
117
|
+
* value the definition or `""` when there is none yet.
|
|
118
|
+
*
|
|
119
|
+
* The whole file is the glossary, so writing replaces it. Parsing is strict
|
|
120
|
+
* on purpose, like the markdown format: anything it cannot read is refused
|
|
121
|
+
* rather than dropped, because a dropped word reads as stale and writing
|
|
122
|
+
* would delete its definition.
|
|
123
|
+
*/
|
|
124
|
+
export declare class JsonService implements GlossaryFormatHandler {
|
|
125
|
+
constructor();
|
|
126
|
+
/** Where the string opening at `start` ends, past its closing quote. */
|
|
127
|
+
private endOfString;
|
|
128
|
+
/** Where the token starting at `start` ends. */
|
|
129
|
+
private endOfToken;
|
|
130
|
+
/** Fails a parse, naming the file and, when known, the one-indexed line. */
|
|
131
|
+
private fail;
|
|
132
|
+
/** Whether a character ends a run of literal characters. */
|
|
133
|
+
private isBoundary;
|
|
134
|
+
/** Whether a parsed value is an object, as opposed to an array or `null`. */
|
|
135
|
+
private isObject;
|
|
136
|
+
/** The parsed value, refusing content that is not valid JSON. */
|
|
137
|
+
private parseJson;
|
|
138
|
+
/**
|
|
139
|
+
* Refuses a word listed twice, which `JSON.parse` would resolve silently
|
|
140
|
+
* by keeping the last definition and dropping the first.
|
|
141
|
+
*
|
|
142
|
+
* Walks the tokens of content already known to be an object, reading the
|
|
143
|
+
* first string after the opening brace or after a top-level comma as a key.
|
|
144
|
+
*/
|
|
145
|
+
private refuseDuplicates;
|
|
146
|
+
/**
|
|
147
|
+
* The tokens of content already known to be valid JSON: a string with its
|
|
148
|
+
* quotes and escapes, a bracket, comma, or colon, or any other run of
|
|
149
|
+
* literal characters. Whitespace is skipped.
|
|
150
|
+
*
|
|
151
|
+
* Enough to walk an object's top level and tell its keys from its values,
|
|
152
|
+
* which is what lets a duplicated key be found: `JSON.parse` keeps only the
|
|
153
|
+
* last, whatever type the first one had. Scanned by hand in one pass, since
|
|
154
|
+
* a regular expression for strings backtracks on input it cannot finish.
|
|
155
|
+
*/
|
|
156
|
+
private tokenize;
|
|
157
|
+
/**
|
|
158
|
+
* The glossary a file holds.
|
|
159
|
+
*
|
|
160
|
+
* Throws `MalformedGlossaryError` on invalid JSON, anything but an object,
|
|
161
|
+
* a value that is not a string, or a word listed twice.
|
|
162
|
+
*/
|
|
163
|
+
parse(content: string, filePath: string): Glossary;
|
|
164
|
+
/**
|
|
165
|
+
* Reads a destination's glossary; a missing or blank file holds none.
|
|
166
|
+
*/
|
|
167
|
+
read(content: string | undefined, filePath: string): Glossary | undefined;
|
|
168
|
+
/**
|
|
169
|
+
* The whole file: one word per line, sorted by code unit whatever order
|
|
170
|
+
* the glossary holds them in, ending in a newline.
|
|
171
|
+
*
|
|
172
|
+
* Written out entry by entry rather than through an object, because an
|
|
173
|
+
* object would reorder a key that looks like an array index.
|
|
174
|
+
*/
|
|
175
|
+
render(glossary: Glossary): string;
|
|
176
|
+
/** The destination's whole new content: nothing else is kept. */
|
|
177
|
+
write(args: WriteGlossaryArguments): string;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Provides the markdown glossary format: rendering, parsing, and splicing the
|
|
182
|
+
* anchored bullet block.
|
|
183
|
+
*/
|
|
184
|
+
export declare class MarkdownModule {
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Renders, parses, and splices the markdown glossary block.
|
|
189
|
+
*
|
|
190
|
+
* The block is the `## 🪙 Coinagerie` heading, an optional description, and
|
|
191
|
+
* one `- **word**: definition` bullet per word, between the
|
|
192
|
+
* `coinagerie:start` and `coinagerie:end` anchors. A definition continues on
|
|
193
|
+
* indented lines below its bullet, kept verbatim. Parsing is strict on
|
|
194
|
+
* purpose: anything it cannot read is refused rather than dropped, because a
|
|
195
|
+
* dropped word reads as stale and writing would delete its definition.
|
|
196
|
+
*/
|
|
197
|
+
export declare class MarkdownService implements GlossaryFormatHandler {
|
|
198
|
+
constructor();
|
|
199
|
+
/** Fails a parse, naming the file and the one-indexed line. */
|
|
200
|
+
private fail;
|
|
201
|
+
/**
|
|
202
|
+
* Where the block sits, or `undefined` when the file has no anchors.
|
|
203
|
+
*
|
|
204
|
+
* Exactly one start anchor followed by exactly one end anchor; any other
|
|
205
|
+
* arrangement is refused.
|
|
206
|
+
*/
|
|
207
|
+
private findAnchors;
|
|
208
|
+
/** Stores the word being read, with its definition, and forgets it. */
|
|
209
|
+
private flush;
|
|
210
|
+
/** Reads one bullet, starting a new word. */
|
|
211
|
+
private readBullet;
|
|
212
|
+
/**
|
|
213
|
+
* Adds an indented line, and any blank lines above it, to the definition
|
|
214
|
+
* being read; anything else in the bullet list is refused.
|
|
215
|
+
*/
|
|
216
|
+
private readContinuation;
|
|
217
|
+
/**
|
|
218
|
+
* The prose between a block's heading and its first bullet, or `undefined`
|
|
219
|
+
* when there is none. Only ever read from content `parse` already accepted.
|
|
220
|
+
*/
|
|
221
|
+
private readDescription;
|
|
222
|
+
/** Reads one line of the block, or refuses it. */
|
|
223
|
+
private readLine;
|
|
224
|
+
/** One word's bullet, with its definition after the colon. */
|
|
225
|
+
private renderBullet;
|
|
226
|
+
/**
|
|
227
|
+
* The glossary in a file's block, or `undefined` when it has no anchors.
|
|
228
|
+
*
|
|
229
|
+
* Throws `MalformedGlossaryError` on an unrecognized line, a duplicated
|
|
230
|
+
* word, or misplaced anchors. Free text between the heading and the first
|
|
231
|
+
* bullet is the description: never a word, and kept by `write`.
|
|
232
|
+
*/
|
|
233
|
+
parse(content: string, filePath: string): Glossary | undefined;
|
|
234
|
+
/** Reads a destination's glossary; a missing file holds none. */
|
|
235
|
+
read(content: string | undefined, filePath: string): Glossary | undefined;
|
|
236
|
+
/**
|
|
237
|
+
* The whole block, anchors included, with no trailing newline. Words are
|
|
238
|
+
* rendered sorted, whatever order the glossary holds them in.
|
|
239
|
+
*/
|
|
240
|
+
render(args: RenderMarkdownArguments): string;
|
|
241
|
+
/**
|
|
242
|
+
* A file's content with the block in place: replacing the anchored block
|
|
243
|
+
* when there is one, appending it after a blank line when there is not,
|
|
244
|
+
* and standing alone in a file that is empty or does not exist.
|
|
245
|
+
*/
|
|
246
|
+
splice(content: string | undefined, block: string): string;
|
|
247
|
+
/**
|
|
248
|
+
* Writes a glossary into a destination's content as a rendered block.
|
|
249
|
+
*
|
|
250
|
+
* The configured description wins; without one, whatever prose already
|
|
251
|
+
* sits between the heading and the first bullet is kept, so a write never
|
|
252
|
+
* deletes text a person wrote there.
|
|
253
|
+
*/
|
|
254
|
+
write(args: WriteGlossaryArguments): string;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** What a markdown block is rendered from. */
|
|
258
|
+
export declare interface RenderMarkdownArguments {
|
|
259
|
+
/** Rendered under the heading when present. */
|
|
260
|
+
description?: string | undefined;
|
|
261
|
+
glossary: Glossary;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** What a format writes a glossary from. */
|
|
265
|
+
export declare interface WriteGlossaryArguments {
|
|
266
|
+
/** The file's current content, or `undefined` when it does not exist. */
|
|
267
|
+
content: string | undefined;
|
|
268
|
+
destination: ResolvedCoinagerieOutput;
|
|
269
|
+
/** The glossary to write, already reconciled and sorted. */
|
|
270
|
+
glossary: Glossary;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export { }
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { Injectable as e, Module as t } from "@nestjs/common";
|
|
2
|
+
import { COINAGERIE_END_ANCHOR as n, COINAGERIE_HEADING as r, COINAGERIE_START_ANCHOR as i, MalformedGlossaryError as a } from "@coinagerie/core";
|
|
3
|
+
import { existsSync as o, mkdirSync as s, readFileSync as c, writeFileSync as l } from "node:fs";
|
|
4
|
+
import u from "node:path";
|
|
5
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/decorateMetadata.js
|
|
6
|
+
function __decorateMetadata(e, t) {
|
|
7
|
+
if (typeof Reflect == "object" && typeof Reflect.metadata == "function") return Reflect.metadata(e, t);
|
|
8
|
+
}
|
|
9
|
+
// \0@oxc-project+runtime@0.155.0/helpers/esm/decorate.js
|
|
10
|
+
function __decorate(e, t, n, r) {
|
|
11
|
+
var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
|
|
12
|
+
if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
|
|
13
|
+
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);
|
|
14
|
+
return i > 3 && a && Object.defineProperty(t, n, a), a;
|
|
15
|
+
}
|
|
16
|
+
// src/modules/comparison/comparison.service.ts
|
|
17
|
+
var d = class ComparisonService {
|
|
18
|
+
constructor() {}
|
|
19
|
+
compare(e, t) {
|
|
20
|
+
let n = new Set(e);
|
|
21
|
+
return {
|
|
22
|
+
missing: e.filter((e) => !t.has(e)).toSorted(),
|
|
23
|
+
stale: [...t.keys()].filter((e) => !n.has(e)).toSorted()
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
reconcile(e, t) {
|
|
27
|
+
return new Map(e.toSorted().map((e) => [e, t.get(e) ?? ""]));
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
d = __decorate([e(), __decorateMetadata("design:paramtypes", [])], d);
|
|
31
|
+
// src/modules/comparison/comparison.module.ts
|
|
32
|
+
var f = class ComparisonModule {};
|
|
33
|
+
f = __decorate([t({
|
|
34
|
+
controllers: [],
|
|
35
|
+
exports: [d],
|
|
36
|
+
imports: [],
|
|
37
|
+
providers: [d]
|
|
38
|
+
})], f);
|
|
39
|
+
// src/modules/json/json.service.ts
|
|
40
|
+
var p = class JsonService {
|
|
41
|
+
constructor() {}
|
|
42
|
+
endOfString(e, t) {
|
|
43
|
+
let n = t + 1;
|
|
44
|
+
for (; n < e.length && e.charAt(n) !== "\"";) n += e.charAt(n) === "\\" ? 2 : 1;
|
|
45
|
+
return n + 1;
|
|
46
|
+
}
|
|
47
|
+
endOfToken(e, t) {
|
|
48
|
+
let n = e.charAt(t);
|
|
49
|
+
if (n === "\"") return this.endOfString(e, t);
|
|
50
|
+
if ("[]{},:".includes(n)) return t + 1;
|
|
51
|
+
let r = t + 1;
|
|
52
|
+
for (; r < e.length && !this.isBoundary(e.charAt(r));) r += 1;
|
|
53
|
+
return r;
|
|
54
|
+
}
|
|
55
|
+
fail(e, t, n) {
|
|
56
|
+
throw new a({
|
|
57
|
+
line: n,
|
|
58
|
+
path: e.filePath,
|
|
59
|
+
reason: t
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
isBoundary(e) {
|
|
63
|
+
return e === "\"" || "[]{},:".includes(e) || /\s/u.test(e);
|
|
64
|
+
}
|
|
65
|
+
isObject(e) {
|
|
66
|
+
return typeof e == "object" && !!e && !Array.isArray(e);
|
|
67
|
+
}
|
|
68
|
+
parseJson(e) {
|
|
69
|
+
try {
|
|
70
|
+
return JSON.parse(e.content);
|
|
71
|
+
} catch (t) {
|
|
72
|
+
return this.fail(e, `the file is not valid JSON (${String(t)})`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
refuseDuplicates(e) {
|
|
76
|
+
let t = /* @__PURE__ */ new Set(), n = 0, r = "";
|
|
77
|
+
for (let i of this.tokenize(e.content)) {
|
|
78
|
+
let { text: a } = i;
|
|
79
|
+
if (n === 1 && a.startsWith("\"") && (r === "{" || r === ",")) {
|
|
80
|
+
let n = String(JSON.parse(a));
|
|
81
|
+
t.has(n) && this.fail(e, `the word "${n}" is listed twice`, e.content.slice(0, i.index).split("\n").length), t.add(n);
|
|
82
|
+
}
|
|
83
|
+
n += +!!"{[".includes(a), n -= +!!"}]".includes(a), r = a;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
tokenize(e) {
|
|
87
|
+
let t = [], n = 0;
|
|
88
|
+
for (; n < e.length;) if (/\s/u.test(e.charAt(n))) n += 1;
|
|
89
|
+
else {
|
|
90
|
+
let r = this.endOfToken(e, n);
|
|
91
|
+
t.push({
|
|
92
|
+
index: n,
|
|
93
|
+
text: e.slice(n, r)
|
|
94
|
+
}), n = r;
|
|
95
|
+
}
|
|
96
|
+
return t;
|
|
97
|
+
}
|
|
98
|
+
parse(e, t) {
|
|
99
|
+
let n = {
|
|
100
|
+
content: e,
|
|
101
|
+
filePath: t
|
|
102
|
+
}, r = this.parseJson(n);
|
|
103
|
+
if (!this.isObject(r)) return this.fail(n, "the file must be an object of words");
|
|
104
|
+
this.refuseDuplicates(n);
|
|
105
|
+
let i = /* @__PURE__ */ new Map();
|
|
106
|
+
for (let [e, t] of Object.entries(r)) typeof t != "string" && this.fail(n, `the value of "${e}" is not a string`), i.set(e, t);
|
|
107
|
+
return i;
|
|
108
|
+
}
|
|
109
|
+
read(e, t) {
|
|
110
|
+
return e === void 0 || e.trim() === "" ? void 0 : this.parse(e, t);
|
|
111
|
+
}
|
|
112
|
+
render(e) {
|
|
113
|
+
let t = [...e].toSorted(([e], [t]) => e < t ? -1 : 1).map(([e, t]) => ` ${JSON.stringify(e)}: ${JSON.stringify(t)}`);
|
|
114
|
+
return t.length === 0 ? "{}\n" : `{\n${t.join(",\n")}\n}\n`;
|
|
115
|
+
}
|
|
116
|
+
write(e) {
|
|
117
|
+
return this.render(e.glossary);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
p = __decorate([e(), __decorateMetadata("design:paramtypes", [])], p);
|
|
121
|
+
// src/modules/json/json.module.ts
|
|
122
|
+
var m = class JsonModule {};
|
|
123
|
+
m = __decorate([t({
|
|
124
|
+
controllers: [],
|
|
125
|
+
exports: [p],
|
|
126
|
+
imports: [],
|
|
127
|
+
providers: [p]
|
|
128
|
+
})], m);
|
|
129
|
+
// src/modules/markdown/markdown.constants.ts
|
|
130
|
+
var h = /^- \*\*(?<word>[^*]+)\*\*:(?<rest>.*)$/u, g = /^[-*+]\s/u, _ = /\r?\n/u, v = /^[ \t]+\S/u, y = class MarkdownService {
|
|
131
|
+
constructor() {}
|
|
132
|
+
fail(e, t, n) {
|
|
133
|
+
throw new a({
|
|
134
|
+
line: t,
|
|
135
|
+
path: e.filePath,
|
|
136
|
+
reason: n
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
findAnchors(e, t) {
|
|
140
|
+
let indexesOf = (t) => e.flatMap((e, n) => e.trim() === t ? [n] : []), [r, a] = indexesOf(i), [o, s] = indexesOf(n), c = { filePath: t };
|
|
141
|
+
if (a !== void 0 && this.fail(c, a + 1, "a second start anchor"), s !== void 0 && this.fail(c, s + 1, "a second end anchor"), r !== void 0 && o !== void 0) return o < r && this.fail(c, o + 1, "an end anchor before the start anchor"), {
|
|
142
|
+
end: o,
|
|
143
|
+
start: r
|
|
144
|
+
};
|
|
145
|
+
let l = r ?? o;
|
|
146
|
+
l !== void 0 && this.fail(c, l + 1, "an anchor without its partner");
|
|
147
|
+
}
|
|
148
|
+
flush(e) {
|
|
149
|
+
e.current !== void 0 && e.glossary.set(e.current.word, e.current.lines.join("\n")), e.current = void 0, e.pendingBlankLines = 0;
|
|
150
|
+
}
|
|
151
|
+
readBullet(e, t, n) {
|
|
152
|
+
t.rest !== "" && !t.rest.startsWith(" ") && this.fail(e, n, "a definition must follow its colon after a space"), this.flush(e), e.glossary.has(t.word) && this.fail(e, n, `the word "${t.word}" is listed twice`), e.current = {
|
|
153
|
+
lines: [t.rest.slice(1)],
|
|
154
|
+
word: t.word
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
readContinuation(e, t, n) {
|
|
158
|
+
e.current !== void 0 && v.test(t) || this.fail(e, n, "not a word bullet or an indented continuation"), e.current.lines.push(...Array.from({ length: e.pendingBlankLines }, () => ""), t), e.pendingBlankLines = 0;
|
|
159
|
+
}
|
|
160
|
+
readDescription(e) {
|
|
161
|
+
let t = e?.split(_) ?? [], n = this.findAnchors(t, ""), i = n === void 0 ? [] : t.slice(n.start + 1, n.end), a = i.findIndex((e) => g.test(e)), o = (a === -1 ? i : i.slice(0, a)).filter((e) => e.trim() !== r).join("\n").trim();
|
|
162
|
+
return o === "" ? void 0 : o;
|
|
163
|
+
}
|
|
164
|
+
readLine(e, t, n) {
|
|
165
|
+
if (!e.readingBullets && !g.test(t)) return;
|
|
166
|
+
e.readingBullets = !0;
|
|
167
|
+
let r = h.exec(t)?.groups;
|
|
168
|
+
r?.word !== void 0 && r.rest !== void 0 ? this.readBullet(e, {
|
|
169
|
+
rest: r.rest,
|
|
170
|
+
word: r.word
|
|
171
|
+
}, n) : t.trim() === "" ? e.pendingBlankLines += 1 : this.readContinuation(e, t, n);
|
|
172
|
+
}
|
|
173
|
+
renderBullet(e, t) {
|
|
174
|
+
return t === "" || t.startsWith("\n") ? `- **${e}**:${t}` : `- **${e}**: ${t}`;
|
|
175
|
+
}
|
|
176
|
+
parse(e, t) {
|
|
177
|
+
let n = e.split(_), r = this.findAnchors(n, t);
|
|
178
|
+
if (r === void 0) return;
|
|
179
|
+
let i = {
|
|
180
|
+
current: void 0,
|
|
181
|
+
filePath: t,
|
|
182
|
+
glossary: /* @__PURE__ */ new Map(),
|
|
183
|
+
pendingBlankLines: 0,
|
|
184
|
+
readingBullets: !1
|
|
185
|
+
};
|
|
186
|
+
return n.slice(r.start + 1, r.end).forEach((e, t) => {
|
|
187
|
+
this.readLine(i, e, r.start + t + 2);
|
|
188
|
+
}), this.flush(i), i.glossary;
|
|
189
|
+
}
|
|
190
|
+
read(e, t) {
|
|
191
|
+
return e === void 0 ? void 0 : this.parse(e, t);
|
|
192
|
+
}
|
|
193
|
+
render(e) {
|
|
194
|
+
let t = [
|
|
195
|
+
i,
|
|
196
|
+
"",
|
|
197
|
+
r,
|
|
198
|
+
""
|
|
199
|
+
], a = e.description === void 0 || e.description === "" ? [] : [e.description, ""], o = [...e.glossary].toSorted(([e], [t]) => e < t ? -1 : 1).map(([e, t]) => this.renderBullet(e, t));
|
|
200
|
+
return [
|
|
201
|
+
...t,
|
|
202
|
+
...a,
|
|
203
|
+
...o,
|
|
204
|
+
...o.length > 0 ? [""] : [],
|
|
205
|
+
n
|
|
206
|
+
].join("\n");
|
|
207
|
+
}
|
|
208
|
+
splice(e, t) {
|
|
209
|
+
if (e === void 0 || e === "") return `${t}\n`;
|
|
210
|
+
let n = e.includes("\r\n") ? "\r\n" : "\n", r = t.split("\n"), i = e.split(_), a = this.findAnchors(i, "");
|
|
211
|
+
return a === void 0 ? `${e.endsWith("\n") ? e : `${e}${n}`}${n}${r.join(n)}${n}` : [
|
|
212
|
+
...i.slice(0, a.start),
|
|
213
|
+
...r,
|
|
214
|
+
...i.slice(a.end + 1)
|
|
215
|
+
].join(n);
|
|
216
|
+
}
|
|
217
|
+
write(e) {
|
|
218
|
+
let t = "description" in e.destination ? e.destination.description : void 0;
|
|
219
|
+
return this.splice(e.content, this.render({
|
|
220
|
+
description: t ?? this.readDescription(e.content),
|
|
221
|
+
glossary: e.glossary
|
|
222
|
+
}));
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
y = __decorate([e(), __decorateMetadata("design:paramtypes", [])], y);
|
|
226
|
+
// src/modules/markdown/markdown.module.ts
|
|
227
|
+
var b = class MarkdownModule {};
|
|
228
|
+
b = __decorate([t({
|
|
229
|
+
controllers: [],
|
|
230
|
+
exports: [y],
|
|
231
|
+
imports: [],
|
|
232
|
+
providers: [y]
|
|
233
|
+
})], b);
|
|
234
|
+
// src/modules/delivery/delivery.service.ts
|
|
235
|
+
var x = class DeliveryService {
|
|
236
|
+
comparisonService;
|
|
237
|
+
constructor(e, t, n) {
|
|
238
|
+
this.comparisonService = e, this.handlers = {
|
|
239
|
+
json: t,
|
|
240
|
+
markdown: n
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
handlers;
|
|
244
|
+
contentFor(e, t) {
|
|
245
|
+
return this.handlerFor(e.destination).write({
|
|
246
|
+
content: e.content,
|
|
247
|
+
destination: e.destination,
|
|
248
|
+
glossary: this.comparisonService.reconcile(t, e.glossary)
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
differenceOf(e, t) {
|
|
252
|
+
return {
|
|
253
|
+
...this.comparisonService.compare(t, e.glossary),
|
|
254
|
+
path: e.destination.path,
|
|
255
|
+
type: e.destination.type
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
handlerFor(e) {
|
|
259
|
+
return this.handlers[e.type];
|
|
260
|
+
}
|
|
261
|
+
readAll(e) {
|
|
262
|
+
return e.map((e) => {
|
|
263
|
+
let t = o(e.path) ? c(e.path, "utf8") : void 0;
|
|
264
|
+
return {
|
|
265
|
+
content: t,
|
|
266
|
+
destination: e,
|
|
267
|
+
glossary: this.handlerFor(e).read(t, e.path) ?? /* @__PURE__ */ new Map()
|
|
268
|
+
};
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
check(e) {
|
|
272
|
+
return this.readAll(e.destinations).map((t) => this.differenceOf(t, e.words));
|
|
273
|
+
}
|
|
274
|
+
write(e) {
|
|
275
|
+
return this.readAll(e.destinations).map((t) => {
|
|
276
|
+
let n = this.contentFor(t, e.words), r = n !== t.content;
|
|
277
|
+
return r && (s(u.dirname(t.destination.path), { recursive: !0 }), l(t.destination.path, n)), {
|
|
278
|
+
...this.differenceOf(t, e.words),
|
|
279
|
+
written: r
|
|
280
|
+
};
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
x = __decorate([e(), __decorateMetadata("design:paramtypes", [
|
|
285
|
+
d === void 0 ? Object : d,
|
|
286
|
+
p === void 0 ? Object : p,
|
|
287
|
+
y === void 0 ? Object : y
|
|
288
|
+
])], x);
|
|
289
|
+
// src/modules/delivery/delivery.module.ts
|
|
290
|
+
var S = class DeliveryModule {};
|
|
291
|
+
S = __decorate([t({
|
|
292
|
+
controllers: [],
|
|
293
|
+
exports: [x],
|
|
294
|
+
imports: [
|
|
295
|
+
f,
|
|
296
|
+
m,
|
|
297
|
+
b
|
|
298
|
+
],
|
|
299
|
+
providers: [x]
|
|
300
|
+
})], S);
|
|
301
|
+
export { f as ComparisonModule, d as ComparisonService, S as DeliveryModule, x as DeliveryService, m as JsonModule, p as JsonService, b as MarkdownModule, y as MarkdownService };
|
package/package.json
CHANGED
|
@@ -1,6 +1,61 @@
|
|
|
1
1
|
{
|
|
2
|
+
"author": "Jimmy Paolini",
|
|
3
|
+
"bugs": {
|
|
4
|
+
"url": "https://github.com/organizzolini/codebase/issues"
|
|
5
|
+
},
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@coinagerie/configuration": "0.0.2",
|
|
8
|
+
"@coinagerie/core": "0.0.2",
|
|
9
|
+
"@nestjs/common": "^11.1.21 || ^12.0.1",
|
|
10
|
+
"reflect-metadata": "^0.2.2"
|
|
11
|
+
},
|
|
12
|
+
"description": "Renders and parses the markdown and JSON glossaries and compares them with the vocabulary of a codebase",
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@golevelup/ts-vitest": "^4.0.0",
|
|
15
|
+
"@nestjs/testing": "^12.0.1",
|
|
16
|
+
"@nx/eslint-plugin": "^24.0.0",
|
|
17
|
+
"@swc/helpers": "^0.5.21",
|
|
18
|
+
"@types/node": "^26.5.1",
|
|
19
|
+
"@vitest/coverage-v8": "^5.0.0",
|
|
20
|
+
"vitest": "^5.0.0"
|
|
21
|
+
},
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/src/index.d.ts",
|
|
25
|
+
"default": "./dist/src/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./package.json": "./package.json"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"CHANGELOG.md",
|
|
31
|
+
"dist",
|
|
32
|
+
"LICENSE",
|
|
33
|
+
"README.md"
|
|
34
|
+
],
|
|
35
|
+
"homepage": "https://github.com/organizzolini/codebase/tree/main/projects/ic-suite/coinagerie/coinagerie-output#readme",
|
|
36
|
+
"keywords": [
|
|
37
|
+
"coinagerie",
|
|
38
|
+
"glossary",
|
|
39
|
+
"rendering",
|
|
40
|
+
"vocabulary"
|
|
41
|
+
],
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"main": "./dist/src/index.js",
|
|
2
44
|
"name": "@coinagerie/output",
|
|
3
|
-
"
|
|
4
|
-
|
|
5
|
-
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public",
|
|
47
|
+
"registry": "https://registry.npmjs.org"
|
|
48
|
+
},
|
|
49
|
+
"repository": {
|
|
50
|
+
"directory": "projects/ic-suite/coinagerie/coinagerie-output",
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/organizzolini/codebase.git"
|
|
53
|
+
},
|
|
54
|
+
"type": "module",
|
|
55
|
+
"typeCoverage": {
|
|
56
|
+
"atLeast": 100,
|
|
57
|
+
"strict": true
|
|
58
|
+
},
|
|
59
|
+
"types": "./dist/src/index.d.ts",
|
|
60
|
+
"version": "0.0.2"
|
|
6
61
|
}
|