@claryai/cli 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 (237) hide show
  1. package/LICENSE +25 -0
  2. package/README.md +197 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/ajv.d.ts +3 -0
  5. package/dist/ajv.d.ts.map +1 -0
  6. package/dist/ajv.js +13 -0
  7. package/dist/analytics/analytics.d.ts +370 -0
  8. package/dist/analytics/analytics.d.ts.map +1 -0
  9. package/dist/analytics/analytics.js +143 -0
  10. package/dist/config.d.ts +34 -0
  11. package/dist/config.d.ts.map +1 -0
  12. package/dist/config.js +134 -0
  13. package/dist/dbt/context.d.ts +14 -0
  14. package/dist/dbt/context.d.ts.map +1 -0
  15. package/dist/dbt/context.js +76 -0
  16. package/dist/dbt/context.test.d.ts +2 -0
  17. package/dist/dbt/context.test.d.ts.map +1 -0
  18. package/dist/dbt/context.test.js +152 -0
  19. package/dist/dbt/manifest.d.ts +7 -0
  20. package/dist/dbt/manifest.d.ts.map +1 -0
  21. package/dist/dbt/manifest.js +23 -0
  22. package/dist/dbt/models.d.ts +43 -0
  23. package/dist/dbt/models.d.ts.map +1 -0
  24. package/dist/dbt/models.js +256 -0
  25. package/dist/dbt/models.test.d.ts +2 -0
  26. package/dist/dbt/models.test.d.ts.map +1 -0
  27. package/dist/dbt/models.test.js +19 -0
  28. package/dist/dbt/profile.d.ts +9 -0
  29. package/dist/dbt/profile.d.ts.map +1 -0
  30. package/dist/dbt/profile.js +86 -0
  31. package/dist/dbt/profiles.test.d.ts +2 -0
  32. package/dist/dbt/profiles.test.d.ts.map +1 -0
  33. package/dist/dbt/profiles.test.js +50 -0
  34. package/dist/dbt/schema.d.ts +31 -0
  35. package/dist/dbt/schema.d.ts.map +1 -0
  36. package/dist/dbt/schema.js +49 -0
  37. package/dist/dbt/targets/Bigquery/index.d.ts +18 -0
  38. package/dist/dbt/targets/Bigquery/index.d.ts.map +1 -0
  39. package/dist/dbt/targets/Bigquery/index.js +105 -0
  40. package/dist/dbt/targets/Bigquery/oauth.d.ts +2 -0
  41. package/dist/dbt/targets/Bigquery/oauth.d.ts.map +1 -0
  42. package/dist/dbt/targets/Bigquery/oauth.js +43 -0
  43. package/dist/dbt/targets/Bigquery/serviceAccount.d.ts +35 -0
  44. package/dist/dbt/targets/Bigquery/serviceAccount.d.ts.map +1 -0
  45. package/dist/dbt/targets/Bigquery/serviceAccount.js +149 -0
  46. package/dist/dbt/targets/Databricks/oauth.d.ts +21 -0
  47. package/dist/dbt/targets/Databricks/oauth.d.ts.map +1 -0
  48. package/dist/dbt/targets/Databricks/oauth.js +184 -0
  49. package/dist/dbt/targets/athena.d.ts +21 -0
  50. package/dist/dbt/targets/athena.d.ts.map +1 -0
  51. package/dist/dbt/targets/athena.js +91 -0
  52. package/dist/dbt/targets/athena.test.d.ts +2 -0
  53. package/dist/dbt/targets/athena.test.d.ts.map +1 -0
  54. package/dist/dbt/targets/athena.test.js +60 -0
  55. package/dist/dbt/targets/clickhouse.d.ts +24 -0
  56. package/dist/dbt/targets/clickhouse.d.ts.map +1 -0
  57. package/dist/dbt/targets/clickhouse.js +90 -0
  58. package/dist/dbt/targets/databricks.d.ts +27 -0
  59. package/dist/dbt/targets/databricks.d.ts.map +1 -0
  60. package/dist/dbt/targets/databricks.js +138 -0
  61. package/dist/dbt/targets/duckdb.d.ts +16 -0
  62. package/dist/dbt/targets/duckdb.d.ts.map +1 -0
  63. package/dist/dbt/targets/duckdb.js +63 -0
  64. package/dist/dbt/targets/duckdb.test.d.ts +2 -0
  65. package/dist/dbt/targets/duckdb.test.d.ts.map +1 -0
  66. package/dist/dbt/targets/duckdb.test.js +37 -0
  67. package/dist/dbt/targets/postgres.d.ts +26 -0
  68. package/dist/dbt/targets/postgres.d.ts.map +1 -0
  69. package/dist/dbt/targets/postgres.js +142 -0
  70. package/dist/dbt/targets/redshift.d.ts +23 -0
  71. package/dist/dbt/targets/redshift.d.ts.map +1 -0
  72. package/dist/dbt/targets/redshift.js +96 -0
  73. package/dist/dbt/targets/snowflake.d.ts +4 -0
  74. package/dist/dbt/targets/snowflake.d.ts.map +1 -0
  75. package/dist/dbt/targets/snowflake.js +134 -0
  76. package/dist/dbt/targets/trino.d.ts +16 -0
  77. package/dist/dbt/targets/trino.d.ts.map +1 -0
  78. package/dist/dbt/targets/trino.js +65 -0
  79. package/dist/dbt/templating.d.ts +15 -0
  80. package/dist/dbt/templating.d.ts.map +1 -0
  81. package/dist/dbt/templating.js +50 -0
  82. package/dist/dbt/templating.test.d.ts +2 -0
  83. package/dist/dbt/templating.test.d.ts.map +1 -0
  84. package/dist/dbt/templating.test.js +51 -0
  85. package/dist/dbt/types.d.ts +17 -0
  86. package/dist/dbt/types.d.ts.map +1 -0
  87. package/dist/dbt/types.js +2 -0
  88. package/dist/dbt/validation.d.ts +9 -0
  89. package/dist/dbt/validation.d.ts.map +1 -0
  90. package/dist/dbt/validation.js +54 -0
  91. package/dist/env.d.ts +12 -0
  92. package/dist/env.d.ts.map +1 -0
  93. package/dist/env.js +40 -0
  94. package/dist/error.d.ts +2 -0
  95. package/dist/error.d.ts.map +1 -0
  96. package/dist/error.js +12 -0
  97. package/dist/globalState.d.ts +29 -0
  98. package/dist/globalState.d.ts.map +1 -0
  99. package/dist/globalState.js +67 -0
  100. package/dist/handlers/asyncQuery.d.ts +7 -0
  101. package/dist/handlers/asyncQuery.d.ts.map +1 -0
  102. package/dist/handlers/asyncQuery.js +50 -0
  103. package/dist/handlers/compile.d.ts +16 -0
  104. package/dist/handlers/compile.d.ts.map +1 -0
  105. package/dist/handlers/compile.js +277 -0
  106. package/dist/handlers/compile.test.d.ts +2 -0
  107. package/dist/handlers/compile.test.d.ts.map +1 -0
  108. package/dist/handlers/compile.test.js +201 -0
  109. package/dist/handlers/createProject.d.ts +37 -0
  110. package/dist/handlers/createProject.d.ts.map +1 -0
  111. package/dist/handlers/createProject.js +272 -0
  112. package/dist/handlers/dbt/apiClient.d.ts +14 -0
  113. package/dist/handlers/dbt/apiClient.d.ts.map +1 -0
  114. package/dist/handlers/dbt/apiClient.js +167 -0
  115. package/dist/handlers/dbt/compile.d.ts +35 -0
  116. package/dist/handlers/dbt/compile.d.ts.map +1 -0
  117. package/dist/handlers/dbt/compile.js +220 -0
  118. package/dist/handlers/dbt/getDbtProfileTargetName.d.ts +9 -0
  119. package/dist/handlers/dbt/getDbtProfileTargetName.d.ts.map +1 -0
  120. package/dist/handlers/dbt/getDbtProfileTargetName.js +44 -0
  121. package/dist/handlers/dbt/getDbtVersion.d.ts +16 -0
  122. package/dist/handlers/dbt/getDbtVersion.d.ts.map +1 -0
  123. package/dist/handlers/dbt/getDbtVersion.js +141 -0
  124. package/dist/handlers/dbt/getDbtVersion.mocks.d.ts +11 -0
  125. package/dist/handlers/dbt/getDbtVersion.mocks.d.ts.map +1 -0
  126. package/dist/handlers/dbt/getDbtVersion.mocks.js +70 -0
  127. package/dist/handlers/dbt/getDbtVersion.test.d.ts +2 -0
  128. package/dist/handlers/dbt/getDbtVersion.test.d.ts.map +1 -0
  129. package/dist/handlers/dbt/getDbtVersion.test.js +97 -0
  130. package/dist/handlers/dbt/getWarehouseClient.d.ts +24 -0
  131. package/dist/handlers/dbt/getWarehouseClient.d.ts.map +1 -0
  132. package/dist/handlers/dbt/getWarehouseClient.js +312 -0
  133. package/dist/handlers/dbt/refresh.d.ts +11 -0
  134. package/dist/handlers/dbt/refresh.d.ts.map +1 -0
  135. package/dist/handlers/dbt/refresh.js +114 -0
  136. package/dist/handlers/dbt/run.d.ts +14 -0
  137. package/dist/handlers/dbt/run.d.ts.map +1 -0
  138. package/dist/handlers/dbt/run.js +67 -0
  139. package/dist/handlers/deploy.d.ts +26 -0
  140. package/dist/handlers/deploy.d.ts.map +1 -0
  141. package/dist/handlers/deploy.js +377 -0
  142. package/dist/handlers/diagnostics.d.ts +11 -0
  143. package/dist/handlers/diagnostics.d.ts.map +1 -0
  144. package/dist/handlers/diagnostics.js +194 -0
  145. package/dist/handlers/download.d.ts +29 -0
  146. package/dist/handlers/download.d.ts.map +1 -0
  147. package/dist/handlers/download.js +955 -0
  148. package/dist/handlers/exportChartImage.d.ts +7 -0
  149. package/dist/handlers/exportChartImage.d.ts.map +1 -0
  150. package/dist/handlers/exportChartImage.js +33 -0
  151. package/dist/handlers/generate.d.ts +13 -0
  152. package/dist/handlers/generate.d.ts.map +1 -0
  153. package/dist/handlers/generate.js +159 -0
  154. package/dist/handlers/generateExposures.d.ts +8 -0
  155. package/dist/handlers/generateExposures.d.ts.map +1 -0
  156. package/dist/handlers/generateExposures.js +100 -0
  157. package/dist/handlers/getProject.d.ts +6 -0
  158. package/dist/handlers/getProject.d.ts.map +1 -0
  159. package/dist/handlers/getProject.js +43 -0
  160. package/dist/handlers/installSkills.d.ts +12 -0
  161. package/dist/handlers/installSkills.d.ts.map +1 -0
  162. package/dist/handlers/installSkills.js +321 -0
  163. package/dist/handlers/lint/ajvToSarif.d.ts +66 -0
  164. package/dist/handlers/lint/ajvToSarif.d.ts.map +1 -0
  165. package/dist/handlers/lint/ajvToSarif.js +222 -0
  166. package/dist/handlers/lint/sarifFormatter.d.ts +14 -0
  167. package/dist/handlers/lint/sarifFormatter.d.ts.map +1 -0
  168. package/dist/handlers/lint/sarifFormatter.js +111 -0
  169. package/dist/handlers/lint.d.ts +8 -0
  170. package/dist/handlers/lint.d.ts.map +1 -0
  171. package/dist/handlers/lint.js +308 -0
  172. package/dist/handlers/listProjects.d.ts +6 -0
  173. package/dist/handlers/listProjects.d.ts.map +1 -0
  174. package/dist/handlers/listProjects.js +53 -0
  175. package/dist/handlers/login/oauth.d.ts +2 -0
  176. package/dist/handlers/login/oauth.d.ts.map +1 -0
  177. package/dist/handlers/login/oauth.js +27 -0
  178. package/dist/handlers/login/pat.d.ts +2 -0
  179. package/dist/handlers/login/pat.d.ts.map +1 -0
  180. package/dist/handlers/login/pat.js +31 -0
  181. package/dist/handlers/login.d.ts +15 -0
  182. package/dist/handlers/login.d.ts.map +1 -0
  183. package/dist/handlers/login.js +239 -0
  184. package/dist/handlers/metadataFile.d.ts +9 -0
  185. package/dist/handlers/metadataFile.d.ts.map +1 -0
  186. package/dist/handlers/metadataFile.js +34 -0
  187. package/dist/handlers/oauthLogin.d.ts +6 -0
  188. package/dist/handlers/oauthLogin.d.ts.map +1 -0
  189. package/dist/handlers/oauthLogin.js +191 -0
  190. package/dist/handlers/preview.d.ts +29 -0
  191. package/dist/handlers/preview.d.ts.map +1 -0
  192. package/dist/handlers/preview.js +415 -0
  193. package/dist/handlers/renameHandler.d.ts +16 -0
  194. package/dist/handlers/renameHandler.d.ts.map +1 -0
  195. package/dist/handlers/renameHandler.js +160 -0
  196. package/dist/handlers/runChart.d.ts +10 -0
  197. package/dist/handlers/runChart.d.ts.map +1 -0
  198. package/dist/handlers/runChart.js +105 -0
  199. package/dist/handlers/selectProject.d.ts +20 -0
  200. package/dist/handlers/selectProject.d.ts.map +1 -0
  201. package/dist/handlers/selectProject.js +91 -0
  202. package/dist/handlers/setProject.d.ts +14 -0
  203. package/dist/handlers/setProject.d.ts.map +1 -0
  204. package/dist/handlers/setProject.js +131 -0
  205. package/dist/handlers/setWarehouse.d.ts +14 -0
  206. package/dist/handlers/setWarehouse.d.ts.map +1 -0
  207. package/dist/handlers/setWarehouse.js +94 -0
  208. package/dist/handlers/sql.d.ts +9 -0
  209. package/dist/handlers/sql.d.ts.map +1 -0
  210. package/dist/handlers/sql.js +89 -0
  211. package/dist/handlers/utils.d.ts +11 -0
  212. package/dist/handlers/utils.d.ts.map +1 -0
  213. package/dist/handlers/utils.js +36 -0
  214. package/dist/handlers/validate.d.ts +22 -0
  215. package/dist/handlers/validate.d.ts.map +1 -0
  216. package/dist/handlers/validate.js +201 -0
  217. package/dist/index.d.ts +3 -0
  218. package/dist/index.d.ts.map +1 -0
  219. package/dist/index.js +581 -0
  220. package/dist/lightdash/loader.d.ts +21 -0
  221. package/dist/lightdash/loader.d.ts.map +1 -0
  222. package/dist/lightdash/loader.js +122 -0
  223. package/dist/lightdash/projectType.d.ts +84 -0
  224. package/dist/lightdash/projectType.d.ts.map +1 -0
  225. package/dist/lightdash/projectType.js +75 -0
  226. package/dist/lightdash-config/index.d.ts +2 -0
  227. package/dist/lightdash-config/index.d.ts.map +1 -0
  228. package/dist/lightdash-config/index.js +41 -0
  229. package/dist/lightdash-config/lightdash-config.test.d.ts +2 -0
  230. package/dist/lightdash-config/lightdash-config.test.d.ts.map +1 -0
  231. package/dist/lightdash-config/lightdash-config.test.js +70 -0
  232. package/dist/styles.d.ts +10 -0
  233. package/dist/styles.d.ts.map +1 -0
  234. package/dist/styles.js +14 -0
  235. package/entitlements.plist +33 -0
  236. package/package.json +71 -0
  237. package/track.sh +116 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"globalState.d.ts","sourceRoot":"","sources":["../src/globalState.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,KAAK,YAAY,GAAG;IAChB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACxC,CAAC;AAEF,cAAM,WAAW;IACb,OAAO,CAAC,OAAO,CAAkB;IAEjC,OAAO,CAAC,cAAc,CAAkB;IAExC,OAAO,CAAC,aAAa,CAAsB;IAE3C,OAAO,CAAC,kBAAkB,CAAe;IAEzC,OAAO,CAAC,SAAS,CAAuB;;IAMxC,YAAY,IAAI,MAAM;IAOtB,iBAAiB,CAAC,KAAK,EAAE,OAAO;IAIhC,gBAAgB,IAAI,OAAO;IAI3B,gBAAgB;IAIhB,YAAY,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,GAAG,MAAM,GAAG,GAAG,CAAC,GAAG;IAMrD,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,cAAc,EAAE,OAAO,EAAE;IAUlD,UAAU,CAAC,OAAO,EAAE,OAAO;IAI3B,oBAAoB,CAAC,CAAC,SAAS,MAAM,YAAY,EAC7C,MAAM,EAAE,CAAC,GACV,YAAY,CAAC,CAAC,CAAC,GAAG,SAAS;IAI9B,gBAAgB,CAAC,CAAC,SAAS,MAAM,YAAY,EACzC,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;IAK1B,iBAAiB;IAIjB,KAAK,CAAC,OAAO,EAAE,MAAM;IAMrB,cAAc,CAAC,MAAM,EAAE,MAAM;CAKhC;;AAED,wBAAiC"}
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const ora_1 = tslib_1.__importDefault(require("ora"));
5
+ const uuid_1 = require("uuid");
6
+ const styles = tslib_1.__importStar(require("./styles"));
7
+ class GlobalState {
8
+ verbose = false;
9
+ nonInteractive = false;
10
+ activeSpinner;
11
+ savedPromptAnswers;
12
+ sessionId = null;
13
+ constructor() {
14
+ this.savedPromptAnswers = {};
15
+ }
16
+ getSessionId() {
17
+ if (!this.sessionId) {
18
+ this.sessionId = (0, uuid_1.v4)();
19
+ }
20
+ return this.sessionId;
21
+ }
22
+ setNonInteractive(value) {
23
+ this.nonInteractive = value;
24
+ }
25
+ isNonInteractive() {
26
+ return this.nonInteractive || process.env.CI === 'true';
27
+ }
28
+ getActiveSpinner() {
29
+ return this.activeSpinner;
30
+ }
31
+ startSpinner(options) {
32
+ this.activeSpinner = (0, ora_1.default)(options);
33
+ this.activeSpinner.start();
34
+ return this.activeSpinner;
35
+ }
36
+ log(message, ...optionalParams) {
37
+ const spinner = this.getActiveSpinner();
38
+ const shouldRestartSpinner = spinner?.isSpinning;
39
+ spinner?.stop();
40
+ console.error(message, ...optionalParams);
41
+ if (shouldRestartSpinner) {
42
+ spinner?.start();
43
+ }
44
+ }
45
+ setVerbose(verbose) {
46
+ this.verbose = verbose;
47
+ }
48
+ getSavedPromptAnswer(prompt) {
49
+ return this.savedPromptAnswers[prompt];
50
+ }
51
+ savePromptAnswer(prompt, value) {
52
+ this.savedPromptAnswers[prompt] = value;
53
+ }
54
+ clearPromptAnswer() {
55
+ this.savedPromptAnswers = {};
56
+ }
57
+ debug(message) {
58
+ if (this.verbose) {
59
+ this.log(styles.debug(message));
60
+ }
61
+ }
62
+ logProjectInfo(config) {
63
+ const projectUuid = config.context?.project;
64
+ this.log(`\n${styles.success('Using project:')} ${projectUuid}\n`);
65
+ }
66
+ }
67
+ exports.default = new GlobalState();
@@ -0,0 +1,7 @@
1
+ import { ApiGetAsyncQueryResults, ResultRow } from '@lightdash/common';
2
+ export declare function pollForResults(projectUuid: string, queryUuid: string, options?: {
3
+ pageSize?: number;
4
+ backoffMs?: number;
5
+ }): Promise<ApiGetAsyncQueryResults>;
6
+ export declare function resultsToCsv(columns: string[], rows: ResultRow[]): string;
7
+ //# sourceMappingURL=asyncQuery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asyncQuery.d.ts","sourceRoot":"","sources":["../../src/handlers/asyncQuery.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,uBAAuB,EAEvB,SAAS,EACZ,MAAM,mBAAmB,CAAC;AAa3B,wBAAsB,cAAc,CAChC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACxD,OAAO,CAAC,uBAAuB,CAAC,CAwBlC;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM,CAkBzE"}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pollForResults = pollForResults;
4
+ exports.resultsToCsv = resultsToCsv;
5
+ const tslib_1 = require("tslib");
6
+ const common_1 = require("@lightdash/common");
7
+ const globalState_1 = tslib_1.__importDefault(require("../globalState"));
8
+ const apiClient_1 = require("./dbt/apiClient");
9
+ const INITIAL_BACKOFF_MS = 250;
10
+ const MAX_BACKOFF_MS = 1000;
11
+ function sleep(ms) {
12
+ return new Promise((resolve) => {
13
+ setTimeout(resolve, ms);
14
+ });
15
+ }
16
+ async function pollForResults(projectUuid, queryUuid, options = {}) {
17
+ const { pageSize, backoffMs = INITIAL_BACKOFF_MS } = options;
18
+ const pageSizeParam = pageSize ? `?pageSize=${pageSize}` : '';
19
+ const result = await (0, apiClient_1.lightdashApi)({
20
+ method: 'GET',
21
+ url: `/api/v2/projects/${projectUuid}/query/${queryUuid}${pageSizeParam}`,
22
+ body: undefined,
23
+ });
24
+ globalState_1.default.debug(`> Query status: ${result.status}`);
25
+ if (result.status === common_1.QueryHistoryStatus.PENDING ||
26
+ result.status === common_1.QueryHistoryStatus.QUEUED ||
27
+ result.status === common_1.QueryHistoryStatus.EXECUTING) {
28
+ await sleep(backoffMs);
29
+ return pollForResults(projectUuid, queryUuid, {
30
+ pageSize,
31
+ backoffMs: Math.min(backoffMs * 2, MAX_BACKOFF_MS),
32
+ });
33
+ }
34
+ return result;
35
+ }
36
+ function resultsToCsv(columns, rows) {
37
+ const escapeValue = (value) => {
38
+ if (value === null || value === undefined) {
39
+ return '';
40
+ }
41
+ const str = String(value);
42
+ if (str.includes(',') || str.includes('"') || str.includes('\n')) {
43
+ return `"${str.replace(/"/g, '""')}"`;
44
+ }
45
+ return str;
46
+ };
47
+ const header = columns.map(escapeValue).join(',');
48
+ const dataRows = rows.map((row) => columns.map((col) => escapeValue(row[col]?.value?.raw)).join(','));
49
+ return [header, ...dataRows].join('\n');
50
+ }
@@ -0,0 +1,16 @@
1
+ import { Explore, ExploreError } from '@lightdash/common';
2
+ import { DbtCompileOptions } from './dbt/compile';
3
+ export type CompileHandlerOptions = DbtCompileOptions & {
4
+ projectDir: string;
5
+ profilesDir: string;
6
+ target: string | undefined;
7
+ profile: string | undefined;
8
+ vars: string | undefined;
9
+ verbose: boolean;
10
+ startOfWeek?: number;
11
+ warehouseCredentials?: boolean;
12
+ disableTimestampConversion?: boolean;
13
+ };
14
+ export declare const compile: (options: CompileHandlerOptions) => Promise<(Explore | ExploreError)[]>;
15
+ export declare const compileHandler: (originalOptions: CompileHandlerOptions) => Promise<void>;
16
+ //# sourceMappingURL=compile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/handlers/compile.ts"],"names":[],"mappings":"AAAA,OAAO,EAOH,OAAO,EACP,YAAY,EAYf,MAAM,mBAAmB,CAAC;AAa3B,OAAO,EAAE,iBAAiB,EAA8B,MAAM,eAAe,CAAC;AAI9E,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,GAAG;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACxC,CAAC;AAwHF,eAAO,MAAM,OAAO,GAAU,SAAS,qBAAqB,wCAmP3D,CAAC;AAEF,eAAO,MAAM,cAAc,GACvB,iBAAiB,qBAAqB,kBAmCzC,CAAC"}
@@ -0,0 +1,277 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.compileHandler = exports.compile = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@lightdash/common");
6
+ const warehouses_1 = require("@lightdash/warehouses");
7
+ const path_1 = tslib_1.__importDefault(require("path"));
8
+ const uuid_1 = require("uuid");
9
+ const analytics_1 = require("../analytics/analytics");
10
+ const context_1 = require("../dbt/context");
11
+ const manifest_1 = require("../dbt/manifest");
12
+ const validation_1 = require("../dbt/validation");
13
+ const globalState_1 = tslib_1.__importDefault(require("../globalState"));
14
+ const lightdash_config_1 = require("../lightdash-config");
15
+ const loader_1 = require("../lightdash/loader");
16
+ const projectType_1 = require("../lightdash/projectType");
17
+ const styles = tslib_1.__importStar(require("../styles"));
18
+ const compile_1 = require("./dbt/compile");
19
+ const getDbtVersion_1 = require("./dbt/getDbtVersion");
20
+ const getWarehouseClient_1 = tslib_1.__importDefault(require("./dbt/getWarehouseClient"));
21
+ const getExploresFromLightdashYmlProject = async (projectDir, lightdashProjectConfig, startOfWeek, disableTimestampConversion) => {
22
+ // Try to load Lightdash YAML models
23
+ const lightdashModels = await (0, loader_1.loadLightdashModels)(projectDir);
24
+ if (lightdashModels.length === 0) {
25
+ return null; // No Lightdash models, use dbt path
26
+ }
27
+ globalState_1.default.debug(`> Found ${lightdashModels.length} Lightdash YAML models`);
28
+ if (!lightdashProjectConfig.warehouse?.type) {
29
+ throw new common_1.ParseError('Lightdash models found but no warehouse type specified in lightdash.config.yml.\n' +
30
+ 'Add a warehouse section:\n' +
31
+ 'warehouse:\n' +
32
+ ' type: postgres # or bigquery, snowflake, redshift, databricks, trino, clickhouse');
33
+ }
34
+ const adapterType = lightdashProjectConfig.warehouse.type;
35
+ globalState_1.default.debug(`> Using adapter type from lightdash.config.yml: ${adapterType}`);
36
+ // Convert Lightdash models to DbtModelNode format
37
+ const validModels = (0, common_1.convertLightdashModelsToDbtModels)(lightdashModels);
38
+ if (validModels.length === 0) {
39
+ return null;
40
+ }
41
+ globalState_1.default.debug('> Skipping warehouse catalog (types in YAML)');
42
+ const warehouseSqlBuilder = (0, warehouses_1.warehouseSqlBuilderFromType)(adapterType, startOfWeek);
43
+ const validExplores = await (0, common_1.convertExplores)(validModels, false, warehouseSqlBuilder.getAdapterType(), [], warehouseSqlBuilder, lightdashProjectConfig, {
44
+ disableTimestampConversion,
45
+ allowPartialCompilation: process.env.PARTIAL_COMPILATION_ENABLED !== 'false',
46
+ postProcessors: [common_1.preAggregatePostProcessor],
47
+ });
48
+ return validExplores;
49
+ };
50
+ /**
51
+ * When using --defer, non-selected models pulled in via joins
52
+ * have incorrect schema/relation_name (they point to the dev target
53
+ * instead of production). Return new models with production values
54
+ * from the state manifest.
55
+ */
56
+ async function patchDeferredModels(compiledModels, originallySelectedModelIds, state) {
57
+ const statePath = path_1.default.resolve(state);
58
+ globalState_1.default.debug(`> Loading state manifest for defer from ${statePath}`);
59
+ try {
60
+ const stateManifest = await (0, manifest_1.loadManifest)({
61
+ targetDir: statePath,
62
+ });
63
+ const stateModels = (0, common_1.getModelsFromManifest)(stateManifest);
64
+ const stateModelMap = new Map(stateModels.map((m) => [m.unique_id, m]));
65
+ const patchedModels = compiledModels.map((model) => {
66
+ if (originallySelectedModelIds.includes(model.unique_id)) {
67
+ return model;
68
+ }
69
+ const stateModel = stateModelMap.get(model.unique_id);
70
+ if (!stateModel) {
71
+ return model;
72
+ }
73
+ globalState_1.default.debug(`> Deferred model ${model.name}: using production schema ${stateModel.schema}`);
74
+ return {
75
+ ...model,
76
+ relation_name: stateModel.relation_name,
77
+ schema: stateModel.schema,
78
+ database: stateModel.database,
79
+ };
80
+ });
81
+ const patchedCount = patchedModels.filter((m, i) => m !== compiledModels[i]).length;
82
+ if (patchedCount > 0) {
83
+ globalState_1.default.debug(`> Patched ${patchedCount} deferred model(s) with production schema`);
84
+ }
85
+ return patchedModels;
86
+ }
87
+ catch (e) {
88
+ globalState_1.default.debug(`> Warning: Could not load state manifest for defer patching: ${(0, common_1.getErrorMessage)(e)}`);
89
+ return compiledModels;
90
+ }
91
+ }
92
+ const compile = async (options) => {
93
+ const dbtVersionResult = await (0, getDbtVersion_1.tryGetDbtVersion)();
94
+ const executionId = (0, uuid_1.v4)();
95
+ const startTime = Date.now();
96
+ await analytics_1.LightdashAnalytics.track({
97
+ event: 'compile.started',
98
+ properties: {
99
+ executionId,
100
+ dbtVersion: dbtVersionResult.success
101
+ ? dbtVersionResult.version.verboseVersion
102
+ : undefined,
103
+ useDbtList: !!options.useDbtList,
104
+ skipWarehouseCatalog: !!options.skipWarehouseCatalog,
105
+ skipDbtCompile: !!options.skipDbtCompile,
106
+ },
107
+ });
108
+ const absoluteProjectPath = path_1.default.resolve(options.projectDir);
109
+ globalState_1.default.debug(`> Compiling with project dir ${absoluteProjectPath}`);
110
+ const lightdashProjectConfig = await (0, lightdash_config_1.readAndLoadLightdashProjectConfig)(absoluteProjectPath);
111
+ globalState_1.default.debug(`> Loaded Clary project config`);
112
+ // Try Clary project compile
113
+ let explores = null;
114
+ let dbtMetrics = null;
115
+ explores = await getExploresFromLightdashYmlProject(absoluteProjectPath, lightdashProjectConfig, options.startOfWeek, options.disableTimestampConversion);
116
+ // Load dbt Project
117
+ if (explores === null) {
118
+ if (!dbtVersionResult.success) {
119
+ await analytics_1.LightdashAnalytics.track({
120
+ event: 'compile.error',
121
+ properties: {
122
+ executionId,
123
+ error: 'dbt not found',
124
+ },
125
+ });
126
+ throw dbtVersionResult.error;
127
+ }
128
+ const context = await (0, context_1.getDbtContext)({
129
+ projectDir: absoluteProjectPath,
130
+ targetPath: options.targetPath,
131
+ });
132
+ const { compiledModelIds, originallySelectedModelIds } = await (0, compile_1.maybeCompileModelsAndJoins)({ targetDir: context.targetDir }, options);
133
+ const manifest = await (0, manifest_1.loadManifest)({ targetDir: context.targetDir });
134
+ const manifestVersion = (0, common_1.getDbtManifestVersion)(manifest);
135
+ const manifestModels = (0, common_1.getModelsFromManifest)(manifest);
136
+ const compiledModels = (0, common_1.getCompiledModels)(manifestModels, compiledModelIds);
137
+ // When using --defer, non-selected models pulled in via joins
138
+ // have incorrect schema/relation_name (they point to the dev target
139
+ // instead of production). Patch them from the state manifest.
140
+ const modelsForValidation = options.defer && options.state && originallySelectedModelIds
141
+ ? await patchDeferredModels(compiledModels, originallySelectedModelIds, options.state)
142
+ : compiledModels;
143
+ const adapterType = manifest.metadata.adapter_type;
144
+ const { valid: validModels, invalid: failedExplores } = await (0, validation_1.validateDbtModel)(adapterType, manifestVersion, modelsForValidation);
145
+ if (failedExplores.length > 0) {
146
+ const errors = failedExplores.map((failedExplore) => failedExplore.errors.map((error) => `- ${failedExplore.name}: ${error.message}\n`));
147
+ console.error(styles.warning(`Found ${failedExplores.length} errors when validating dbt models:
148
+ ${errors.join('')}`));
149
+ }
150
+ // Skipping assumes yml has the field types.
151
+ let catalog = {};
152
+ if (!options.skipWarehouseCatalog) {
153
+ const { warehouseClient } = await (0, getWarehouseClient_1.default)({
154
+ isDbtCloudCLI: dbtVersionResult.success
155
+ ? dbtVersionResult.version.isDbtCloudCLI
156
+ : false,
157
+ profilesDir: options.profilesDir,
158
+ profile: options.profile || context.profileName,
159
+ target: options.target,
160
+ startOfWeek: options.startOfWeek,
161
+ });
162
+ globalState_1.default.debug('> Fetching warehouse catalog');
163
+ catalog = await warehouseClient.getCatalog((0, common_1.getSchemaStructureFromDbtModels)(validModels));
164
+ }
165
+ else {
166
+ globalState_1.default.debug('> Skipping warehouse catalog');
167
+ }
168
+ const validModelsWithTypes = (0, common_1.attachTypesToModels)(validModels, catalog, false);
169
+ if (!(0, common_1.isSupportedDbtAdapter)(manifest.metadata)) {
170
+ await analytics_1.LightdashAnalytics.track({
171
+ event: 'compile.error',
172
+ properties: {
173
+ executionId,
174
+ dbtVersion: dbtVersionResult.success
175
+ ? dbtVersionResult.version.verboseVersion
176
+ : undefined,
177
+ error: `Dbt adapter ${manifest.metadata.adapter_type} is not supported`,
178
+ },
179
+ });
180
+ throw new common_1.ParseError(`Dbt adapter ${manifest.metadata.adapter_type} is not supported`);
181
+ }
182
+ globalState_1.default.debug(`> Converting explores with adapter: ${manifest.metadata.adapter_type}`);
183
+ globalState_1.default.debug(`> Loading Clary project config from ${absoluteProjectPath}`);
184
+ const warehouseSqlBuilder = (0, warehouses_1.warehouseSqlBuilderFromType)(adapterType, options.startOfWeek);
185
+ const validExplores = await (0, common_1.convertExplores)(validModelsWithTypes, false, manifest.metadata.adapter_type, [
186
+ common_1.DbtManifestVersion.V10,
187
+ common_1.DbtManifestVersion.V11,
188
+ common_1.DbtManifestVersion.V12,
189
+ ].includes(manifestVersion)
190
+ ? []
191
+ : Object.values(manifest.metrics || {}), warehouseSqlBuilder, lightdashProjectConfig, {
192
+ disableTimestampConversion: options.disableTimestampConversion,
193
+ allowPartialCompilation: process.env.PARTIAL_COMPILATION_ENABLED !== 'false',
194
+ postProcessors: [common_1.preAggregatePostProcessor],
195
+ });
196
+ console.error('');
197
+ explores = [...validExplores, ...failedExplores];
198
+ dbtMetrics = manifest.metrics;
199
+ }
200
+ let errors = 0;
201
+ let partialSuccess = 0;
202
+ let success = 0;
203
+ explores.forEach((e) => {
204
+ let status;
205
+ let messages = '';
206
+ if ((0, common_1.isExploreError)(e)) {
207
+ status = styles.error('ERROR');
208
+ messages = `: ${styles.error(e.errors.map((err) => err.message).join(', '))}`;
209
+ errors += 1;
210
+ }
211
+ else if (process.env.PARTIAL_COMPILATION_ENABLED !== 'false' &&
212
+ 'warnings' in e &&
213
+ e.warnings &&
214
+ e.warnings.length > 0) {
215
+ status = styles.warning('PARTIAL_SUCCESS');
216
+ messages = `: ${styles.warning(e.warnings.map((warning) => warning.message).join(', '))}`;
217
+ partialSuccess += 1;
218
+ }
219
+ else {
220
+ status = styles.success('SUCCESS');
221
+ success += 1;
222
+ }
223
+ console.error(`- ${status}> ${e.name} ${messages}`);
224
+ });
225
+ console.error('');
226
+ if (process.env.PARTIAL_COMPILATION_ENABLED !== 'false' &&
227
+ partialSuccess > 0) {
228
+ console.error(`Compiled ${explores.length} explores, SUCCESS=${success} PARTIAL_SUCCESS=${partialSuccess} ERRORS=${errors}`);
229
+ }
230
+ else {
231
+ console.error(`Compiled ${explores.length} explores, SUCCESS=${success} ERRORS=${errors}`);
232
+ }
233
+ const metricsCount = dbtMetrics === null ? 0 : Object.values(dbtMetrics).length;
234
+ await analytics_1.LightdashAnalytics.track({
235
+ event: 'compile.completed',
236
+ properties: {
237
+ executionId,
238
+ explores: explores.length,
239
+ errors,
240
+ dbtMetrics: metricsCount,
241
+ dbtVersion: dbtVersionResult.success
242
+ ? dbtVersionResult.version.verboseVersion
243
+ : undefined,
244
+ durationMs: Date.now() - startTime,
245
+ },
246
+ });
247
+ return explores;
248
+ };
249
+ exports.compile = compile;
250
+ const compileHandler = async (originalOptions) => {
251
+ const options = { ...originalOptions };
252
+ // Detect project type and configure options accordingly
253
+ const projectTypeConfig = await (0, projectType_1.detectProjectType)({
254
+ projectDir: options.projectDir,
255
+ userOptions: {
256
+ warehouseCredentials: options.warehouseCredentials,
257
+ skipDbtCompile: options.skipDbtCompile,
258
+ skipWarehouseCatalog: options.skipWarehouseCatalog,
259
+ },
260
+ });
261
+ // Apply project type configuration to options
262
+ options.warehouseCredentials = projectTypeConfig.warehouseCredentials;
263
+ options.skipDbtCompile = projectTypeConfig.skipDbtCompile;
264
+ options.skipWarehouseCatalog = projectTypeConfig.skipWarehouseCatalog;
265
+ globalState_1.default.setVerbose(options.verbose);
266
+ const explores = await (0, exports.compile)(options);
267
+ const errorsCount = explores.filter((e) => (0, common_1.isExploreError)(e)).length;
268
+ console.error('');
269
+ if (errorsCount > 0) {
270
+ console.error(styles.error(`Failed to compile project. Found ${errorsCount} error${errorsCount > 1 ? 's' : ''}`));
271
+ process.exit(1);
272
+ }
273
+ else {
274
+ console.error(styles.success('Successfully compiled project'));
275
+ }
276
+ };
277
+ exports.compileHandler = compileHandler;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=compile.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile.test.d.ts","sourceRoot":"","sources":["../../src/handlers/compile.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const promises_1 = tslib_1.__importDefault(require("fs/promises"));
5
+ const os = tslib_1.__importStar(require("os"));
6
+ const path = tslib_1.__importStar(require("path"));
7
+ const styles = tslib_1.__importStar(require("../styles"));
8
+ const compile_1 = require("./compile");
9
+ jest.mock('execa');
10
+ jest.mock('../analytics/analytics');
11
+ jest.mock('../config', () => ({
12
+ getConfig: jest.fn().mockResolvedValue({ user: null, context: null }),
13
+ }));
14
+ describe('compile', () => {
15
+ let tempDir;
16
+ beforeEach(async () => {
17
+ jest.clearAllMocks();
18
+ tempDir = await promises_1.default.mkdtemp(path.join(os.tmpdir(), 'lightdash-compile-test-'));
19
+ // Create minimal lightdash.config.yml
20
+ await promises_1.default.writeFile(path.join(tempDir, 'lightdash.config.yml'), `
21
+ warehouse:
22
+ type: postgres
23
+ `);
24
+ // Create lightdash/models directory and a test model
25
+ const modelsDir = path.join(tempDir, 'lightdash', 'models');
26
+ await promises_1.default.mkdir(modelsDir, { recursive: true });
27
+ await promises_1.default.writeFile(path.join(modelsDir, 'test_model.yml'), `
28
+ version: 1
29
+ type: model
30
+ name: test_model
31
+ description: Test model
32
+ sql_from: "SELECT * FROM test_table"
33
+ dimensions:
34
+ - name: id
35
+ description: ID column
36
+ type: number
37
+ sql: id
38
+ `);
39
+ });
40
+ afterEach(async () => {
41
+ await promises_1.default.rm(tempDir, { recursive: true, force: true });
42
+ });
43
+ test('should compile Lightdash YAML project without dbt installed', async () => {
44
+ // Mock analytics to prevent actual tracking
45
+ const { LightdashAnalytics } = await Promise.resolve().then(() => tslib_1.__importStar(require('../analytics/analytics')));
46
+ LightdashAnalytics.track.mockResolvedValue(undefined);
47
+ const result = await (0, compile_1.compile)({
48
+ projectDir: tempDir,
49
+ profilesDir: '',
50
+ target: undefined,
51
+ profile: undefined,
52
+ vars: undefined,
53
+ verbose: false,
54
+ startOfWeek: 0,
55
+ skipWarehouseCatalog: true,
56
+ skipDbtCompile: true,
57
+ useDbtList: false,
58
+ select: undefined,
59
+ models: undefined,
60
+ threads: undefined,
61
+ noVersionCheck: false,
62
+ exclude: undefined,
63
+ selector: undefined,
64
+ state: undefined,
65
+ fullRefresh: false,
66
+ defer: false,
67
+ targetPath: undefined,
68
+ favorState: false,
69
+ warehouseCredentials: false,
70
+ disableTimestampConversion: false,
71
+ });
72
+ // Should succeed even though dbt is not installed
73
+ expect(result).toBeDefined();
74
+ expect(result.length).toBeGreaterThan(0);
75
+ // Analytics should be called even though dbt is not found
76
+ const trackCalls = LightdashAnalytics.track.mock.calls;
77
+ expect(LightdashAnalytics.track).toHaveBeenCalledWith(expect.objectContaining({
78
+ event: 'compile.started',
79
+ properties: expect.objectContaining({
80
+ dbtVersion: undefined,
81
+ }),
82
+ }));
83
+ expect(LightdashAnalytics.track).toHaveBeenCalledWith(expect.objectContaining({
84
+ event: 'compile.completed',
85
+ }));
86
+ // Verify compile.started was called with undefined dbtVersion
87
+ const startedCall = trackCalls.find((call) => call[0].event === 'compile.started');
88
+ expect(startedCall).toBeDefined();
89
+ expect(startedCall[0].properties.dbtVersion).toBeUndefined();
90
+ });
91
+ test('should display PARTIAL_SUCCESS with warning messages', () => {
92
+ // Mock console.error to capture output
93
+ const consoleSpy = jest.spyOn(console, 'error').mockImplementation();
94
+ // Partial compilation is now enabled by default
95
+ const originalEnv = process.env.PARTIAL_COMPILATION_ENABLED;
96
+ // No need to set to 'true' as it's enabled by default
97
+ try {
98
+ // Create mock explores array with different statuses
99
+ const mockExplores = [
100
+ {
101
+ name: 'successful_explore',
102
+ label: 'Successful Explore',
103
+ tags: [],
104
+ baseTable: 'table1',
105
+ // No warnings or errors - should be SUCCESS
106
+ },
107
+ {
108
+ name: 'explore_with_warnings',
109
+ label: 'Explore with Warnings',
110
+ tags: [],
111
+ baseTable: 'table2',
112
+ warnings: [
113
+ {
114
+ type: 'MISSING_TABLE',
115
+ message: 'Join to table "missing_table" was skipped',
116
+ },
117
+ {
118
+ type: 'FIELD_ERROR',
119
+ message: 'Field compilation warning',
120
+ },
121
+ ],
122
+ },
123
+ {
124
+ name: 'failed_explore',
125
+ label: 'Failed Explore',
126
+ tags: [],
127
+ errors: [
128
+ {
129
+ type: 'NO_DIMENSIONS_FOUND',
130
+ message: 'No dimensions found in model',
131
+ },
132
+ ],
133
+ },
134
+ ];
135
+ // Simulate the explore display logic from compile.ts
136
+ let errors = 0;
137
+ let partialSuccess = 0;
138
+ let success = 0;
139
+ mockExplores.forEach((e) => {
140
+ let status;
141
+ let messages = '';
142
+ if ('errors' in e && e.errors) {
143
+ status = styles.error('ERROR');
144
+ messages = `: ${styles.error(e.errors.map((err) => err.message).join(', '))}`;
145
+ errors += 1;
146
+ }
147
+ else if (process.env.PARTIAL_COMPILATION_ENABLED !== 'false' &&
148
+ 'warnings' in e &&
149
+ e.warnings &&
150
+ e.warnings.length > 0) {
151
+ status = styles.warning('PARTIAL_SUCCESS');
152
+ messages = `: ${styles.warning(e.warnings
153
+ .map((warning) => warning.message)
154
+ .join(', '))}`;
155
+ partialSuccess += 1;
156
+ }
157
+ else {
158
+ status = styles.success('SUCCESS');
159
+ success += 1;
160
+ }
161
+ console.error(`- ${status}> ${e.name} ${messages}`);
162
+ });
163
+ console.error('');
164
+ // Display summary
165
+ if (process.env.PARTIAL_COMPILATION_ENABLED !== 'false' &&
166
+ partialSuccess > 0) {
167
+ console.error(`Compiled ${mockExplores.length} explores, SUCCESS=${success} PARTIAL_SUCCESS=${partialSuccess} ERRORS=${errors}`);
168
+ }
169
+ else {
170
+ console.error(`Compiled ${mockExplores.length} explores, SUCCESS=${success} ERRORS=${errors}`);
171
+ }
172
+ // Verify the output
173
+ const calls = consoleSpy.mock.calls.map((call) => call[0]);
174
+ // Check that PARTIAL_SUCCESS status is displayed
175
+ const partialSuccessCall = calls.find((call) => typeof call === 'string' &&
176
+ call.includes('PARTIAL_SUCCESS> explore_with_warnings'));
177
+ expect(partialSuccessCall).toBeDefined();
178
+ expect(partialSuccessCall).toContain('Join to table "missing_table" was skipped');
179
+ expect(partialSuccessCall).toContain('Field compilation warning');
180
+ // Check that SUCCESS status is displayed
181
+ const successCall = calls.find((call) => typeof call === 'string' &&
182
+ call.includes('SUCCESS> successful_explore'));
183
+ expect(successCall).toBeDefined();
184
+ // Check that ERROR status is displayed
185
+ const errorCall = calls.find((call) => typeof call === 'string' &&
186
+ call.includes('ERROR> failed_explore'));
187
+ expect(errorCall).toBeDefined();
188
+ // Check the summary includes PARTIAL_SUCCESS count
189
+ const summaryCall = calls.find((call) => typeof call === 'string' &&
190
+ call.includes('Compiled') &&
191
+ call.includes('PARTIAL_SUCCESS='));
192
+ expect(summaryCall).toBeDefined();
193
+ expect(summaryCall).toContain('SUCCESS=1 PARTIAL_SUCCESS=1 ERRORS=1');
194
+ }
195
+ finally {
196
+ // Clean up
197
+ consoleSpy.mockRestore();
198
+ process.env.PARTIAL_COMPILATION_ENABLED = originalEnv;
199
+ }
200
+ });
201
+ });