@sitepong/fastnode 0.1.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.
Files changed (162) hide show
  1. package/README.md +81 -0
  2. package/bin/fastnode.js +13 -0
  3. package/bin/fastnode.ts +5 -0
  4. package/dist/actions/index.cjs +7405 -0
  5. package/dist/actions/index.cjs.map +1 -0
  6. package/dist/actions/index.d.cts +15 -0
  7. package/dist/actions/index.d.ts +15 -0
  8. package/dist/actions/index.mjs +7377 -0
  9. package/dist/actions/index.mjs.map +1 -0
  10. package/dist/cert/index.cjs +219 -0
  11. package/dist/cert/index.cjs.map +1 -0
  12. package/dist/cert/index.d.cts +4 -0
  13. package/dist/cert/index.d.ts +4 -0
  14. package/dist/cert/index.mjs +191 -0
  15. package/dist/cert/index.mjs.map +1 -0
  16. package/dist/cert-BmJGtYtb.d.cts +27 -0
  17. package/dist/cert-owkOFNW8.d.ts +27 -0
  18. package/dist/cli/index.cjs +7998 -0
  19. package/dist/cli/index.cjs.map +1 -0
  20. package/dist/cli/index.d.cts +9 -0
  21. package/dist/cli/index.d.ts +9 -0
  22. package/dist/cli/index.mjs +7972 -0
  23. package/dist/cli/index.mjs.map +1 -0
  24. package/dist/client/index.cjs +2592 -0
  25. package/dist/client/index.cjs.map +1 -0
  26. package/dist/client/index.d.cts +2 -0
  27. package/dist/client/index.d.ts +2 -0
  28. package/dist/client/index.mjs +2582 -0
  29. package/dist/client/index.mjs.map +1 -0
  30. package/dist/context-CymLkfrS.d.cts +13 -0
  31. package/dist/context-CymLkfrS.d.ts +13 -0
  32. package/dist/core/index.cjs +281 -0
  33. package/dist/core/index.cjs.map +1 -0
  34. package/dist/core/index.d.cts +1 -0
  35. package/dist/core/index.d.ts +1 -0
  36. package/dist/core/index.mjs +254 -0
  37. package/dist/core/index.mjs.map +1 -0
  38. package/dist/deliver/index.cjs +328 -0
  39. package/dist/deliver/index.cjs.map +1 -0
  40. package/dist/deliver/index.d.cts +3 -0
  41. package/dist/deliver/index.d.ts +3 -0
  42. package/dist/deliver/index.mjs +322 -0
  43. package/dist/deliver/index.mjs.map +1 -0
  44. package/dist/enums-B609j2rb.d.cts +20 -0
  45. package/dist/enums-B609j2rb.d.ts +20 -0
  46. package/dist/frameit/index.cjs +247 -0
  47. package/dist/frameit/index.cjs.map +1 -0
  48. package/dist/frameit/index.d.cts +1 -0
  49. package/dist/frameit/index.d.ts +1 -0
  50. package/dist/frameit/index.mjs +242 -0
  51. package/dist/frameit/index.mjs.map +1 -0
  52. package/dist/gym/index.cjs +356 -0
  53. package/dist/gym/index.cjs.map +1 -0
  54. package/dist/gym/index.d.cts +2 -0
  55. package/dist/gym/index.d.ts +2 -0
  56. package/dist/gym/index.mjs +346 -0
  57. package/dist/gym/index.mjs.map +1 -0
  58. package/dist/index-1Vu2cRQ2.d.ts +99 -0
  59. package/dist/index-A5MimeQk.d.ts +72 -0
  60. package/dist/index-B0yhu_LZ.d.ts +76 -0
  61. package/dist/index-B9yXicrQ.d.ts +62 -0
  62. package/dist/index-BFdNOmPJ.d.cts +53 -0
  63. package/dist/index-BLubSlgK.d.cts +1513 -0
  64. package/dist/index-BN0ubxjZ.d.ts +70 -0
  65. package/dist/index-BQJIJlK7.d.cts +70 -0
  66. package/dist/index-BYonklf3.d.cts +84 -0
  67. package/dist/index-BYonklf3.d.ts +84 -0
  68. package/dist/index-BimqCmY8.d.cts +78 -0
  69. package/dist/index-BimqCmY8.d.ts +78 -0
  70. package/dist/index-BoU8qt8r.d.cts +59 -0
  71. package/dist/index-BoU8qt8r.d.ts +59 -0
  72. package/dist/index-C2yG3wXA.d.cts +95 -0
  73. package/dist/index-C2yG3wXA.d.ts +95 -0
  74. package/dist/index-CR3BFPIz.d.cts +77 -0
  75. package/dist/index-CR3BFPIz.d.ts +77 -0
  76. package/dist/index-CWNLnSOL.d.cts +99 -0
  77. package/dist/index-Cp6cjtd-.d.cts +65 -0
  78. package/dist/index-Cp6cjtd-.d.ts +65 -0
  79. package/dist/index-D1Izm7qt.d.ts +1513 -0
  80. package/dist/index-D5eihzwM.d.cts +76 -0
  81. package/dist/index-DImN9PWc.d.ts +155 -0
  82. package/dist/index-DfCUVJX1.d.cts +62 -0
  83. package/dist/index-DfirmFbC.d.ts +32 -0
  84. package/dist/index-DkvinY7_.d.ts +54 -0
  85. package/dist/index-DrUpRXRG.d.cts +155 -0
  86. package/dist/index-EcVvViW8.d.cts +72 -0
  87. package/dist/index-HRiaaX-Q.d.cts +54 -0
  88. package/dist/index-TfXqwuac.d.ts +53 -0
  89. package/dist/index-lt819Jgj.d.cts +32 -0
  90. package/dist/index.cjs +8464 -0
  91. package/dist/index.cjs.map +1 -0
  92. package/dist/index.d.cts +23 -0
  93. package/dist/index.d.ts +23 -0
  94. package/dist/index.mjs +8410 -0
  95. package/dist/index.mjs.map +1 -0
  96. package/dist/lane/index.cjs +7641 -0
  97. package/dist/lane/index.cjs.map +1 -0
  98. package/dist/lane/index.d.cts +51 -0
  99. package/dist/lane/index.d.ts +51 -0
  100. package/dist/lane/index.mjs +7603 -0
  101. package/dist/lane/index.mjs.map +1 -0
  102. package/dist/match/index.cjs +942 -0
  103. package/dist/match/index.cjs.map +1 -0
  104. package/dist/match/index.d.cts +5 -0
  105. package/dist/match/index.d.ts +5 -0
  106. package/dist/match/index.mjs +913 -0
  107. package/dist/match/index.mjs.map +1 -0
  108. package/dist/pem/index.cjs +195 -0
  109. package/dist/pem/index.cjs.map +1 -0
  110. package/dist/pem/index.d.cts +3 -0
  111. package/dist/pem/index.d.ts +3 -0
  112. package/dist/pem/index.mjs +170 -0
  113. package/dist/pem/index.mjs.map +1 -0
  114. package/dist/pilot/index.cjs +206 -0
  115. package/dist/pilot/index.cjs.map +1 -0
  116. package/dist/pilot/index.d.cts +3 -0
  117. package/dist/pilot/index.d.ts +3 -0
  118. package/dist/pilot/index.mjs +196 -0
  119. package/dist/pilot/index.mjs.map +1 -0
  120. package/dist/precheck/index.cjs +277 -0
  121. package/dist/precheck/index.cjs.map +1 -0
  122. package/dist/precheck/index.d.cts +3 -0
  123. package/dist/precheck/index.d.ts +3 -0
  124. package/dist/precheck/index.mjs +274 -0
  125. package/dist/precheck/index.mjs.map +1 -0
  126. package/dist/produce/index.cjs +200 -0
  127. package/dist/produce/index.cjs.map +1 -0
  128. package/dist/produce/index.d.cts +3 -0
  129. package/dist/produce/index.d.ts +3 -0
  130. package/dist/produce/index.mjs +191 -0
  131. package/dist/produce/index.mjs.map +1 -0
  132. package/dist/scan/index.cjs +187 -0
  133. package/dist/scan/index.cjs.map +1 -0
  134. package/dist/scan/index.d.cts +1 -0
  135. package/dist/scan/index.d.ts +1 -0
  136. package/dist/scan/index.mjs +183 -0
  137. package/dist/scan/index.mjs.map +1 -0
  138. package/dist/sigh/index.cjs +203 -0
  139. package/dist/sigh/index.cjs.map +1 -0
  140. package/dist/sigh/index.d.cts +3 -0
  141. package/dist/sigh/index.d.ts +3 -0
  142. package/dist/sigh/index.mjs +198 -0
  143. package/dist/sigh/index.mjs.map +1 -0
  144. package/dist/snapshot/index.cjs +448 -0
  145. package/dist/snapshot/index.cjs.map +1 -0
  146. package/dist/snapshot/index.d.cts +1 -0
  147. package/dist/snapshot/index.d.ts +1 -0
  148. package/dist/snapshot/index.mjs +438 -0
  149. package/dist/snapshot/index.mjs.map +1 -0
  150. package/dist/trainer/index.cjs +395 -0
  151. package/dist/trainer/index.cjs.map +1 -0
  152. package/dist/trainer/index.d.cts +1 -0
  153. package/dist/trainer/index.d.ts +1 -0
  154. package/dist/trainer/index.mjs +372 -0
  155. package/dist/trainer/index.mjs.map +1 -0
  156. package/dist/xcode/index.cjs +188 -0
  157. package/dist/xcode/index.cjs.map +1 -0
  158. package/dist/xcode/index.d.cts +1 -0
  159. package/dist/xcode/index.d.ts +1 -0
  160. package/dist/xcode/index.mjs +176 -0
  161. package/dist/xcode/index.mjs.map +1 -0
  162. package/package.json +223 -0
@@ -0,0 +1,395 @@
1
+ 'use strict';
2
+
3
+ var child_process = require('child_process');
4
+ var util = require('util');
5
+ var fs = require('fs');
6
+ var path = require('path');
7
+ var plist = require('plist');
8
+
9
+ function _interopNamespace(e) {
10
+ if (e && e.__esModule) return e;
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n.default = e;
24
+ return Object.freeze(n);
25
+ }
26
+
27
+ var plist__namespace = /*#__PURE__*/_interopNamespace(plist);
28
+
29
+ // src/trainer/index.ts
30
+
31
+ // src/xcode/platform.ts
32
+ function requireMacOS(feature) {
33
+ if (process.platform !== "darwin") {
34
+ throw new Error(
35
+ `${feature} requires macOS. This operation uses Xcode command-line tools which are not available on ${process.platform}.`
36
+ );
37
+ }
38
+ }
39
+ var execFileAsync = util.promisify(child_process.execFile);
40
+ async function parseTestResults(options) {
41
+ const inputPath = options.path ?? findTestResults();
42
+ const outputDir = options.outputDirectory ?? process.cwd();
43
+ const outputFilename = options.outputFilename ?? "report.junit";
44
+ const junitPath = path.join(outputDir, outputFilename);
45
+ if (!fs.existsSync(inputPath)) {
46
+ throw new Error("Test results not found at: " + inputPath);
47
+ }
48
+ let testSuites;
49
+ if (inputPath.endsWith(".xcresult")) {
50
+ requireMacOS("xcresult parsing");
51
+ testSuites = await parseXCResult(inputPath);
52
+ } else if (inputPath.endsWith(".plist")) {
53
+ testSuites = parsePlistResults(inputPath);
54
+ } else {
55
+ const stat = await import('fs').then(
56
+ (fs) => fs.statSync(inputPath)
57
+ );
58
+ if (stat.isDirectory()) {
59
+ requireMacOS("xcresult parsing");
60
+ testSuites = await parseXCResult(inputPath);
61
+ } else {
62
+ testSuites = parsePlistResults(inputPath);
63
+ }
64
+ }
65
+ let totalTests = 0;
66
+ let failures = 0;
67
+ let skipped = 0;
68
+ for (const suite of testSuites) {
69
+ totalTests += suite.tests;
70
+ failures += suite.failures;
71
+ for (const tc of suite.testCases) {
72
+ if (tc.time === 0 && tc.failure === null) ;
73
+ }
74
+ }
75
+ for (const suite of testSuites) {
76
+ for (const tc of suite.testCases) {
77
+ if (tc.failure === "skipped" || tc.failure === "disabled") {
78
+ skipped++;
79
+ }
80
+ }
81
+ }
82
+ const { numberOfRetries, numberOfTestsExcludingRetries, numberOfFailuresExcludingRetries } = computeRetryStats(testSuites);
83
+ const junitXml = generateJUnitXml(testSuites);
84
+ fs.writeFileSync(junitPath, junitXml, "utf-8");
85
+ const success = numberOfFailuresExcludingRetries === 0;
86
+ if (!success && options.failBuildOnError) {
87
+ throw new Error(
88
+ "Tests failed: " + numberOfFailuresExcludingRetries + " failure(s) out of " + numberOfTestsExcludingRetries + " test(s)"
89
+ );
90
+ }
91
+ return {
92
+ success,
93
+ totalTests,
94
+ failures,
95
+ skipped,
96
+ retries: numberOfRetries,
97
+ numberOfRetries,
98
+ numberOfTestsExcludingRetries,
99
+ numberOfFailuresExcludingRetries,
100
+ junitPath,
101
+ testSuites
102
+ };
103
+ }
104
+ function computeRetryStats(testSuites) {
105
+ let numberOfRetries = 0;
106
+ let uniqueTests = 0;
107
+ let uniqueFailures = 0;
108
+ for (const suite of testSuites) {
109
+ const attemptsByKey = /* @__PURE__ */ new Map();
110
+ for (const tc of suite.testCases) {
111
+ const key = `${tc.className}::${tc.name}`;
112
+ const arr = attemptsByKey.get(key) ?? [];
113
+ arr.push(tc);
114
+ attemptsByKey.set(key, arr);
115
+ }
116
+ for (const attempts of attemptsByKey.values()) {
117
+ uniqueTests++;
118
+ numberOfRetries += Math.max(0, attempts.length - 1);
119
+ const last = attempts[attempts.length - 1];
120
+ if (last.failure !== null && last.failure !== "skipped" && last.failure !== "disabled") {
121
+ uniqueFailures++;
122
+ }
123
+ }
124
+ }
125
+ return {
126
+ numberOfRetries,
127
+ numberOfTestsExcludingRetries: uniqueTests,
128
+ numberOfFailuresExcludingRetries: uniqueFailures
129
+ };
130
+ }
131
+ async function parseXCResult(xcresultPath) {
132
+ const rootJson = await xcresulttoolGet(xcresultPath);
133
+ const root = JSON.parse(rootJson);
134
+ const actions = root.actions?._values ?? [];
135
+ const testSuites = [];
136
+ for (const action of actions) {
137
+ const testsRefId = action.actionResult?.testsRef?.id?._value;
138
+ if (!testsRefId) continue;
139
+ const testsJson = await xcresulttoolGet(xcresultPath, testsRefId);
140
+ const testsRoot = JSON.parse(testsJson);
141
+ const topNodes = testsRoot.subtests?._values ?? [];
142
+ for (const node of topNodes) {
143
+ extractTestSuites(node, testSuites);
144
+ }
145
+ }
146
+ return testSuites;
147
+ }
148
+ function extractTestSuites(node, suites, parentName) {
149
+ const name = node.name?._value ?? node.identifier?._value ?? "Unknown";
150
+ const subtests = node.subtests?._values;
151
+ if (subtests && subtests.length > 0) {
152
+ const hasLeafTests = subtests.some(
153
+ (s) => !s.subtests || !s.subtests._values || s.subtests._values.length === 0
154
+ );
155
+ if (hasLeafTests) {
156
+ const testCases = [];
157
+ for (const sub of subtests) {
158
+ if (sub.subtests?._values && sub.subtests._values.length > 0) {
159
+ extractTestSuites(sub, suites, name);
160
+ } else {
161
+ testCases.push(extractTestCase(sub, name));
162
+ }
163
+ }
164
+ if (testCases.length > 0) {
165
+ const failureCount = testCases.filter((tc) => tc.failure !== null && tc.failure !== "skipped").length;
166
+ const totalTime = testCases.reduce((acc, tc) => acc + tc.time, 0);
167
+ suites.push({
168
+ name: parentName ? parentName + "." + name : name,
169
+ tests: testCases.length,
170
+ failures: failureCount,
171
+ time: totalTime,
172
+ testCases
173
+ });
174
+ }
175
+ } else {
176
+ for (const sub of subtests) {
177
+ extractTestSuites(sub, suites, name);
178
+ }
179
+ }
180
+ }
181
+ }
182
+ function extractTestCase(node, className) {
183
+ const name = node.name?._value ?? node.identifier?._value ?? "Unknown";
184
+ const duration = node.duration?._value ? parseFloat(node.duration._value) : 0;
185
+ const status = node.testStatus?._value ?? "";
186
+ let failure = null;
187
+ if (status === "Failure") {
188
+ const summaries = node.summaries?._values ?? [];
189
+ const failureMessages = [];
190
+ for (const summary of summaries) {
191
+ const failureSummaries = summary.failureSummaries?._values ?? [];
192
+ for (const fs of failureSummaries) {
193
+ const msg = fs.message?._value ?? "Test failed";
194
+ const file = fs.fileName?._value ?? "";
195
+ const line = fs.lineNumber?._value ?? "";
196
+ if (file) {
197
+ failureMessages.push(msg + " (" + file + ":" + line + ")");
198
+ } else {
199
+ failureMessages.push(msg);
200
+ }
201
+ }
202
+ }
203
+ failure = failureMessages.length > 0 ? failureMessages.join("\n") : "Test failed";
204
+ } else if (status === "Skipped") {
205
+ failure = "skipped";
206
+ }
207
+ return { name, className, time: duration, failure };
208
+ }
209
+ async function xcresulttoolGet(xcresultPath, id) {
210
+ const args = [
211
+ "xcresulttool",
212
+ "get",
213
+ "--format",
214
+ "json",
215
+ "--path",
216
+ xcresultPath
217
+ ];
218
+ if (id) {
219
+ args.push("--id", id);
220
+ }
221
+ const { stdout } = await execFileAsync("xcrun", args, {
222
+ maxBuffer: 50 * 1024 * 1024
223
+ // 50MB buffer for large results
224
+ });
225
+ return stdout;
226
+ }
227
+ function parsePlistResults(plistPath) {
228
+ const raw = fs.readFileSync(plistPath, "utf-8");
229
+ const parsed = plist__namespace.parse(raw);
230
+ const suites = [];
231
+ if (Array.isArray(parsed)) {
232
+ for (const entry of parsed) {
233
+ extractPlistSuites(entry, suites);
234
+ }
235
+ } else {
236
+ extractPlistSuites(parsed, suites);
237
+ }
238
+ return suites;
239
+ }
240
+ function extractPlistSuites(node, suites, parentName) {
241
+ const name = node.TestName ?? node.TestIdentifier ?? "Unknown";
242
+ const subtests = node.Subtests;
243
+ if (subtests && subtests.length > 0) {
244
+ const hasLeafTests = subtests.some(
245
+ (s) => !s.Subtests || s.Subtests.length === 0
246
+ );
247
+ if (hasLeafTests) {
248
+ const testCases = [];
249
+ for (const sub of subtests) {
250
+ if (sub.Subtests && sub.Subtests.length > 0) {
251
+ extractPlistSuites(sub, suites, name);
252
+ } else {
253
+ testCases.push(extractPlistTestCase(sub, name));
254
+ }
255
+ }
256
+ if (testCases.length > 0) {
257
+ const failureCount = testCases.filter(
258
+ (tc) => tc.failure !== null && tc.failure !== "skipped"
259
+ ).length;
260
+ const totalTime = testCases.reduce((acc, tc) => acc + tc.time, 0);
261
+ suites.push({
262
+ name: parentName ? parentName + "." + name : name,
263
+ tests: testCases.length,
264
+ failures: failureCount,
265
+ time: totalTime,
266
+ testCases
267
+ });
268
+ }
269
+ } else {
270
+ for (const sub of subtests) {
271
+ extractPlistSuites(sub, suites, name);
272
+ }
273
+ }
274
+ }
275
+ }
276
+ function extractPlistTestCase(node, className) {
277
+ const name = node.TestName ?? node.TestIdentifier ?? "Unknown";
278
+ const duration = node.Duration ?? 0;
279
+ const status = node.TestStatus ?? "";
280
+ let failure = null;
281
+ if (status === "Failure") {
282
+ const summaries = node.FailureSummaries ?? [];
283
+ const messages = summaries.map((s) => {
284
+ const msg = s.Message ?? "Test failed";
285
+ const file = s.FileName ?? "";
286
+ const line = s.LineNumber ?? "";
287
+ return file ? msg + " (" + file + ":" + line + ")" : msg;
288
+ });
289
+ failure = messages.length > 0 ? messages.join("\n") : "Test failed";
290
+ } else if (status === "Skipped") {
291
+ failure = "skipped";
292
+ }
293
+ return { name, className, time: duration, failure };
294
+ }
295
+ function generateJUnitXml(testSuites) {
296
+ const totalTests = testSuites.reduce((acc, s) => acc + s.tests, 0);
297
+ const totalFailures = testSuites.reduce((acc, s) => acc + s.failures, 0);
298
+ const totalTime = testSuites.reduce((acc, s) => acc + s.time, 0);
299
+ const lines = [];
300
+ lines.push('<?xml version="1.0" encoding="UTF-8"?>');
301
+ lines.push(
302
+ '<testsuites tests="' + totalTests + '" failures="' + totalFailures + '" time="' + totalTime.toFixed(3) + '">'
303
+ );
304
+ for (const suite of testSuites) {
305
+ lines.push(
306
+ ' <testsuite name="' + escapeXmlAttr(suite.name) + '" tests="' + suite.tests + '" failures="' + suite.failures + '" time="' + suite.time.toFixed(3) + '">'
307
+ );
308
+ for (const tc of suite.testCases) {
309
+ if (tc.failure === "skipped") {
310
+ lines.push(
311
+ ' <testcase classname="' + escapeXmlAttr(tc.className) + '" name="' + escapeXmlAttr(tc.name) + '" time="' + tc.time.toFixed(3) + '">'
312
+ );
313
+ lines.push(" <skipped/>");
314
+ lines.push(" </testcase>");
315
+ } else if (tc.failure !== null) {
316
+ lines.push(
317
+ ' <testcase classname="' + escapeXmlAttr(tc.className) + '" name="' + escapeXmlAttr(tc.name) + '" time="' + tc.time.toFixed(3) + '">'
318
+ );
319
+ lines.push(
320
+ ' <failure message="' + escapeXmlAttr(tc.failure) + '">'
321
+ );
322
+ lines.push(" " + escapeXmlContent(tc.failure));
323
+ lines.push(" </failure>");
324
+ lines.push(" </testcase>");
325
+ } else {
326
+ lines.push(
327
+ ' <testcase classname="' + escapeXmlAttr(tc.className) + '" name="' + escapeXmlAttr(tc.name) + '" time="' + tc.time.toFixed(3) + '"/>'
328
+ );
329
+ }
330
+ }
331
+ lines.push(" </testsuite>");
332
+ }
333
+ lines.push("</testsuites>");
334
+ return lines.join("\n") + "\n";
335
+ }
336
+ function findTestResults() {
337
+ const cwd = process.cwd();
338
+ const derivedDataPath = path.join(
339
+ process.env.HOME ?? "/tmp",
340
+ "Library",
341
+ "Developer",
342
+ "Xcode",
343
+ "DerivedData"
344
+ );
345
+ if (fs.existsSync(derivedDataPath)) {
346
+ try {
347
+ const projects = fs.readdirSync(derivedDataPath);
348
+ for (const project of projects) {
349
+ const logsDir = path.join(
350
+ derivedDataPath,
351
+ project,
352
+ "Logs",
353
+ "Test"
354
+ );
355
+ if (!fs.existsSync(logsDir)) continue;
356
+ const entries = fs.readdirSync(logsDir);
357
+ const xcresults = entries.filter((e) => e.endsWith(".xcresult")).map((e) => ({
358
+ name: e,
359
+ path: path.join(logsDir, e)
360
+ }));
361
+ if (xcresults.length > 0) {
362
+ return xcresults[xcresults.length - 1].path;
363
+ }
364
+ }
365
+ } catch {
366
+ }
367
+ }
368
+ const plistFiles = safeReaddir(cwd).filter(
369
+ (f) => f.endsWith(".plist") && f.includes("Test")
370
+ );
371
+ if (plistFiles.length > 0) {
372
+ return path.join(cwd, plistFiles[0]);
373
+ }
374
+ throw new Error(
375
+ "Could not auto-detect test results. Please specify the path option."
376
+ );
377
+ }
378
+ function safeReaddir(dir) {
379
+ try {
380
+ return fs.readdirSync(dir);
381
+ } catch {
382
+ return [];
383
+ }
384
+ }
385
+ function escapeXmlAttr(str) {
386
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
387
+ }
388
+ function escapeXmlContent(str) {
389
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
390
+ }
391
+
392
+ exports.generateJUnitXml = generateJUnitXml;
393
+ exports.parseTestResults = parseTestResults;
394
+ //# sourceMappingURL=index.cjs.map
395
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/xcode/platform.ts","../../src/trainer/index.ts"],"names":["promisify","execFile","join","existsSync","writeFileSync","readFileSync","plist","readdirSync"],"mappings":"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","file":"index.cjs","sourcesContent":["export function requireMacOS(feature: string): void {\n if (process.platform !== \"darwin\") {\n throw new Error(\n `${feature} requires macOS. This operation uses Xcode command-line tools ` +\n `which are not available on ${process.platform}.`\n );\n }\n}\n\nexport function isMacOS(): boolean {\n return process.platform === \"darwin\";\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { existsSync, readFileSync, writeFileSync, readdirSync } from \"node:fs\";\nimport { join, extname, basename } from \"node:path\";\nimport { requireMacOS } from \"../xcode/platform.js\";\nimport * as plist from \"plist\";\n\nconst execFileAsync = promisify(execFile);\n\n// ── Types ──────────────────────────────────────────────────────────────────\n\nexport interface TrainerOptions {\n path?: string;\n outputDirectory?: string;\n outputFilename?: string;\n failBuildOnError?: boolean;\n xcpretty?: boolean;\n}\n\nexport interface JUnitResult {\n success: boolean;\n totalTests: number;\n failures: number;\n skipped: number;\n /** Total number of retried test attempts across all suites. */\n retries: number;\n numberOfRetries: number;\n /** Count of unique tests after collapsing retries. */\n numberOfTestsExcludingRetries: number;\n /** Count of unique failing tests after collapsing retries (last attempt wins). */\n numberOfFailuresExcludingRetries: number;\n junitPath: string;\n testSuites: TestSuite[];\n}\n\nexport interface TestSuite {\n name: string;\n tests: number;\n failures: number;\n time: number;\n testCases: TestCase[];\n}\n\nexport interface TestCase {\n name: string;\n className: string;\n time: number;\n failure: string | null;\n}\n\n// ── xcresulttool JSON shapes ───────────────────────────────────────────────\n\ninterface XCResultValue {\n _value?: string;\n _values?: XCResultValue[];\n _type?: { _name?: string };\n}\n\ninterface XCResultActionRecord {\n actionResult?: {\n testsRef?: { id?: XCResultValue };\n };\n}\n\ninterface XCResultActionsInvocation {\n actions?: {\n _values?: XCResultActionRecord[];\n };\n}\n\ninterface XCResultTestNode {\n name?: XCResultValue;\n identifier?: XCResultValue;\n duration?: XCResultValue;\n testStatus?: XCResultValue;\n subtests?: { _values?: XCResultTestNode[] };\n summaries?: {\n _values?: Array<{\n failureSummaries?: {\n _values?: Array<{\n message?: XCResultValue;\n fileName?: XCResultValue;\n lineNumber?: XCResultValue;\n }>;\n };\n }>;\n };\n}\n\ninterface XCResultTestPlan {\n subtests?: { _values?: XCResultTestNode[] };\n name?: XCResultValue;\n}\n\n// ── plist test results shape ───────────────────────────────────────────────\n\ninterface PlistTestSuite {\n TestName?: string;\n TestIdentifier?: string;\n Duration?: number;\n TestStatus?: string;\n Subtests?: PlistTestSuite[];\n FailureSummaries?: Array<{\n Message?: string;\n FileName?: string;\n LineNumber?: number;\n }>;\n}\n\n// ── Main Entry Point ───────────────────────────────────────────────────────\n\n/**\n * Parse test results from either .xcresult bundles or .plist files,\n * generate JUnit XML, and return structured results.\n *\n * Mirrors Fastlane trainer's test_parser.rb logic.\n */\nexport async function parseTestResults(\n options: TrainerOptions,\n): Promise<JUnitResult> {\n const inputPath = options.path ?? findTestResults();\n const outputDir = options.outputDirectory ?? process.cwd();\n const outputFilename = options.outputFilename ?? \"report.junit\";\n const junitPath = join(outputDir, outputFilename);\n\n if (!existsSync(inputPath)) {\n throw new Error(\"Test results not found at: \" + inputPath);\n }\n\n let testSuites: TestSuite[];\n\n if (inputPath.endsWith(\".xcresult\")) {\n requireMacOS(\"xcresult parsing\");\n testSuites = await parseXCResult(inputPath);\n } else if (inputPath.endsWith(\".plist\")) {\n testSuites = parsePlistResults(inputPath);\n } else {\n // Try to detect: if it's a directory, it might be an xcresult bundle\n const stat = await import(\"node:fs\").then((fs) =>\n fs.statSync(inputPath),\n );\n if (stat.isDirectory()) {\n requireMacOS(\"xcresult parsing\");\n testSuites = await parseXCResult(inputPath);\n } else {\n // Attempt plist parsing as fallback\n testSuites = parsePlistResults(inputPath);\n }\n }\n\n // Compute aggregated stats\n let totalTests = 0;\n let failures = 0;\n let skipped = 0;\n\n for (const suite of testSuites) {\n totalTests += suite.tests;\n failures += suite.failures;\n for (const tc of suite.testCases) {\n if (tc.time === 0 && tc.failure === null) {\n // Heuristic: zero-duration passing tests are often skipped\n }\n }\n }\n\n // Count skipped tests (tests with name containing \"skipped\" or with specific markers)\n for (const suite of testSuites) {\n for (const tc of suite.testCases) {\n if (tc.failure === \"skipped\" || tc.failure === \"disabled\") {\n skipped++;\n }\n }\n }\n\n // Retry detection: xcresult emits one TestCase per attempt of the same\n // (className, name). The final attempt wins for pass/fail. Count the\n // retry attempts that preceded it and compute retry-adjusted totals.\n const { numberOfRetries, numberOfTestsExcludingRetries, numberOfFailuresExcludingRetries } =\n computeRetryStats(testSuites);\n\n // Generate JUnit XML\n const junitXml = generateJUnitXml(testSuites);\n writeFileSync(junitPath, junitXml, \"utf-8\");\n\n const success = numberOfFailuresExcludingRetries === 0;\n\n if (!success && options.failBuildOnError) {\n throw new Error(\n \"Tests failed: \" + numberOfFailuresExcludingRetries + \" failure(s) out of \" +\n numberOfTestsExcludingRetries + \" test(s)\",\n );\n }\n\n return {\n success,\n totalTests,\n failures,\n skipped,\n retries: numberOfRetries,\n numberOfRetries,\n numberOfTestsExcludingRetries,\n numberOfFailuresExcludingRetries,\n junitPath,\n testSuites,\n };\n}\n\nfunction computeRetryStats(testSuites: TestSuite[]): {\n numberOfRetries: number;\n numberOfTestsExcludingRetries: number;\n numberOfFailuresExcludingRetries: number;\n} {\n let numberOfRetries = 0;\n let uniqueTests = 0;\n let uniqueFailures = 0;\n\n for (const suite of testSuites) {\n const attemptsByKey = new Map<string, TestCase[]>();\n for (const tc of suite.testCases) {\n const key = `${tc.className}::${tc.name}`;\n const arr = attemptsByKey.get(key) ?? [];\n arr.push(tc);\n attemptsByKey.set(key, arr);\n }\n for (const attempts of attemptsByKey.values()) {\n uniqueTests++;\n numberOfRetries += Math.max(0, attempts.length - 1);\n const last = attempts[attempts.length - 1];\n // Only real failures count — not \"skipped\" markers.\n if (last.failure !== null && last.failure !== \"skipped\" && last.failure !== \"disabled\") {\n uniqueFailures++;\n }\n }\n }\n\n return {\n numberOfRetries,\n numberOfTestsExcludingRetries: uniqueTests,\n numberOfFailuresExcludingRetries: uniqueFailures,\n };\n}\n\n// ── xcresult Parsing ───────────────────────────────────────────────────────\n\nasync function parseXCResult(xcresultPath: string): Promise<TestSuite[]> {\n // Step 1: Get the top-level invocation record\n const rootJson = await xcresulttoolGet(xcresultPath);\n const root = JSON.parse(rootJson) as XCResultActionsInvocation;\n\n const actions = root.actions?._values ?? [];\n const testSuites: TestSuite[] = [];\n\n for (const action of actions) {\n const testsRefId = action.actionResult?.testsRef?.id?._value;\n if (!testsRefId) continue;\n\n // Step 2: Get the test plan run summaries using the ref id\n const testsJson = await xcresulttoolGet(xcresultPath, testsRefId);\n const testsRoot = JSON.parse(testsJson) as XCResultTestPlan;\n\n // Step 3: Walk the test tree to extract suites and cases\n const topNodes = testsRoot.subtests?._values ?? [];\n for (const node of topNodes) {\n extractTestSuites(node, testSuites);\n }\n }\n\n return testSuites;\n}\n\nfunction extractTestSuites(\n node: XCResultTestNode,\n suites: TestSuite[],\n parentName?: string,\n): void {\n const name = node.name?._value ?? node.identifier?._value ?? \"Unknown\";\n const subtests = node.subtests?._values;\n\n if (subtests && subtests.length > 0) {\n // Check if children are leaf test cases or more groups\n const hasLeafTests = subtests.some(\n (s) => !s.subtests || !s.subtests._values || s.subtests._values.length === 0,\n );\n\n if (hasLeafTests) {\n // This node is a test suite containing test cases\n const testCases: TestCase[] = [];\n\n for (const sub of subtests) {\n if (sub.subtests?._values && sub.subtests._values.length > 0) {\n // Nested group -- recurse\n extractTestSuites(sub, suites, name);\n } else {\n // Leaf test case\n testCases.push(extractTestCase(sub, name));\n }\n }\n\n if (testCases.length > 0) {\n const failureCount = testCases.filter((tc) => tc.failure !== null && tc.failure !== \"skipped\").length;\n const totalTime = testCases.reduce((acc, tc) => acc + tc.time, 0);\n\n suites.push({\n name: parentName ? parentName + \".\" + name : name,\n tests: testCases.length,\n failures: failureCount,\n time: totalTime,\n testCases,\n });\n }\n } else {\n // All children are groups -- recurse deeper\n for (const sub of subtests) {\n extractTestSuites(sub, suites, name);\n }\n }\n }\n}\n\nfunction extractTestCase(\n node: XCResultTestNode,\n className: string,\n): TestCase {\n const name = node.name?._value ?? node.identifier?._value ?? \"Unknown\";\n const duration = node.duration?._value ? parseFloat(node.duration._value) : 0;\n const status = node.testStatus?._value ?? \"\";\n\n let failure: string | null = null;\n\n if (status === \"Failure\") {\n // Extract failure message from summaries\n const summaries = node.summaries?._values ?? [];\n const failureMessages: string[] = [];\n\n for (const summary of summaries) {\n const failureSummaries = summary.failureSummaries?._values ?? [];\n for (const fs of failureSummaries) {\n const msg = fs.message?._value ?? \"Test failed\";\n const file = fs.fileName?._value ?? \"\";\n const line = fs.lineNumber?._value ?? \"\";\n if (file) {\n failureMessages.push(msg + \" (\" + file + \":\" + line + \")\");\n } else {\n failureMessages.push(msg);\n }\n }\n }\n\n failure = failureMessages.length > 0\n ? failureMessages.join(\"\\n\")\n : \"Test failed\";\n } else if (status === \"Skipped\") {\n failure = \"skipped\";\n }\n\n return { name, className, time: duration, failure };\n}\n\nasync function xcresulttoolGet(\n xcresultPath: string,\n id?: string,\n): Promise<string> {\n const args = [\n \"xcresulttool\",\n \"get\",\n \"--format\",\n \"json\",\n \"--path\",\n xcresultPath,\n ];\n\n if (id) {\n args.push(\"--id\", id);\n }\n\n const { stdout } = await execFileAsync(\"xcrun\", args, {\n maxBuffer: 50 * 1024 * 1024, // 50MB buffer for large results\n });\n\n return stdout;\n}\n\n// ── Plist Parsing ──────────────────────────────────────────────────────────\n\nfunction parsePlistResults(plistPath: string): TestSuite[] {\n const raw = readFileSync(plistPath, \"utf-8\");\n const parsed = plist.parse(raw);\n\n // The plist can be either a single test suite dict or an array\n const suites: TestSuite[] = [];\n\n if (Array.isArray(parsed)) {\n for (const entry of parsed) {\n extractPlistSuites(entry as PlistTestSuite, suites);\n }\n } else {\n extractPlistSuites(parsed as PlistTestSuite, suites);\n }\n\n return suites;\n}\n\nfunction extractPlistSuites(\n node: PlistTestSuite,\n suites: TestSuite[],\n parentName?: string,\n): void {\n const name =\n node.TestName ?? node.TestIdentifier ?? \"Unknown\";\n const subtests = node.Subtests;\n\n if (subtests && subtests.length > 0) {\n const hasLeafTests = subtests.some(\n (s) => !s.Subtests || s.Subtests.length === 0,\n );\n\n if (hasLeafTests) {\n const testCases: TestCase[] = [];\n\n for (const sub of subtests) {\n if (sub.Subtests && sub.Subtests.length > 0) {\n extractPlistSuites(sub, suites, name);\n } else {\n testCases.push(extractPlistTestCase(sub, name));\n }\n }\n\n if (testCases.length > 0) {\n const failureCount = testCases.filter(\n (tc) => tc.failure !== null && tc.failure !== \"skipped\",\n ).length;\n const totalTime = testCases.reduce((acc, tc) => acc + tc.time, 0);\n\n suites.push({\n name: parentName ? parentName + \".\" + name : name,\n tests: testCases.length,\n failures: failureCount,\n time: totalTime,\n testCases,\n });\n }\n } else {\n for (const sub of subtests) {\n extractPlistSuites(sub, suites, name);\n }\n }\n }\n}\n\nfunction extractPlistTestCase(\n node: PlistTestSuite,\n className: string,\n): TestCase {\n const name =\n node.TestName ?? node.TestIdentifier ?? \"Unknown\";\n const duration = node.Duration ?? 0;\n const status = node.TestStatus ?? \"\";\n\n let failure: string | null = null;\n\n if (status === \"Failure\") {\n const summaries = node.FailureSummaries ?? [];\n const messages = summaries.map((s) => {\n const msg = s.Message ?? \"Test failed\";\n const file = s.FileName ?? \"\";\n const line = s.LineNumber ?? \"\";\n return file ? msg + \" (\" + file + \":\" + line + \")\" : msg;\n });\n failure = messages.length > 0 ? messages.join(\"\\n\") : \"Test failed\";\n } else if (status === \"Skipped\") {\n failure = \"skipped\";\n }\n\n return { name, className, time: duration, failure };\n}\n\n// ── JUnit XML Generation ───────────────────────────────────────────────────\n\n/**\n * Generate a JUnit XML string from test suites.\n * Mirrors Fastlane trainer's junit_generator.rb output format.\n */\nexport function generateJUnitXml(testSuites: TestSuite[]): string {\n const totalTests = testSuites.reduce((acc, s) => acc + s.tests, 0);\n const totalFailures = testSuites.reduce((acc, s) => acc + s.failures, 0);\n const totalTime = testSuites.reduce((acc, s) => acc + s.time, 0);\n\n const lines: string[] = [];\n lines.push('<?xml version=\"1.0\" encoding=\"UTF-8\"?>');\n lines.push(\n '<testsuites tests=\"' + totalTests +\n '\" failures=\"' + totalFailures +\n '\" time=\"' + totalTime.toFixed(3) + '\">',\n );\n\n for (const suite of testSuites) {\n lines.push(\n ' <testsuite name=\"' + escapeXmlAttr(suite.name) +\n '\" tests=\"' + suite.tests +\n '\" failures=\"' + suite.failures +\n '\" time=\"' + suite.time.toFixed(3) + '\">',\n );\n\n for (const tc of suite.testCases) {\n if (tc.failure === \"skipped\") {\n lines.push(\n ' <testcase classname=\"' + escapeXmlAttr(tc.className) +\n '\" name=\"' + escapeXmlAttr(tc.name) +\n '\" time=\"' + tc.time.toFixed(3) + '\">',\n );\n lines.push(\" <skipped/>\");\n lines.push(\" </testcase>\");\n } else if (tc.failure !== null) {\n lines.push(\n ' <testcase classname=\"' + escapeXmlAttr(tc.className) +\n '\" name=\"' + escapeXmlAttr(tc.name) +\n '\" time=\"' + tc.time.toFixed(3) + '\">',\n );\n lines.push(\n ' <failure message=\"' + escapeXmlAttr(tc.failure) + '\">',\n );\n lines.push(\" \" + escapeXmlContent(tc.failure));\n lines.push(\" </failure>\");\n lines.push(\" </testcase>\");\n } else {\n lines.push(\n ' <testcase classname=\"' + escapeXmlAttr(tc.className) +\n '\" name=\"' + escapeXmlAttr(tc.name) +\n '\" time=\"' + tc.time.toFixed(3) + '\"/>',\n );\n }\n }\n\n lines.push(\" </testsuite>\");\n }\n\n lines.push(\"</testsuites>\");\n\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n// ── Helpers ────────────────────────────────────────────────────────────────\n\n/**\n * Auto-detect test results path. Searches common locations.\n */\nfunction findTestResults(): string {\n const cwd = process.cwd();\n\n // Check for xcresult in common derived data locations\n const derivedDataPath = join(\n process.env.HOME ?? \"/tmp\",\n \"Library\",\n \"Developer\",\n \"Xcode\",\n \"DerivedData\",\n );\n\n if (existsSync(derivedDataPath)) {\n try {\n const projects = readdirSync(derivedDataPath);\n for (const project of projects) {\n const logsDir = join(\n derivedDataPath,\n project,\n \"Logs\",\n \"Test\",\n );\n if (!existsSync(logsDir)) continue;\n\n const entries = readdirSync(logsDir);\n const xcresults = entries\n .filter((e) => e.endsWith(\".xcresult\"))\n .map((e) => ({\n name: e,\n path: join(logsDir, e),\n }));\n\n if (xcresults.length > 0) {\n // Return the most recently modified one\n return xcresults[xcresults.length - 1].path;\n }\n }\n } catch {\n // Ignore errors scanning derived data\n }\n }\n\n // Check for plist in current directory\n const plistFiles = safeReaddir(cwd).filter(\n (f) => f.endsWith(\".plist\") && f.includes(\"Test\"),\n );\n if (plistFiles.length > 0) {\n return join(cwd, plistFiles[0]);\n }\n\n throw new Error(\n \"Could not auto-detect test results. Please specify the path option.\",\n );\n}\n\nfunction safeReaddir(dir: string): string[] {\n try {\n return readdirSync(dir);\n } catch {\n return [];\n }\n}\n\nfunction escapeXmlAttr(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&apos;\");\n}\n\nfunction escapeXmlContent(str: string): string {\n return str\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n}\n"]}
@@ -0,0 +1 @@
1
+ export { J as JUnitResult, b as TestCase, a as TestSuite, T as TrainerOptions, g as generateJUnitXml, p as parseTestResults } from '../index-BoU8qt8r.cjs';
@@ -0,0 +1 @@
1
+ export { J as JUnitResult, b as TestCase, a as TestSuite, T as TrainerOptions, g as generateJUnitXml, p as parseTestResults } from '../index-BoU8qt8r.js';