@solidxai/core 0.1.13-beta.11 → 0.1.13-beta.13

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 (103) hide show
  1. package/.claude/settings.local.json +16 -0
  2. package/CHANGELOG.md +1128 -0
  3. package/CLAUDE.md +26 -0
  4. package/dist/commands/run-tests.command.d.ts +2 -0
  5. package/dist/commands/run-tests.command.d.ts.map +1 -1
  6. package/dist/commands/run-tests.command.js +20 -3
  7. package/dist/commands/run-tests.command.js.map +1 -1
  8. package/dist/seeders/seed-data/solid-core-metadata.json +1 -1
  9. package/dist/services/chatter-message.service.d.ts +4 -1
  10. package/dist/services/chatter-message.service.d.ts.map +1 -1
  11. package/dist/services/chatter-message.service.js +4 -1
  12. package/dist/services/chatter-message.service.js.map +1 -1
  13. package/dist/services/crud-helper.service.d.ts +1 -2
  14. package/dist/services/crud-helper.service.d.ts.map +1 -1
  15. package/dist/services/crud-helper.service.js +2 -16
  16. package/dist/services/crud-helper.service.js.map +1 -1
  17. package/dist/services/crud.service.d.ts.map +1 -1
  18. package/dist/services/crud.service.js +1 -1
  19. package/dist/services/crud.service.js.map +1 -1
  20. package/dist/services/draft-publish-helper.service.d.ts +1 -0
  21. package/dist/services/draft-publish-helper.service.d.ts.map +1 -1
  22. package/dist/services/draft-publish-helper.service.js +38 -4
  23. package/dist/services/draft-publish-helper.service.js.map +1 -1
  24. package/dist/services/settings/default-settings-provider.service.d.ts +62 -6
  25. package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
  26. package/dist/services/settings/default-settings-provider.service.js +34 -3
  27. package/dist/services/settings/default-settings-provider.service.js.map +1 -1
  28. package/dist/testing/reporter/console-reporter.d.ts +3 -0
  29. package/dist/testing/reporter/console-reporter.d.ts.map +1 -1
  30. package/dist/testing/reporter/console-reporter.js +2 -0
  31. package/dist/testing/reporter/console-reporter.js.map +1 -1
  32. package/dist/testing/reporter/progress-reporter.d.ts +64 -0
  33. package/dist/testing/reporter/progress-reporter.d.ts.map +1 -0
  34. package/dist/testing/reporter/progress-reporter.js +224 -0
  35. package/dist/testing/reporter/progress-reporter.js.map +1 -0
  36. package/dist/testing/reporter/reporter.types.d.ts +3 -0
  37. package/dist/testing/reporter/reporter.types.d.ts.map +1 -1
  38. package/dist/testing/reporter/reporter.types.js.map +1 -1
  39. package/dist/testing/runner/run-from-metadata.d.ts.map +1 -1
  40. package/dist/testing/runner/run-from-metadata.js +1 -0
  41. package/dist/testing/runner/run-from-metadata.js.map +1 -1
  42. package/dist/theme/theme-registry.d.ts +14 -0
  43. package/dist/theme/theme-registry.d.ts.map +1 -0
  44. package/dist/theme/theme-registry.js +147 -0
  45. package/dist/theme/theme-registry.js.map +1 -0
  46. package/package.json +1 -1
  47. package/src/commands/run-tests.command.ts +17 -3
  48. package/src/seeders/seed-data/solid-core-metadata.json +1 -1
  49. package/src/services/1.js +6 -0
  50. package/src/services/chatter-message.service.ts +22 -1
  51. package/src/services/crud-helper.service.ts +19 -16
  52. package/src/services/crud.service.ts +2 -1
  53. package/src/services/draft-publish-helper.service.ts +56 -4
  54. package/src/services/settings/default-settings-provider.service.ts +34 -3
  55. package/src/testing/README.md +2 -1
  56. package/src/testing/reporter/console-reporter.ts +4 -0
  57. package/src/testing/reporter/progress-reporter.ts +251 -0
  58. package/src/testing/reporter/reporter.types.ts +3 -0
  59. package/src/testing/runner/run-from-metadata.ts +1 -0
  60. package/src/theme/theme-registry.ts +181 -0
  61. package/dist-tests/api/authenticate.spec.js +0 -119
  62. package/dist-tests/api/authenticate.spec.js.map +0 -1
  63. package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +0 -97
  64. package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +0 -1
  65. package/dist-tests/api/ping.spec.js +0 -21
  66. package/dist-tests/api/ping.spec.js.map +0 -1
  67. package/dist-tests/helpers/auth.js +0 -41
  68. package/dist-tests/helpers/auth.js.map +0 -1
  69. package/dist-tests/helpers/env.js +0 -11
  70. package/dist-tests/helpers/env.js.map +0 -1
  71. package/docs/agent-builder/notebook-lm-prompt-for-agent-builder.md +0 -136
  72. package/docs/agent-builder/team-ready-note-agent-builder.md +0 -305
  73. package/docs/agent-hub-grooming.md +0 -301
  74. package/docs/dashboards/AGENTIC_DASHBOARD_IMPLEMENTATION_PLAN.md +0 -438
  75. package/docs/dashboards/dashboard-curl-smoke-tests.txt +0 -146
  76. package/docs/dashboards/delete-legacy-dashboard-metadata.sql +0 -172
  77. package/docs/datasource-introspection-ddl-analysis.md +0 -326
  78. package/docs/datasource-introspection-implementation-plan.md +0 -306
  79. package/docs/grouping-enhancements.md +0 -89
  80. package/docs/java-spring/README.md +0 -3
  81. package/docs/java-spring/solid-core-module-deep-dive-report.md +0 -1317
  82. package/docs/module-package-import-handoff.md +0 -691
  83. package/docs/seed-changes.md +0 -65
  84. package/docs/test-data-workflow.md +0 -200
  85. package/docs/type-declaration-import-issue.md +0 -24
  86. package/docs/workflow/business-automation-example-notes.md +0 -309
  87. package/docs/workflow/control-flow-node-addition-sop.md +0 -324
  88. package/docs/workflow/data-engineering-pipeline-example-notes.md +0 -330
  89. package/docs/workflow/foreach-example-notes.md +0 -187
  90. package/docs/workflow/hello-world-example-notes.md +0 -271
  91. package/docs/workflow/kestra-concepts-plugins-blueprints.md +0 -315
  92. package/docs/workflow/loop-until-example-notes.md +0 -198
  93. package/docs/workflow/microservices-and-apis-example-notes.md +0 -264
  94. package/docs/workflow/samples.md +0 -25
  95. package/docs/workflow/what-is-kestra.md +0 -79
  96. package/docs/workflow/workflow-core-module-handoff-summary.md +0 -191
  97. package/docs/workflow/workflow-module-brd.md +0 -185
  98. package/docs/workflow/workflow-module-domain-model.md +0 -252
  99. package/docs/workflow/workflow-module-metadata-dsl.md +0 -302
  100. package/docs/workflow/workflow-module-technical-spec.md +0 -293
  101. package/docs/workflow/workflow-node-type-contracts.md +0 -635
  102. package/docs/workflow/workflow-node-ui-metadata-contract.md +0 -1262
  103. package/docs/workflow/workflow-solidx-model-field-spec.md +0 -284
@@ -0,0 +1,64 @@
1
+ import type { StepPhase } from "../contracts/runtime-context.types";
2
+ import type { OpStep, ScenarioSpec } from "../contracts/testing-metadata.types";
3
+ import type { SolidTestSpecResult } from "../contracts/test-spec.types";
4
+ import type { Reporter } from "./reporter.types";
5
+ export declare class ProgressReporter implements Reporter {
6
+ private readonly delegate;
7
+ private startedAt;
8
+ private total;
9
+ private completed;
10
+ private passed;
11
+ private failed;
12
+ private timer?;
13
+ private rendered;
14
+ constructor(delegate: Reporter);
15
+ onRunStart(args: {
16
+ total: number;
17
+ }): void;
18
+ onScenarioStart(scenario: ScenarioSpec): void;
19
+ onScenarioEnd(scenario: ScenarioSpec, result: {
20
+ ok: boolean;
21
+ error?: unknown;
22
+ durationMs: number;
23
+ }): void;
24
+ onStepStart(args: {
25
+ scenarioId: string;
26
+ phase: StepPhase;
27
+ step: OpStep;
28
+ }): void;
29
+ onStepEnd(args: {
30
+ scenarioId: string;
31
+ phase: StepPhase;
32
+ step: OpStep;
33
+ ok: boolean;
34
+ error?: unknown;
35
+ durationMs: number;
36
+ }): void;
37
+ onSpecResult(args: {
38
+ scenarioId: string;
39
+ specId: string;
40
+ stepName?: string;
41
+ result: SolidTestSpecResult;
42
+ }): void;
43
+ attach(args: {
44
+ scenarioId: string;
45
+ name: string;
46
+ contentType: string;
47
+ data: Buffer | string;
48
+ }): void;
49
+ onRunEnd(args: {
50
+ ok: boolean;
51
+ total: number;
52
+ passed: number;
53
+ failed: number;
54
+ durationMs: number;
55
+ }): void;
56
+ private startTimer;
57
+ private stopTimer;
58
+ private withFooterPaused;
59
+ private renderFooter;
60
+ private clearFooter;
61
+ private renderProgressBar;
62
+ private isInteractive;
63
+ }
64
+ //# sourceMappingURL=progress-reporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-reporter.d.ts","sourceRoot":"","sources":["../../../src/testing/reporter/progress-reporter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAChF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAWjD,qBAAa,gBAAiB,YAAW,QAAQ;IASnC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IARrC,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,KAAK,CAAC,CAAiB;IAC/B,OAAO,CAAC,QAAQ,CAAS;gBAEI,QAAQ,EAAE,QAAQ;IAE/C,UAAU,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAWzC,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI;IAI7C,aAAa,CACX,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAC3D,IAAI;IAUP,WAAW,CAAC,IAAI,EAAE;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,SAAS,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,GAAG,IAAI;IAIR,SAAS,CAAC,IAAI,EAAE;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,SAAS,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,EAAE,EAAE,OAAO,CAAC;QACZ,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,IAAI;IAIR,YAAY,CAAC,IAAI,EAAE;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,mBAAmB,CAAC;KAC7B,GAAG,IAAI;IAIR,MAAM,CAAC,IAAI,EAAE;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;KACvB,GAAG,IAAI;IAIR,QAAQ,CAAC,IAAI,EAAE;QACb,EAAE,EAAE,OAAO,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,IAAI;IASR,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,SAAS;IAQjB,OAAO,CAAC,gBAAgB;IAQxB,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,aAAa;CAGtB"}
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.ProgressReporter = void 0;
37
+ const readline = __importStar(require("readline"));
38
+ const ANSI_BOLD = "\u001b[1m";
39
+ const ANSI_BOLD_OFF = "\u001b[22m";
40
+ const ANSI_DIM = "\u001b[2m";
41
+ const ANSI_GREEN = "\u001b[32m";
42
+ const ANSI_COLOR_OFF = "\u001b[39m";
43
+ const ANSI_RED = "\u001b[31m";
44
+ const ANSI_INVERSE = "\u001b[7m";
45
+ const ANSI_INVERSE_OFF = "\u001b[27m";
46
+ class ProgressReporter {
47
+ constructor(delegate) {
48
+ this.delegate = delegate;
49
+ this.startedAt = Date.now();
50
+ this.total = 0;
51
+ this.completed = 0;
52
+ this.passed = 0;
53
+ this.failed = 0;
54
+ this.rendered = false;
55
+ }
56
+ onRunStart(args) {
57
+ this.total = args.total;
58
+ this.startedAt = Date.now();
59
+ this.completed = 0;
60
+ this.passed = 0;
61
+ this.failed = 0;
62
+ this.delegate.onRunStart?.(args);
63
+ this.startTimer();
64
+ this.renderFooter();
65
+ }
66
+ onScenarioStart(scenario) {
67
+ this.withFooterPaused(() => this.delegate.onScenarioStart(scenario));
68
+ }
69
+ onScenarioEnd(scenario, result) {
70
+ this.completed += 1;
71
+ if (result.ok) {
72
+ this.passed += 1;
73
+ }
74
+ else {
75
+ this.failed += 1;
76
+ }
77
+ this.withFooterPaused(() => this.delegate.onScenarioEnd(scenario, result));
78
+ }
79
+ onStepStart(args) {
80
+ this.withFooterPaused(() => this.delegate.onStepStart(args));
81
+ }
82
+ onStepEnd(args) {
83
+ this.withFooterPaused(() => this.delegate.onStepEnd(args));
84
+ }
85
+ onSpecResult(args) {
86
+ this.withFooterPaused(() => this.delegate.onSpecResult?.(args));
87
+ }
88
+ attach(args) {
89
+ this.withFooterPaused(() => this.delegate.attach?.(args));
90
+ }
91
+ onRunEnd(args) {
92
+ this.completed = args.passed + args.failed;
93
+ this.passed = args.passed;
94
+ this.failed = args.failed;
95
+ this.total = args.total;
96
+ this.stopTimer();
97
+ this.withFooterPaused(() => this.delegate.onRunEnd?.(args), false);
98
+ }
99
+ startTimer() {
100
+ this.stopTimer();
101
+ if (!this.isInteractive()) {
102
+ return;
103
+ }
104
+ this.timer = setInterval(() => this.renderFooter(), 1_000);
105
+ this.timer.unref?.();
106
+ }
107
+ stopTimer() {
108
+ if (!this.timer) {
109
+ return;
110
+ }
111
+ clearInterval(this.timer);
112
+ this.timer = undefined;
113
+ }
114
+ withFooterPaused(callback, renderAfter = true) {
115
+ this.clearFooter();
116
+ callback();
117
+ if (renderAfter) {
118
+ this.renderFooter();
119
+ }
120
+ }
121
+ renderFooter() {
122
+ if (!this.isInteractive()) {
123
+ return;
124
+ }
125
+ const terminalWidth = process.stdout.columns || 80;
126
+ const elapsed = formatElapsed(Date.now() - this.startedAt);
127
+ const progressText = `${this.completed}/${this.total}`;
128
+ const resultText = `${ANSI_GREEN}${this.passed} passed${ANSI_COLOR_OFF}${ANSI_DIM} | ${ANSI_BOLD_OFF}${this.failed ? ANSI_RED : ANSI_DIM}${this.failed} failed${this.failed ? ANSI_COLOR_OFF : ANSI_BOLD_OFF}`;
129
+ const footer = [
130
+ `${ANSI_BOLD}Tests${ANSI_BOLD_OFF}: ${this.renderProgressBar(terminalWidth)} ${progressText}`,
131
+ `${ANSI_BOLD}Elapsed${ANSI_BOLD_OFF}: ${elapsed}`,
132
+ resultText,
133
+ ].join(`${ANSI_DIM} | ${ANSI_BOLD_OFF}`);
134
+ readline.clearLine(process.stdout, 0);
135
+ readline.cursorTo(process.stdout, 0);
136
+ process.stdout.write(truncateAnsiText(`${ANSI_INVERSE} ${footer} ${ANSI_INVERSE_OFF}`, terminalWidth));
137
+ this.rendered = true;
138
+ }
139
+ clearFooter() {
140
+ if (!this.rendered || !this.isInteractive()) {
141
+ return;
142
+ }
143
+ readline.clearLine(process.stdout, 0);
144
+ readline.cursorTo(process.stdout, 0);
145
+ this.rendered = false;
146
+ }
147
+ renderProgressBar(terminalWidth) {
148
+ const width = terminalWidth >= 120 ? 30 : terminalWidth >= 90 ? 22 : 14;
149
+ const ratio = this.total > 0 ? Math.min(1, this.completed / this.total) : 0;
150
+ const filled = Math.round(width * ratio);
151
+ const empty = Math.max(0, width - filled);
152
+ return `[${ANSI_GREEN}${"=".repeat(filled)}${ANSI_COLOR_OFF}${" ".repeat(empty)}]`;
153
+ }
154
+ isInteractive() {
155
+ return Boolean(process.stdout.isTTY || process.env.SOLIDCTL_TEST_PROGRESS === "1");
156
+ }
157
+ }
158
+ exports.ProgressReporter = ProgressReporter;
159
+ function formatElapsed(durationMs) {
160
+ const totalSeconds = Math.max(0, Math.floor(durationMs / 1000));
161
+ const minutes = Math.floor(totalSeconds / 60);
162
+ const seconds = totalSeconds % 60;
163
+ if (minutes < 60) {
164
+ return `${minutes}:${seconds.toString().padStart(2, "0")}`;
165
+ }
166
+ const hours = Math.floor(minutes / 60);
167
+ const remainingMinutes = minutes % 60;
168
+ return `${hours}:${remainingMinutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
169
+ }
170
+ function truncateAnsiText(text, maxWidth) {
171
+ if (maxWidth <= 0) {
172
+ return "";
173
+ }
174
+ let visibleWidth = 0;
175
+ let index = 0;
176
+ let output = "";
177
+ let hasEscape = false;
178
+ while (index < text.length) {
179
+ if (text[index] === "\u001b") {
180
+ const match = /\u001b\[[0-9;]*m/.exec(text.slice(index));
181
+ if (!match) {
182
+ break;
183
+ }
184
+ output += match[0];
185
+ hasEscape = true;
186
+ index += match[0].length;
187
+ continue;
188
+ }
189
+ if (visibleWidth >= maxWidth) {
190
+ break;
191
+ }
192
+ output += text[index];
193
+ visibleWidth += 1;
194
+ index += 1;
195
+ }
196
+ if (index < text.length && maxWidth >= 1) {
197
+ output = trimAnsiText(output, maxWidth - 1) + "…";
198
+ }
199
+ if (hasEscape && !output.endsWith(ANSI_INVERSE_OFF)) {
200
+ output += ANSI_INVERSE_OFF;
201
+ }
202
+ return output;
203
+ }
204
+ function trimAnsiText(text, maxWidth) {
205
+ let visibleWidth = 0;
206
+ let index = 0;
207
+ let output = "";
208
+ while (index < text.length && visibleWidth < maxWidth) {
209
+ if (text[index] === "\u001b") {
210
+ const match = /\u001b\[[0-9;]*m/.exec(text.slice(index));
211
+ if (!match) {
212
+ break;
213
+ }
214
+ output += match[0];
215
+ index += match[0].length;
216
+ continue;
217
+ }
218
+ output += text[index];
219
+ visibleWidth += 1;
220
+ index += 1;
221
+ }
222
+ return output;
223
+ }
224
+ //# sourceMappingURL=progress-reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress-reporter.js","sourceRoot":"","sources":["../../../src/testing/reporter/progress-reporter.ts"],"names":[],"mappings":"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","sourcesContent":["import * as readline from \"readline\";\nimport type { StepPhase } from \"../contracts/runtime-context.types\";\nimport type { OpStep, ScenarioSpec } from \"../contracts/testing-metadata.types\";\nimport type { SolidTestSpecResult } from \"../contracts/test-spec.types\";\nimport type { Reporter } from \"./reporter.types\";\n\nconst ANSI_BOLD = \"\\u001b[1m\";\nconst ANSI_BOLD_OFF = \"\\u001b[22m\";\nconst ANSI_DIM = \"\\u001b[2m\";\nconst ANSI_GREEN = \"\\u001b[32m\";\nconst ANSI_COLOR_OFF = \"\\u001b[39m\";\nconst ANSI_RED = \"\\u001b[31m\";\nconst ANSI_INVERSE = \"\\u001b[7m\";\nconst ANSI_INVERSE_OFF = \"\\u001b[27m\";\n\nexport class ProgressReporter implements Reporter {\n private startedAt = Date.now();\n private total = 0;\n private completed = 0;\n private passed = 0;\n private failed = 0;\n private timer?: NodeJS.Timeout;\n private rendered = false;\n\n constructor(private readonly delegate: Reporter) {}\n\n onRunStart(args: { total: number }): void {\n this.total = args.total;\n this.startedAt = Date.now();\n this.completed = 0;\n this.passed = 0;\n this.failed = 0;\n this.delegate.onRunStart?.(args);\n this.startTimer();\n this.renderFooter();\n }\n\n onScenarioStart(scenario: ScenarioSpec): void {\n this.withFooterPaused(() => this.delegate.onScenarioStart(scenario));\n }\n\n onScenarioEnd(\n scenario: ScenarioSpec,\n result: { ok: boolean; error?: unknown; durationMs: number },\n ): void {\n this.completed += 1;\n if (result.ok) {\n this.passed += 1;\n } else {\n this.failed += 1;\n }\n this.withFooterPaused(() => this.delegate.onScenarioEnd(scenario, result));\n }\n\n onStepStart(args: {\n scenarioId: string;\n phase: StepPhase;\n step: OpStep;\n }): void {\n this.withFooterPaused(() => this.delegate.onStepStart(args));\n }\n\n onStepEnd(args: {\n scenarioId: string;\n phase: StepPhase;\n step: OpStep;\n ok: boolean;\n error?: unknown;\n durationMs: number;\n }): void {\n this.withFooterPaused(() => this.delegate.onStepEnd(args));\n }\n\n onSpecResult(args: {\n scenarioId: string;\n specId: string;\n stepName?: string;\n result: SolidTestSpecResult;\n }): void {\n this.withFooterPaused(() => this.delegate.onSpecResult?.(args));\n }\n\n attach(args: {\n scenarioId: string;\n name: string;\n contentType: string;\n data: Buffer | string;\n }): void {\n this.withFooterPaused(() => this.delegate.attach?.(args));\n }\n\n onRunEnd(args: {\n ok: boolean;\n total: number;\n passed: number;\n failed: number;\n durationMs: number;\n }): void {\n this.completed = args.passed + args.failed;\n this.passed = args.passed;\n this.failed = args.failed;\n this.total = args.total;\n this.stopTimer();\n this.withFooterPaused(() => this.delegate.onRunEnd?.(args), false);\n }\n\n private startTimer(): void {\n this.stopTimer();\n if (!this.isInteractive()) {\n return;\n }\n this.timer = setInterval(() => this.renderFooter(), 1_000);\n this.timer.unref?.();\n }\n\n private stopTimer(): void {\n if (!this.timer) {\n return;\n }\n clearInterval(this.timer);\n this.timer = undefined;\n }\n\n private withFooterPaused(callback: () => void, renderAfter = true): void {\n this.clearFooter();\n callback();\n if (renderAfter) {\n this.renderFooter();\n }\n }\n\n private renderFooter(): void {\n if (!this.isInteractive()) {\n return;\n }\n\n const terminalWidth = process.stdout.columns || 80;\n const elapsed = formatElapsed(Date.now() - this.startedAt);\n const progressText = `${this.completed}/${this.total}`;\n const resultText = `${ANSI_GREEN}${this.passed} passed${ANSI_COLOR_OFF}${ANSI_DIM} | ${ANSI_BOLD_OFF}${this.failed ? ANSI_RED : ANSI_DIM}${this.failed} failed${this.failed ? ANSI_COLOR_OFF : ANSI_BOLD_OFF}`;\n const footer = [\n `${ANSI_BOLD}Tests${ANSI_BOLD_OFF}: ${this.renderProgressBar(terminalWidth)} ${progressText}`,\n `${ANSI_BOLD}Elapsed${ANSI_BOLD_OFF}: ${elapsed}`,\n resultText,\n ].join(`${ANSI_DIM} | ${ANSI_BOLD_OFF}`);\n\n readline.clearLine(process.stdout, 0);\n readline.cursorTo(process.stdout, 0);\n process.stdout.write(truncateAnsiText(`${ANSI_INVERSE} ${footer} ${ANSI_INVERSE_OFF}`, terminalWidth));\n this.rendered = true;\n }\n\n private clearFooter(): void {\n if (!this.rendered || !this.isInteractive()) {\n return;\n }\n readline.clearLine(process.stdout, 0);\n readline.cursorTo(process.stdout, 0);\n this.rendered = false;\n }\n\n private renderProgressBar(terminalWidth: number): string {\n const width = terminalWidth >= 120 ? 30 : terminalWidth >= 90 ? 22 : 14;\n const ratio = this.total > 0 ? Math.min(1, this.completed / this.total) : 0;\n const filled = Math.round(width * ratio);\n const empty = Math.max(0, width - filled);\n return `[${ANSI_GREEN}${\"=\".repeat(filled)}${ANSI_COLOR_OFF}${\" \".repeat(empty)}]`;\n }\n\n private isInteractive(): boolean {\n return Boolean(process.stdout.isTTY || process.env.SOLIDCTL_TEST_PROGRESS === \"1\");\n }\n}\n\nfunction formatElapsed(durationMs: number): string {\n const totalSeconds = Math.max(0, Math.floor(durationMs / 1000));\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n if (minutes < 60) {\n return `${minutes}:${seconds.toString().padStart(2, \"0\")}`;\n }\n const hours = Math.floor(minutes / 60);\n const remainingMinutes = minutes % 60;\n return `${hours}:${remainingMinutes.toString().padStart(2, \"0\")}:${seconds.toString().padStart(2, \"0\")}`;\n}\n\nfunction truncateAnsiText(text: string, maxWidth: number): string {\n if (maxWidth <= 0) {\n return \"\";\n }\n\n let visibleWidth = 0;\n let index = 0;\n let output = \"\";\n let hasEscape = false;\n\n while (index < text.length) {\n if (text[index] === \"\\u001b\") {\n const match = /\\u001b\\[[0-9;]*m/.exec(text.slice(index));\n if (!match) {\n break;\n }\n output += match[0];\n hasEscape = true;\n index += match[0].length;\n continue;\n }\n\n if (visibleWidth >= maxWidth) {\n break;\n }\n\n output += text[index];\n visibleWidth += 1;\n index += 1;\n }\n\n if (index < text.length && maxWidth >= 1) {\n output = trimAnsiText(output, maxWidth - 1) + \"…\";\n }\n\n if (hasEscape && !output.endsWith(ANSI_INVERSE_OFF)) {\n output += ANSI_INVERSE_OFF;\n }\n\n return output;\n}\n\nfunction trimAnsiText(text: string, maxWidth: number): string {\n let visibleWidth = 0;\n let index = 0;\n let output = \"\";\n\n while (index < text.length && visibleWidth < maxWidth) {\n if (text[index] === \"\\u001b\") {\n const match = /\\u001b\\[[0-9;]*m/.exec(text.slice(index));\n if (!match) {\n break;\n }\n output += match[0];\n index += match[0].length;\n continue;\n }\n\n output += text[index];\n visibleWidth += 1;\n index += 1;\n }\n\n return output;\n}\n"]}
@@ -2,6 +2,9 @@ import type { StepPhase } from "../contracts/runtime-context.types";
2
2
  import type { OpStep, ScenarioSpec } from "../contracts/testing-metadata.types";
3
3
  import type { SolidTestSpecResult } from "../contracts/test-spec.types";
4
4
  export interface Reporter {
5
+ onRunStart?(args: {
6
+ total: number;
7
+ }): void;
5
8
  onScenarioStart(scenario: ScenarioSpec): void;
6
9
  onScenarioEnd(scenario: ScenarioSpec, result: {
7
10
  ok: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.types.d.ts","sourceRoot":"","sources":["../../../src/testing/reporter/reporter.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAChF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE,MAAM,WAAW,QAAQ;IACvB,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9C,aAAa,CACX,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAC3D,IAAI,CAAC;IACR,WAAW,CAAC,IAAI,EAAE;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,SAAS,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,GAAG,IAAI,CAAC;IACT,SAAS,CAAC,IAAI,EAAE;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,SAAS,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,EAAE,EAAE,OAAO,CAAC;QACZ,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,IAAI,CAAC;IACT,YAAY,CAAC,CAAC,IAAI,EAAE;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,mBAAmB,CAAC;KAC7B,GAAG,IAAI,CAAC;IACT,MAAM,CAAC,CAAC,IAAI,EAAE;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;KACvB,GAAG,IAAI,CAAC;IACT,QAAQ,CAAC,CAAC,IAAI,EAAE;QACd,EAAE,EAAE,OAAO,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,IAAI,CAAC;CACV"}
1
+ {"version":3,"file":"reporter.types.d.ts","sourceRoot":"","sources":["../../../src/testing/reporter/reporter.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAC;AACpE,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAChF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE,MAAM,WAAW,QAAQ;IACvB,UAAU,CAAC,CAAC,IAAI,EAAE;QAChB,KAAK,EAAE,MAAM,CAAC;KACf,GAAG,IAAI,CAAC;IACT,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9C,aAAa,CACX,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAC3D,IAAI,CAAC;IACR,WAAW,CAAC,IAAI,EAAE;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,SAAS,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,GAAG,IAAI,CAAC;IACT,SAAS,CAAC,IAAI,EAAE;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,SAAS,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,EAAE,EAAE,OAAO,CAAC;QACZ,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,IAAI,CAAC;IACT,YAAY,CAAC,CAAC,IAAI,EAAE;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,mBAAmB,CAAC;KAC7B,GAAG,IAAI,CAAC;IACT,MAAM,CAAC,CAAC,IAAI,EAAE;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;KACvB,GAAG,IAAI,CAAC;IACT,QAAQ,CAAC,CAAC,IAAI,EAAE;QACd,EAAE,EAAE,OAAO,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,IAAI,CAAC;CACV"}
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.types.js","sourceRoot":"","sources":["../../../src/testing/reporter/reporter.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { StepPhase } from \"../contracts/runtime-context.types\";\nimport type { OpStep, ScenarioSpec } from \"../contracts/testing-metadata.types\";\nimport type { SolidTestSpecResult } from \"../contracts/test-spec.types\";\n\nexport interface Reporter {\n onScenarioStart(scenario: ScenarioSpec): void;\n onScenarioEnd(\n scenario: ScenarioSpec,\n result: { ok: boolean; error?: unknown; durationMs: number },\n ): void;\n onStepStart(args: {\n scenarioId: string;\n phase: StepPhase;\n step: OpStep;\n }): void;\n onStepEnd(args: {\n scenarioId: string;\n phase: StepPhase;\n step: OpStep;\n ok: boolean;\n error?: unknown;\n durationMs: number;\n }): void;\n onSpecResult?(args: {\n scenarioId: string;\n specId: string;\n stepName?: string;\n result: SolidTestSpecResult;\n }): void;\n attach?(args: {\n scenarioId: string;\n name: string;\n contentType: string;\n data: Buffer | string;\n }): void;\n onRunEnd?(args: {\n ok: boolean;\n total: number;\n passed: number;\n failed: number;\n durationMs: number;\n }): void;\n}\n"]}
1
+ {"version":3,"file":"reporter.types.js","sourceRoot":"","sources":["../../../src/testing/reporter/reporter.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { StepPhase } from \"../contracts/runtime-context.types\";\nimport type { OpStep, ScenarioSpec } from \"../contracts/testing-metadata.types\";\nimport type { SolidTestSpecResult } from \"../contracts/test-spec.types\";\n\nexport interface Reporter {\n onRunStart?(args: {\n total: number;\n }): void;\n onScenarioStart(scenario: ScenarioSpec): void;\n onScenarioEnd(\n scenario: ScenarioSpec,\n result: { ok: boolean; error?: unknown; durationMs: number },\n ): void;\n onStepStart(args: {\n scenarioId: string;\n phase: StepPhase;\n step: OpStep;\n }): void;\n onStepEnd(args: {\n scenarioId: string;\n phase: StepPhase;\n step: OpStep;\n ok: boolean;\n error?: unknown;\n durationMs: number;\n }): void;\n onSpecResult?(args: {\n scenarioId: string;\n specId: string;\n stepName?: string;\n result: SolidTestSpecResult;\n }): void;\n attach?(args: {\n scenarioId: string;\n name: string;\n contentType: string;\n data: Buffer | string;\n }): void;\n onRunEnd?(args: {\n ok: boolean;\n total: number;\n passed: number;\n failed: number;\n durationMs: number;\n }): void;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"run-from-metadata.d.ts","sourceRoot":"","sources":["../../../src/testing/runner/run-from-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAqB,MAAM,qCAAqC,CAAC;AAC9F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AASxE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAoBrD,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,eAAe,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,GAAG,CAAC,EAAE,iBAAiB,CAAC;IACxB,EAAE,CAAC,EAAE,wBAAwB,CAAC;IAC9B,QAAQ,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACrC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;CAC1C,CAAC;AAEF,wBAAsB,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA2DxE"}
1
+ {"version":3,"file":"run-from-metadata.d.ts","sourceRoot":"","sources":["../../../src/testing/runner/run-from-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAqB,MAAM,qCAAqC,CAAC;AAC9F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AASxE,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAoBrD,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,EAAE,eAAe,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,GAAG,CAAC,EAAE,iBAAiB,CAAC;IACxB,EAAE,CAAC,EAAE,wBAAwB,CAAC;IAC9B,QAAQ,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACrC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;CAC1C,CAAC;AAEF,wBAAsB,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA4DxE"}
@@ -82,6 +82,7 @@ async function runFromMetadata(opts) {
82
82
  }
83
83
  const resources = new resource_store_1.SimpleResourceStore();
84
84
  const reporter = opts.reporter ?? new console_reporter_1.ConsoleReporter();
85
+ reporter.onRunStart?.({ total: scenarios.length });
85
86
  const api = new api_adapter_1.ApiAdapter(opts.api);
86
87
  const { PlaywrightAdapter } = await Promise.resolve().then(() => __importStar(require("../adapters/ui/playwright-adapter")));
87
88
  const ui = new PlaywrightAdapter(opts.ui);
@@ -1 +1 @@
1
- {"version":3,"file":"run-from-metadata.js","sourceRoot":"","sources":["../../../src/testing/runner/run-from-metadata.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Reporter } from \"../reporter/reporter.types\";\nimport type { TestingMetadata, TestingDataRecord } from \"../contracts/testing-metadata.types\";\nimport type { ApiAdapterOptions } from \"../adapters/api/api.types\";\nimport type { PlaywrightAdapterOptions } from \"../adapters/ui/ui.types\";\nimport { ApiAdapter } from \"../adapters/api/api-adapter\";\nimport { registerApiSteps } from \"../steps/api\";\nimport { registerUiSteps } from \"../steps/ui\";\nimport { registerAssertSteps } from \"../steps/assert\";\nimport { registerUtilSteps } from \"../steps/util\";\nimport { registerTestSteps } from \"../steps/test\";\nimport { SimpleResourceStore } from \"../core/resource-store\";\nimport { StepRegistry } from \"../core/step-registry\";\nimport { SpecRegistry } from \"../core/spec-registry\";\nimport { TestingEngine } from \"../core/testing-engine\";\nimport { filterScenarios } from \"./scenario-filter\";\nimport { ensureUiStarted, scenarioNeedsUi } from \"./lifecycle\";\nimport { ConsoleReporter } from \"../reporter/console-reporter\";\n\n\nfunction buildTestDataIndex(data?: TestingDataRecord[]): Record<string, Record<string, any>> {\n const index: Record<string, Record<string, any>> = {};\n if (!Array.isArray(data)) return index;\n for (const record of data) {\n if (!record?.modelUserKey || !record?.recUserKeyValue) continue;\n if (!index[record.modelUserKey]) {\n index[record.modelUserKey] = {};\n }\n index[record.modelUserKey][record.recUserKeyValue] = record.data ?? {};\n }\n return index;\n}\n\nexport type RunnerOptions = {\n metadata: TestingMetadata;\n scenarioIds?: string[];\n includeTags?: string[];\n skipScenarioIds?: string[];\n reporter?: Reporter;\n api?: ApiAdapterOptions;\n ui?: PlaywrightAdapterOptions;\n defaults?: { timeoutMs?: number; retries?: number };\n options?: { printApiLogs?: boolean };\n specs?: (registry: SpecRegistry) => void;\n};\n\nexport async function runFromMetadata(opts: RunnerOptions): Promise<void> {\n const startedAt = Date.now();\n const registry = new StepRegistry();\n registerApiSteps(registry);\n registerUiSteps(registry);\n registerAssertSteps(registry);\n registerUtilSteps(registry);\n registerTestSteps(registry);\n\n const engine = new TestingEngine(registry, opts.defaults);\n const scenarios = filterScenarios(opts.metadata.testing.scenarios, {\n scenarioIds: opts.scenarioIds,\n includeTags: opts.includeTags,\n skipScenarioIds: opts.skipScenarioIds,\n });\n\n const specRegistry = new SpecRegistry();\n const testData = buildTestDataIndex(opts.metadata.testing?.data);\n if (opts.specs) {\n opts.specs(specRegistry);\n }\n\n const resources = new SimpleResourceStore();\n const reporter = opts.reporter ?? new ConsoleReporter();\n const api = new ApiAdapter(opts.api);\n const { PlaywrightAdapter } = await import(\"../adapters/ui/playwright-adapter\");\n const ui = new PlaywrightAdapter(opts.ui);\n const ctxBase = { resources, reporter, api, ui, specRegistry, testData, options: opts.options };\n const uiStarted = { value: false };\n let passed = 0;\n let failed = 0;\n let runError: unknown;\n\n try {\n for (const scenario of scenarios) {\n if (scenarioNeedsUi(scenario)) {\n await ensureUiStarted(ctxBase, uiStarted);\n }\n try {\n await engine.runScenario(scenario, ctxBase);\n passed += 1;\n } catch (error) {\n failed += 1;\n runError = error;\n throw error;\n }\n }\n } finally {\n reporter.onRunEnd?.({\n ok: !runError,\n total: scenarios.length,\n passed,\n failed,\n durationMs: Date.now() - startedAt,\n });\n if (uiStarted.value) {\n await ui.stop();\n }\n }\n}\n"]}
1
+ {"version":3,"file":"run-from-metadata.js","sourceRoot":"","sources":["../../../src/testing/runner/run-from-metadata.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Reporter } from \"../reporter/reporter.types\";\nimport type { TestingMetadata, TestingDataRecord } from \"../contracts/testing-metadata.types\";\nimport type { ApiAdapterOptions } from \"../adapters/api/api.types\";\nimport type { PlaywrightAdapterOptions } from \"../adapters/ui/ui.types\";\nimport { ApiAdapter } from \"../adapters/api/api-adapter\";\nimport { registerApiSteps } from \"../steps/api\";\nimport { registerUiSteps } from \"../steps/ui\";\nimport { registerAssertSteps } from \"../steps/assert\";\nimport { registerUtilSteps } from \"../steps/util\";\nimport { registerTestSteps } from \"../steps/test\";\nimport { SimpleResourceStore } from \"../core/resource-store\";\nimport { StepRegistry } from \"../core/step-registry\";\nimport { SpecRegistry } from \"../core/spec-registry\";\nimport { TestingEngine } from \"../core/testing-engine\";\nimport { filterScenarios } from \"./scenario-filter\";\nimport { ensureUiStarted, scenarioNeedsUi } from \"./lifecycle\";\nimport { ConsoleReporter } from \"../reporter/console-reporter\";\n\n\nfunction buildTestDataIndex(data?: TestingDataRecord[]): Record<string, Record<string, any>> {\n const index: Record<string, Record<string, any>> = {};\n if (!Array.isArray(data)) return index;\n for (const record of data) {\n if (!record?.modelUserKey || !record?.recUserKeyValue) continue;\n if (!index[record.modelUserKey]) {\n index[record.modelUserKey] = {};\n }\n index[record.modelUserKey][record.recUserKeyValue] = record.data ?? {};\n }\n return index;\n}\n\nexport type RunnerOptions = {\n metadata: TestingMetadata;\n scenarioIds?: string[];\n includeTags?: string[];\n skipScenarioIds?: string[];\n reporter?: Reporter;\n api?: ApiAdapterOptions;\n ui?: PlaywrightAdapterOptions;\n defaults?: { timeoutMs?: number; retries?: number };\n options?: { printApiLogs?: boolean };\n specs?: (registry: SpecRegistry) => void;\n};\n\nexport async function runFromMetadata(opts: RunnerOptions): Promise<void> {\n const startedAt = Date.now();\n const registry = new StepRegistry();\n registerApiSteps(registry);\n registerUiSteps(registry);\n registerAssertSteps(registry);\n registerUtilSteps(registry);\n registerTestSteps(registry);\n\n const engine = new TestingEngine(registry, opts.defaults);\n const scenarios = filterScenarios(opts.metadata.testing.scenarios, {\n scenarioIds: opts.scenarioIds,\n includeTags: opts.includeTags,\n skipScenarioIds: opts.skipScenarioIds,\n });\n\n const specRegistry = new SpecRegistry();\n const testData = buildTestDataIndex(opts.metadata.testing?.data);\n if (opts.specs) {\n opts.specs(specRegistry);\n }\n\n const resources = new SimpleResourceStore();\n const reporter = opts.reporter ?? new ConsoleReporter();\n reporter.onRunStart?.({ total: scenarios.length });\n const api = new ApiAdapter(opts.api);\n const { PlaywrightAdapter } = await import(\"../adapters/ui/playwright-adapter\");\n const ui = new PlaywrightAdapter(opts.ui);\n const ctxBase = { resources, reporter, api, ui, specRegistry, testData, options: opts.options };\n const uiStarted = { value: false };\n let passed = 0;\n let failed = 0;\n let runError: unknown;\n\n try {\n for (const scenario of scenarios) {\n if (scenarioNeedsUi(scenario)) {\n await ensureUiStarted(ctxBase, uiStarted);\n }\n try {\n await engine.runScenario(scenario, ctxBase);\n passed += 1;\n } catch (error) {\n failed += 1;\n runError = error;\n throw error;\n }\n }\n } finally {\n reporter.onRunEnd?.({\n ok: !runError,\n total: scenarios.length,\n passed,\n failed,\n durationMs: Date.now() - startedAt,\n });\n if (uiStarted.value) {\n await ui.stop();\n }\n }\n}\n"]}
@@ -0,0 +1,14 @@
1
+ export type ThemeMode = "light" | "dark";
2
+ export type AppThemeDefinition = {
3
+ key: string;
4
+ label: string;
5
+ mode: ThemeMode;
6
+ default?: boolean;
7
+ };
8
+ export declare function getThemeModeFromThemeKey(value?: string | null): ThemeMode | null;
9
+ export declare function getCoreThemes(): AppThemeDefinition[];
10
+ export declare function getRegisteredThemes(): AppThemeDefinition[];
11
+ export declare function getThemesByMode(mode: ThemeMode): AppThemeDefinition[];
12
+ export declare function getDefaultThemeKey(mode?: ThemeMode): string;
13
+ export declare function isRegisteredThemeKey(value?: string | null, mode?: ThemeMode): value is string;
14
+ //# sourceMappingURL=theme-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-registry.d.ts","sourceRoot":"","sources":["../../src/theme/theme-registry.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAEzC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAyCF,wBAAgB,wBAAwB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAQhF;AAuFD,wBAAgB,aAAa,IAAI,kBAAkB,EAAE,CAEpD;AAED,wBAAgB,mBAAmB,IAAI,kBAAkB,EAAE,CAE1D;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,kBAAkB,EAAE,CAErE;AAED,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,SAAmB,GAAG,MAAM,CAEpE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,KAAK,IAAI,MAAM,CAO7F"}
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getThemeModeFromThemeKey = getThemeModeFromThemeKey;
7
+ exports.getCoreThemes = getCoreThemes;
8
+ exports.getRegisteredThemes = getRegisteredThemes;
9
+ exports.getThemesByMode = getThemesByMode;
10
+ exports.getDefaultThemeKey = getDefaultThemeKey;
11
+ exports.isRegisteredThemeKey = isRegisteredThemeKey;
12
+ const fs_1 = __importDefault(require("fs"));
13
+ const path_1 = __importDefault(require("path"));
14
+ const DEFAULT_THEME_KEYS = {
15
+ light: "solid-light-purple",
16
+ dark: "solid-dark-purple",
17
+ };
18
+ const THEME_MODE_TOKENS = {
19
+ light: "-light-",
20
+ dark: "-dark-",
21
+ };
22
+ const THEME_MODE_SUFFIXES = {
23
+ light: "-light",
24
+ dark: "-dark",
25
+ };
26
+ function normalizeThemeKey(value) {
27
+ const normalized = value?.trim().toLowerCase();
28
+ return normalized || null;
29
+ }
30
+ function matchesThemeMode(value, mode) {
31
+ return (value.includes(THEME_MODE_TOKENS[mode])
32
+ || value.endsWith(THEME_MODE_SUFFIXES[mode])
33
+ || value === mode);
34
+ }
35
+ function titleCase(value) {
36
+ return value
37
+ .split(/[-_\s]+/)
38
+ .filter(Boolean)
39
+ .map((token) => {
40
+ if (token.toLowerCase() === "solid")
41
+ return "SolidX";
42
+ return token.charAt(0).toUpperCase() + token.slice(1);
43
+ })
44
+ .join(" ");
45
+ }
46
+ function getThemeModeFromThemeKey(value) {
47
+ const normalized = normalizeThemeKey(value);
48
+ if (!normalized)
49
+ return null;
50
+ if (matchesThemeMode(normalized, "light"))
51
+ return "light";
52
+ if (matchesThemeMode(normalized, "dark"))
53
+ return "dark";
54
+ return null;
55
+ }
56
+ function createThemeDefinition(key, defaultTheme = false) {
57
+ const mode = getThemeModeFromThemeKey(key);
58
+ if (!mode) {
59
+ throw new Error(`Invalid theme key: ${key}`);
60
+ }
61
+ return {
62
+ key,
63
+ label: titleCase(key),
64
+ mode,
65
+ default: defaultTheme,
66
+ };
67
+ }
68
+ function createDefaultTheme(mode) {
69
+ return createThemeDefinition(DEFAULT_THEME_KEYS[mode], true);
70
+ }
71
+ function groupThemesByMode(themes, mode) {
72
+ return themes.filter((theme) => theme.mode === mode);
73
+ }
74
+ function pickDefaultThemeKey(themes, mode) {
75
+ const themesForMode = groupThemesByMode(themes, mode);
76
+ return (themesForMode.find((theme) => theme.default)?.key
77
+ ?? themesForMode[0]?.key
78
+ ?? DEFAULT_THEME_KEYS[mode]);
79
+ }
80
+ function resolveThemeDirectory() {
81
+ const themeDirectory = path_1.default.resolve(process.cwd(), "..", "solid-ui", "public", "themes");
82
+ try {
83
+ if (fs_1.default.existsSync(themeDirectory) && fs_1.default.statSync(themeDirectory).isDirectory()) {
84
+ return path_1.default.resolve(themeDirectory);
85
+ }
86
+ }
87
+ catch {
88
+ return null;
89
+ }
90
+ return null;
91
+ }
92
+ function isThemeDirectory(themeDirectory, entryName) {
93
+ return fs_1.default.existsSync(path_1.default.join(themeDirectory, entryName, "theme.css"));
94
+ }
95
+ function readThemesFromPath() {
96
+ const themeDirectory = resolveThemeDirectory();
97
+ if (!themeDirectory) {
98
+ return [];
99
+ }
100
+ try {
101
+ const directoryEntries = fs_1.default.readdirSync(themeDirectory, { withFileTypes: true });
102
+ return directoryEntries
103
+ .filter((entry) => entry.isDirectory())
104
+ .map((entry) => entry.name.trim())
105
+ .filter(Boolean)
106
+ .filter((entryName) => isThemeDirectory(themeDirectory, entryName))
107
+ .flatMap((entryName) => {
108
+ const mode = getThemeModeFromThemeKey(entryName);
109
+ if (!mode)
110
+ return [];
111
+ return [createThemeDefinition(entryName, entryName === DEFAULT_THEME_KEYS[mode])];
112
+ })
113
+ .sort((left, right) => left.label.localeCompare(right.label));
114
+ }
115
+ catch {
116
+ return [];
117
+ }
118
+ }
119
+ function getThemes() {
120
+ const discoveredThemes = readThemesFromPath();
121
+ if (discoveredThemes.length) {
122
+ return discoveredThemes;
123
+ }
124
+ return [createDefaultTheme("light"), createDefaultTheme("dark")];
125
+ }
126
+ function getCoreThemes() {
127
+ return getThemes();
128
+ }
129
+ function getRegisteredThemes() {
130
+ return getThemes();
131
+ }
132
+ function getThemesByMode(mode) {
133
+ return groupThemesByMode(getRegisteredThemes(), mode);
134
+ }
135
+ function getDefaultThemeKey(mode = "light") {
136
+ return pickDefaultThemeKey(getRegisteredThemes(), mode);
137
+ }
138
+ function isRegisteredThemeKey(value, mode) {
139
+ if (!value)
140
+ return false;
141
+ return getRegisteredThemes().some((theme) => {
142
+ if (theme.key !== value)
143
+ return false;
144
+ return mode ? theme.mode === mode : true;
145
+ });
146
+ }
147
+ //# sourceMappingURL=theme-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-registry.js","sourceRoot":"","sources":["../../src/theme/theme-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"fs\";\nimport path from \"path\";\n\n/**\n * Backend theme registry.\n *\n * Responsibilities:\n * - discover theme folders from the filesystem\n * - classify each theme as light/dark from its key\n * - expose default and grouped theme helpers for backend settings\n *\n * Shared pure parsing helpers are intentionally mirrored in solid-core-ui,\n * but all filesystem discovery stays here.\n */\nexport type ThemeMode = \"light\" | \"dark\";\n\nexport type AppThemeDefinition = {\n key: string;\n label: string;\n mode: ThemeMode;\n default?: boolean;\n};\n\nconst DEFAULT_THEME_KEYS: Record<ThemeMode, string> = {\n light: \"solid-light-purple\",\n dark: \"solid-dark-purple\",\n};\n\nconst THEME_MODE_TOKENS: Record<ThemeMode, string> = {\n light: \"-light-\",\n dark: \"-dark-\",\n};\n\nconst THEME_MODE_SUFFIXES: Record<ThemeMode, string> = {\n light: \"-light\",\n dark: \"-dark\",\n};\n\nfunction normalizeThemeKey(value?: string | null): string | null {\n const normalized = value?.trim().toLowerCase();\n return normalized || null;\n}\n\nfunction matchesThemeMode(value: string, mode: ThemeMode): boolean {\n return (\n value.includes(THEME_MODE_TOKENS[mode])\n || value.endsWith(THEME_MODE_SUFFIXES[mode])\n || value === mode\n );\n}\n\nfunction titleCase(value: string): string {\n return value\n .split(/[-_\\s]+/)\n .filter(Boolean)\n .map((token) => {\n if (token.toLowerCase() === \"solid\") return \"SolidX\";\n return token.charAt(0).toUpperCase() + token.slice(1);\n })\n .join(\" \");\n}\n\nexport function getThemeModeFromThemeKey(value?: string | null): ThemeMode | null {\n const normalized = normalizeThemeKey(value);\n if (!normalized) return null;\n\n if (matchesThemeMode(normalized, \"light\")) return \"light\";\n if (matchesThemeMode(normalized, \"dark\")) return \"dark\";\n\n return null;\n}\n\nfunction createThemeDefinition(key: string, defaultTheme = false): AppThemeDefinition {\n const mode = getThemeModeFromThemeKey(key);\n if (!mode) {\n throw new Error(`Invalid theme key: ${key}`);\n }\n\n return {\n key,\n label: titleCase(key),\n mode,\n default: defaultTheme,\n };\n}\n\nfunction createDefaultTheme(mode: ThemeMode): AppThemeDefinition {\n return createThemeDefinition(DEFAULT_THEME_KEYS[mode], true);\n}\n\nfunction groupThemesByMode(themes: AppThemeDefinition[], mode: ThemeMode): AppThemeDefinition[] {\n return themes.filter((theme) => theme.mode === mode);\n}\n\nfunction pickDefaultThemeKey(themes: AppThemeDefinition[], mode: ThemeMode): string {\n const themesForMode = groupThemesByMode(themes, mode);\n\n return (\n themesForMode.find((theme) => theme.default)?.key\n ?? themesForMode[0]?.key\n ?? DEFAULT_THEME_KEYS[mode]\n );\n}\n\nfunction resolveThemeDirectory(): string | null {\n const themeDirectory = path.resolve(process.cwd(), \"..\", \"solid-ui\", \"public\", \"themes\");\n try {\n if (fs.existsSync(themeDirectory) && fs.statSync(themeDirectory).isDirectory()) {\n return path.resolve(themeDirectory);\n }\n } catch {\n return null;\n }\n\n return null;\n}\n\nfunction isThemeDirectory(themeDirectory: string, entryName: string): boolean {\n return fs.existsSync(path.join(themeDirectory, entryName, \"theme.css\"));\n}\n\nfunction readThemesFromPath(): AppThemeDefinition[] {\n const themeDirectory = resolveThemeDirectory();\n if (!themeDirectory) {\n return [];\n }\n\n try {\n const directoryEntries = fs.readdirSync(themeDirectory, { withFileTypes: true });\n\n return directoryEntries\n .filter((entry) => entry.isDirectory())\n .map((entry) => entry.name.trim())\n .filter(Boolean)\n .filter((entryName) => isThemeDirectory(themeDirectory, entryName))\n .flatMap((entryName) => {\n const mode = getThemeModeFromThemeKey(entryName);\n if (!mode) return [];\n\n return [createThemeDefinition(entryName, entryName === DEFAULT_THEME_KEYS[mode])];\n })\n .sort((left, right) => left.label.localeCompare(right.label));\n } catch {\n return [];\n }\n}\n\nfunction getThemes(): AppThemeDefinition[] {\n const discoveredThemes = readThemesFromPath();\n\n if (discoveredThemes.length) {\n return discoveredThemes;\n }\n\n return [createDefaultTheme(\"light\"), createDefaultTheme(\"dark\")];\n}\n\nexport function getCoreThemes(): AppThemeDefinition[] {\n return getThemes();\n}\n\nexport function getRegisteredThemes(): AppThemeDefinition[] {\n return getThemes();\n}\n\nexport function getThemesByMode(mode: ThemeMode): AppThemeDefinition[] {\n return groupThemesByMode(getRegisteredThemes(), mode);\n}\n\nexport function getDefaultThemeKey(mode: ThemeMode = \"light\"): string {\n return pickDefaultThemeKey(getRegisteredThemes(), mode);\n}\n\nexport function isRegisteredThemeKey(value?: string | null, mode?: ThemeMode): value is string {\n if (!value) return false;\n\n return getRegisteredThemes().some((theme) => {\n if (theme.key !== value) return false;\n return mode ? theme.mode === mode : true;\n });\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidxai/core",
3
- "version": "0.1.13-beta.11",
3
+ "version": "0.1.13-beta.13",
4
4
  "description": "This module is a NestJS module containing all the required core providers required by a Solid application",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",