eqxjs-create-silo-repo 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
1
+ # ─── Stage 1: Build ───────────────────────────────────────────────────────────
2
+ FROM node:24-alpine AS builder
3
+
4
+ WORKDIR /workspace
5
+
6
+ # ── Install the CLI globally from npm ────────────────────────────────────────
7
+ RUN npm install -g eqxjs-create-silo-repo
8
+
9
+ # ── Copy application config ──────────────────────────────────────────────────
10
+ # silo.config.yaml drives which repositories are collected and whether
11
+ # Kafka mode is enabled. Provide your own config at build time via:
12
+ # docker build --build-arg CONFIG_FILE=silo.config.yaml ...
13
+ # or simply COPY it directly if the filename is fixed.
14
+ COPY silo.config.yaml ./silo.config.yaml
15
+
16
+ # ── Run the CLI to generate the combined-app ─────────────────────────────────
17
+ # create-silo reads silo.config.yaml, clones/installs all repos, and writes
18
+ # combined-app/ (package.json, tsconfig.json, src/app.module.ts, src/main.ts).
19
+ RUN create-silo --config ./silo.config.yaml
20
+
21
+ # ── Compile the generated combined-app ───────────────────────────────────────
22
+ WORKDIR /workspace/combined-app
23
+ RUN npm run build 2>/dev/null || npx tsc -p tsconfig.json
24
+
25
+ # Prune devDependencies before copying to the runtime stage
26
+ RUN npm prune --production
27
+
28
+ # ─── Stage 2: Runtime ─────────────────────────────────────────────────────────
29
+ FROM node:24-alpine AS runtime
30
+
31
+ ENV NODE_ENV=production
32
+
33
+ WORKDIR /app
34
+
35
+ # Copy compiled output and production node_modules from the builder
36
+ COPY --from=builder /workspace/combined-app/dist ./dist
37
+ COPY --from=builder /workspace/combined-app/node_modules ./node_modules
38
+ COPY --from=builder /workspace/combined-app/package.json ./package.json
39
+
40
+ EXPOSE 3000
41
+
42
+ CMD ["node", "dist/main.js"]
package/README.md ADDED
@@ -0,0 +1,194 @@
1
+ # eqxjs-create-silo-repo
2
+
3
+ A Node.js CLI written in TypeScript that collects multiple NestJS repositories into a single runnable combined application.
4
+
5
+ ## Features
6
+
7
+ - Prompt repository sources one-by-one (interactive) or pass them via flags (non-interactive)
8
+ - Accepts **local paths** or **Git URLs** (`https://`, `git@`, `ssh://`)
9
+ - Git URL sources are added as **git submodules** under `submodules/`
10
+ - Optional **branch or commit SHA** checkout per git submodule, specified inline (`url#ref`) or via `--ref`
11
+ - Runs `npm install` inside every collected repository
12
+ - Generates a combined NestJS app that imports each repository's `AppModule`
13
+ - Generated app has its own `package.json`, `tsconfig.json`, and `main.ts` and is ready to start
14
+
15
+ ## Global Installation
16
+
17
+ Build the project first, then install it globally so the `create-silo` command is available anywhere:
18
+
19
+ ```bash
20
+ npm run build
21
+ npm install -g .
22
+ ```
23
+
24
+ Then use it from any directory:
25
+
26
+ ```bash
27
+ # Interactive
28
+ create-silo
29
+
30
+ # Non-interactive — local paths
31
+ create-silo --repo ../repo-a --repo ../repo-b
32
+
33
+ # Non-interactive — Git URLs with ref
34
+ create-silo --repo https://github.com/acme/repo-a.git --ref main
35
+ create-silo --repo https://github.com/acme/repo-a.git#main
36
+
37
+ # Uninstall
38
+ npm uninstall -g eqxjs-create-silo-repo
39
+ ```
40
+
41
+ > **Note:** Re-run `npm run build` before re-installing whenever the source changes.
42
+
43
+ ## Prerequisites
44
+
45
+ - Node.js >= 18
46
+ - Git (required when using Git URL sources)
47
+ - The workspace must be a git repository (`git init`) before adding Git URL sources
48
+
49
+ ## Installation
50
+
51
+ ```bash
52
+ npm install
53
+ ```
54
+
55
+ ## Scripts
56
+
57
+ | Script | Description |
58
+ |---|---|
59
+ | `npm start` | Run the CLI directly via `ts-node` |
60
+ | `npm run build` | Compile TypeScript to `dist/` |
61
+ | `npm run start:js` | Run compiled CLI from `dist/` |
62
+ | `npm test` | Run unit tests |
63
+ | `npm run test:coverage` | Run unit tests with 100% coverage enforcement |
64
+
65
+ ## Usage
66
+
67
+ ### Interactive mode
68
+
69
+ ```bash
70
+ npm start
71
+ ```
72
+
73
+ Enter repository sources one-by-one. Press Enter on an empty line to finish.
74
+
75
+ **Local paths:**
76
+
77
+ ```text
78
+ Repository #1: ../repo-a
79
+ Repository #2: ../repo-b
80
+ Repository #3:
81
+ ```
82
+
83
+ **Git URLs with optional branch or SHA (inline `#ref`):**
84
+
85
+ ```text
86
+ Repository #1: https://github.com/acme/repo-a.git#main
87
+ Repository #2: git@github.com:acme/repo-b.git#6fc8e8f
88
+ Repository #3:
89
+ ```
90
+
91
+ ### YAML config file
92
+
93
+ Define all repositories in a YAML file and pass it via `--config`:
94
+
95
+ ```yaml
96
+ # silo.config.yaml
97
+ name: my-combined-app # optional — sets the name in combined-app package.json (default: combined-nest-app)
98
+ version: 1.2.0 # optional — sets the version in combined-app package.json (default: 1.0.0)
99
+
100
+ repositories:
101
+ - source: https://github.com/acme/repo-a.git
102
+ ref: main
103
+
104
+ - source: git@github.com:acme/repo-b.git
105
+ ref: 6fc8e8f
106
+
107
+ - source: ../local-repo-c
108
+ ```
109
+
110
+ ```bash
111
+ # Run with config file
112
+ npm start -- --config ./silo.config.yaml
113
+
114
+ # Mix config file with extra --repo flags
115
+ npm start -- --config ./silo.config.yaml --repo ../extra-repo
116
+ ```
117
+
118
+ A ready-to-use template is provided in `silo.config.example.yaml`.
119
+
120
+ ### Non-interactive mode
121
+
122
+ Pass `--repo` once per repository. Append `#ref` inline or use `--ref` immediately after the relevant `--repo`:
123
+
124
+ ```bash
125
+ # Local paths
126
+ npm start -- --repo ../repo-a --repo ../repo-b
127
+
128
+ # Git URLs — inline ref
129
+ npm start -- --repo https://github.com/acme/repo-a.git#main
130
+
131
+ # Git URLs — --ref flag
132
+ npm start -- --repo https://github.com/acme/repo-a.git --ref main
133
+
134
+ # Mixed
135
+ npm start -- --repo ../repo-a --repo https://github.com/acme/repo-b.git#6fc8e8f
136
+ ```
137
+
138
+ ### Running the compiled build
139
+
140
+ ```bash
141
+ npm run build
142
+ npm run start:js -- --repo ../repo-a --repo ../repo-b
143
+ ```
144
+
145
+ ## Output
146
+
147
+ After the CLI completes, a `combined-app/` directory is created:
148
+
149
+ ```
150
+ combined-app/
151
+ ├── src/
152
+ │ ├── app.module.ts # imports each repository AppModule
153
+ │ └── main.ts # Nest bootstrap on port 3000 (or $PORT)
154
+ ├── package.json
155
+ └── tsconfig.json
156
+ ```
157
+
158
+ Start the combined application:
159
+
160
+ ```bash
161
+ cd combined-app
162
+ npm start
163
+ ```
164
+
165
+ ## Testing
166
+
167
+ The project ships with comprehensive unit tests covering 100% of statements, branches, functions, and lines.
168
+
169
+ ```
170
+ src/
171
+ ├── lib.ts # All exported pure functions
172
+ ├── cli.ts # main() entrypoint
173
+ └── __tests__/
174
+ ├── lib.test.ts # Unit tests for all lib functions
175
+ └── cli.test.ts # Unit tests for main() with mocked dependencies
176
+ ```
177
+
178
+ Run tests:
179
+
180
+ ```bash
181
+ # Run tests once
182
+ npm test
183
+
184
+ # Run with coverage report (enforces 100% threshold)
185
+ npm run test:coverage
186
+ ```
187
+
188
+ Coverage is enforced at 100% for statements, branches, functions, and lines. The CI build will fail if any new code is added without corresponding tests.
189
+
190
+ ## Git Submodule Notes
191
+
192
+ - Git URL repositories are added via `git submodule add` into `submodules/<repo-name>_<index>/`
193
+ - When a `ref` is provided the CLI runs `git checkout <ref>` inside the submodule after adding it
194
+ - To remove a submodule run `git submodule deinit` and `git rm` for the relevant path
@@ -0,0 +1,253 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <coverage generated="1773806224024" clover="3.2.0">
3
+ <project timestamp="1773806224024" name="All files">
4
+ <metrics statements="241" coveredstatements="241" conditionals="117" coveredconditionals="117" methods="30" coveredmethods="30" elements="388" coveredelements="388" complexity="0" loc="241" ncloc="241" packages="1" files="2" classes="2"/>
5
+ <file name="cli.ts" path="/opt/workspace/lagacy-service/cronus-extra-library-eqxjs-create-combined-app/src/cli.ts">
6
+ <metrics statements="79" coveredstatements="79" conditionals="26" coveredconditionals="26" methods="5" coveredmethods="5"/>
7
+ <line num="2" count="1" type="stmt"/>
8
+ <line num="3" count="1" type="stmt"/>
9
+ <line num="4" count="1" type="stmt"/>
10
+ <line num="5" count="1" type="stmt"/>
11
+ <line num="6" count="1" type="stmt"/>
12
+ <line num="29" count="1" type="stmt"/>
13
+ <line num="30" count="14" type="stmt"/>
14
+ <line num="31" count="14" type="stmt"/>
15
+ <line num="32" count="14" type="stmt"/>
16
+ <line num="33" count="14" type="stmt"/>
17
+ <line num="34" count="14" type="stmt"/>
18
+ <line num="35" count="14" type="stmt"/>
19
+ <line num="37" count="14" type="stmt"/>
20
+ <line num="38" count="14" type="stmt"/>
21
+ <line num="40" count="14" type="cond" truecount="2" falsecount="0"/>
22
+ <line num="41" count="3" type="stmt"/>
23
+ <line num="42" count="3" type="stmt"/>
24
+ <line num="43" count="3" type="stmt"/>
25
+ <line num="44" count="3" type="stmt"/>
26
+ <line num="45" count="3" type="stmt"/>
27
+ <line num="46" count="3" type="cond" truecount="2" falsecount="0"/>
28
+ <line num="49" count="14" type="stmt"/>
29
+ <line num="51" count="14" type="cond" truecount="2" falsecount="0"/>
30
+ <line num="52" count="2" type="stmt"/>
31
+ <line num="57" count="14" type="cond" truecount="2" falsecount="0"/>
32
+ <line num="58" count="2" type="stmt"/>
33
+ <line num="59" count="3" type="stmt"/>
34
+ <line num="60" count="3" type="stmt"/>
35
+ <line num="61" count="3" type="cond" truecount="2" falsecount="0"/>
36
+ <line num="62" count="2" type="stmt"/>
37
+ <line num="64" count="1" type="stmt"/>
38
+ <line num="68" count="14" type="cond" truecount="2" falsecount="0"/>
39
+ <line num="69" count="1" type="stmt"/>
40
+ <line num="72" count="13" type="stmt"/>
41
+ <line num="73" count="15" type="cond" truecount="2" falsecount="0"/>
42
+ <line num="74" count="15" type="stmt"/>
43
+ <line num="75" count="16" type="cond" truecount="2" falsecount="0"/>
44
+ <line num="79" count="13" type="stmt"/>
45
+ <line num="81" count="13" type="stmt"/>
46
+ <line num="82" count="14" type="stmt"/>
47
+ <line num="83" count="14" type="stmt"/>
48
+ <line num="84" count="12" type="stmt"/>
49
+ <line num="85" count="12" type="stmt"/>
50
+ <line num="86" count="12" type="stmt"/>
51
+ <line num="87" count="12" type="stmt"/>
52
+ <line num="90" count="11" type="stmt"/>
53
+ <line num="91" count="11" type="stmt"/>
54
+ <line num="92" count="12" type="stmt"/>
55
+ <line num="93" count="12" type="stmt"/>
56
+ <line num="96" count="11" type="stmt"/>
57
+ <line num="97" count="11" type="stmt"/>
58
+ <line num="98" count="11" type="stmt"/>
59
+ <line num="100" count="12" type="stmt"/>
60
+ <line num="105" count="12" type="stmt"/>
61
+ <line num="106" count="11" type="stmt"/>
62
+ <line num="108" count="11" type="cond" truecount="2" falsecount="0"/>
63
+ <line num="109" count="1" type="stmt"/>
64
+ <line num="110" count="1" type="stmt"/>
65
+ <line num="111" count="1" type="stmt"/>
66
+ <line num="112" count="1" type="stmt"/>
67
+ <line num="113" count="1" type="stmt"/>
68
+ <line num="114" count="1" type="stmt"/>
69
+ <line num="117" count="11" type="stmt"/>
70
+ <line num="118" count="11" type="stmt"/>
71
+ <line num="124" count="11" type="cond" truecount="2" falsecount="0"/>
72
+ <line num="125" count="11" type="stmt"/>
73
+ <line num="127" count="11" type="stmt"/>
74
+ <line num="131" count="11" type="stmt"/>
75
+ <line num="132" count="11" type="stmt"/>
76
+ <line num="136" count="11" type="stmt"/>
77
+ <line num="141" count="11" type="stmt"/>
78
+ <line num="142" count="11" type="stmt"/>
79
+ <line num="144" count="11" type="stmt"/>
80
+ <line num="145" count="11" type="stmt"/>
81
+ <line num="146" count="11" type="stmt"/>
82
+ <line num="148" count="3" type="cond" truecount="2" falsecount="0"/>
83
+ <line num="149" count="3" type="stmt"/>
84
+ <line num="150" count="3" type="stmt"/>
85
+ <line num="152" count="14" type="stmt"/>
86
+ </file>
87
+ <file name="lib.ts" path="/opt/workspace/lagacy-service/cronus-extra-library-eqxjs-create-combined-app/src/lib.ts">
88
+ <metrics statements="162" coveredstatements="162" conditionals="91" coveredconditionals="91" methods="25" coveredmethods="25"/>
89
+ <line num="1" count="2" type="stmt"/>
90
+ <line num="2" count="2" type="stmt"/>
91
+ <line num="3" count="2" type="stmt"/>
92
+ <line num="4" count="2" type="stmt"/>
93
+ <line num="50" count="2" type="stmt"/>
94
+ <line num="51" count="2" type="stmt"/>
95
+ <line num="55" count="2" type="stmt"/>
96
+ <line num="56" count="5" type="stmt"/>
97
+ <line num="60" count="5" type="cond" truecount="2" falsecount="0"/>
98
+ <line num="63" count="2" type="stmt"/>
99
+ <line num="64" count="5" type="stmt"/>
100
+ <line num="67" count="2" type="stmt"/>
101
+ <line num="68" count="16" type="stmt"/>
102
+ <line num="69" count="16" type="cond" truecount="2" falsecount="0"/>
103
+ <line num="70" count="4" type="stmt"/>
104
+ <line num="72" count="12" type="stmt"/>
105
+ <line num="75" count="2" type="stmt"/>
106
+ <line num="76" count="13" type="stmt"/>
107
+ <line num="77" count="13" type="cond" truecount="2" falsecount="0"/>
108
+ <line num="78" count="2" type="stmt"/>
109
+ <line num="81" count="11" type="stmt"/>
110
+ <line num="82" count="11" type="cond" truecount="4" falsecount="0"/>
111
+ <line num="83" count="2" type="stmt"/>
112
+ <line num="89" count="9" type="stmt"/>
113
+ <line num="92" count="2" type="stmt"/>
114
+ <line num="93" count="9" type="stmt"/>
115
+ <line num="94" count="9" type="cond" truecount="2" falsecount="0"/>
116
+ <line num="95" count="1" type="stmt"/>
117
+ <line num="98" count="8" type="stmt"/>
118
+ <line num="99" count="8" type="stmt"/>
119
+ <line num="101" count="8" type="cond" truecount="4" falsecount="0"/>
120
+ <line num="102" count="2" type="stmt"/>
121
+ <line num="105" count="6" type="stmt"/>
122
+ <line num="106" count="6" type="cond" truecount="2" falsecount="0"/>
123
+ <line num="107" count="1" type="stmt"/>
124
+ <line num="109" count="5" type="cond" truecount="2" falsecount="0"/>
125
+ <line num="112" count="5" type="stmt"/>
126
+ <line num="120" count="2" type="stmt"/>
127
+ <line num="121" count="12" type="stmt"/>
128
+ <line num="122" count="12" type="stmt"/>
129
+ <line num="123" count="12" type="stmt"/>
130
+ <line num="125" count="12" type="stmt"/>
131
+ <line num="126" count="14" type="stmt"/>
132
+ <line num="127" count="14" type="cond" truecount="2" falsecount="0"/>
133
+ <line num="128" count="1" type="stmt"/>
134
+ <line num="129" count="13" type="cond" truecount="2" falsecount="0"/>
135
+ <line num="130" count="2" type="stmt"/>
136
+ <line num="131" count="2" type="cond" truecount="2" falsecount="0"/>
137
+ <line num="132" count="1" type="stmt"/>
138
+ <line num="134" count="2" type="stmt"/>
139
+ <line num="135" count="11" type="cond" truecount="2" falsecount="0"/>
140
+ <line num="136" count="9" type="stmt"/>
141
+ <line num="137" count="9" type="cond" truecount="2" falsecount="0"/>
142
+ <line num="138" count="8" type="stmt"/>
143
+ <line num="139" count="8" type="cond" truecount="2" falsecount="0"/>
144
+ <line num="140" count="7" type="stmt"/>
145
+ <line num="141" count="7" type="stmt"/>
146
+ <line num="142" count="7" type="cond" truecount="4" falsecount="0"/>
147
+ <line num="143" count="1" type="stmt"/>
148
+ <line num="144" count="1" type="stmt"/>
149
+ <line num="146" count="6" type="stmt"/>
150
+ <line num="150" count="9" type="stmt"/>
151
+ <line num="154" count="12" type="stmt"/>
152
+ <line num="157" count="2" type="stmt"/>
153
+ <line num="158" count="11" type="stmt"/>
154
+ <line num="166" count="2" type="stmt"/>
155
+ <line num="167" count="6" type="stmt"/>
156
+ <line num="168" count="6" type="cond" truecount="2" falsecount="0"/>
157
+ <line num="169" count="2" type="stmt"/>
158
+ <line num="175" count="2" type="stmt"/>
159
+ <line num="176" count="7" type="stmt"/>
160
+ <line num="180" count="7" type="cond" truecount="2" falsecount="0"/>
161
+ <line num="183" count="2" type="stmt"/>
162
+ <line num="184" count="5" type="cond" truecount="2" falsecount="0"/>
163
+ <line num="185" count="1" type="stmt"/>
164
+ <line num="188" count="4" type="stmt"/>
165
+ <line num="189" count="3" type="stmt"/>
166
+ <line num="190" count="3" type="stmt"/>
167
+ <line num="191" count="3" type="stmt"/>
168
+ <line num="192" count="3" type="stmt"/>
169
+ <line num="193" count="3" type="stmt"/>
170
+ <line num="195" count="3" type="cond" truecount="2" falsecount="0"/>
171
+ <line num="196" count="1" type="stmt"/>
172
+ <line num="199" count="3" type="cond" truecount="2" falsecount="0"/>
173
+ <line num="200" count="3" type="stmt"/>
174
+ <line num="201" count="3" type="stmt"/>
175
+ <line num="203" count="3" type="cond" truecount="2" falsecount="0"/>
176
+ <line num="204" count="1" type="stmt"/>
177
+ <line num="205" count="1" type="stmt"/>
178
+ <line num="208" count="3" type="stmt"/>
179
+ <line num="211" count="2" type="stmt"/>
180
+ <line num="212" count="8" type="stmt"/>
181
+ <line num="213" count="8" type="stmt"/>
182
+ <line num="219" count="8" type="stmt"/>
183
+ <line num="220" count="8" type="stmt"/>
184
+ <line num="221" count="7" type="cond" truecount="2" falsecount="0"/>
185
+ <line num="222" count="5" type="stmt"/>
186
+ <line num="224" count="2" type="cond" truecount="2" falsecount="0"/>
187
+ <line num="230" count="2" type="stmt"/>
188
+ <line num="231" count="3" type="stmt"/>
189
+ <line num="232" count="3" type="cond" truecount="2" falsecount="0"/>
190
+ <line num="233" count="1" type="stmt"/>
191
+ <line num="235" count="2" type="cond" truecount="2" falsecount="0"/>
192
+ <line num="236" count="1" type="stmt"/>
193
+ <line num="238" count="1" type="stmt"/>
194
+ <line num="241" count="2" type="stmt"/>
195
+ <line num="242" count="3" type="stmt"/>
196
+ <line num="243" count="3" type="cond" truecount="2" falsecount="0"/>
197
+ <line num="244" count="2" type="stmt"/>
198
+ <line num="245" count="2" type="stmt"/>
199
+ <line num="246" count="2" type="cond" truecount="2" falsecount="0"/>
200
+ <line num="249" count="2" type="stmt"/>
201
+ <line num="252" count="5" type="stmt"/>
202
+ <line num="254" count="5" type="stmt"/>
203
+ <line num="255" count="7" type="stmt"/>
204
+ <line num="256" count="9" type="cond" truecount="2" falsecount="0"/>
205
+ <line num="257" count="9" type="stmt"/>
206
+ <line num="261" count="5" type="stmt"/>
207
+ <line num="262" count="5" type="stmt"/>
208
+ <line num="264" count="5" type="stmt"/>
209
+ <line num="265" count="6" type="stmt"/>
210
+ <line num="266" count="6" type="cond" truecount="4" falsecount="0"/>
211
+ <line num="267" count="2" type="stmt"/>
212
+ <line num="269" count="4" type="stmt"/>
213
+ <line num="273" count="5" type="stmt"/>
214
+ <line num="276" count="2" type="stmt"/>
215
+ <line num="277" count="6" type="stmt"/>
216
+ <line num="278" count="6" type="stmt"/>
217
+ <line num="279" count="5" type="cond" truecount="2" falsecount="0"/>
218
+ <line num="280" count="2" type="stmt"/>
219
+ <line num="282" count="3" type="stmt"/>
220
+ <line num="283" count="3" type="stmt"/>
221
+ <line num="286" count="2" type="stmt"/>
222
+ <line num="289" count="4" type="stmt"/>
223
+ <line num="291" count="4" type="stmt"/>
224
+ <line num="292" count="4" type="stmt"/>
225
+ <line num="293" count="2" type="stmt"/>
226
+ <line num="295" count="2" type="stmt"/>
227
+ <line num="299" count="4" type="stmt"/>
228
+ <line num="302" count="2" type="stmt"/>
229
+ <line num="306" count="2" type="stmt"/>
230
+ <line num="307" count="2" type="stmt"/>
231
+ <line num="308" count="2" type="cond" truecount="2" falsecount="0"/>
232
+ <line num="309" count="2" type="stmt"/>
233
+ <line num="310" count="2" type="stmt"/>
234
+ <line num="313" count="2" type="stmt"/>
235
+ <line num="314" count="2" type="stmt"/>
236
+ <line num="315" count="2" type="stmt"/>
237
+ <line num="317" count="2" type="stmt"/>
238
+ <line num="318" count="2" type="stmt"/>
239
+ <line num="323" count="2" type="stmt"/>
240
+ <line num="326" count="2" type="stmt"/>
241
+ <line num="329" count="2" type="stmt"/>
242
+ <line num="332" count="2" type="cond" truecount="1" falsecount="0"/>
243
+ <line num="333" count="2" type="cond" truecount="2" falsecount="0"/>
244
+ <line num="334" count="1" type="stmt"/>
245
+ <line num="353" count="1" type="stmt"/>
246
+ <line num="369" count="2" type="stmt"/>
247
+ <line num="375" count="5" type="cond" truecount="2" falsecount="0"/>
248
+ <line num="382" count="5" type="stmt"/>
249
+ <line num="403" count="2" type="stmt"/>
250
+ <line num="404" count="1" type="stmt"/>
251
+ </file>
252
+ </project>
253
+ </coverage>