@lightdash/cli 1.94.0 → 1.95.1

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.
@@ -15,6 +15,11 @@ export type AppsValidationIssue = {
15
15
  export type AppsValidationCoverage = DataAppDataReferences['stats'] & {
16
16
  unanalyzed: number;
17
17
  };
18
+ export type AppsValidationUnanalyzedReference = {
19
+ kind: DataAppDataReferences['references'][number]['kind'];
20
+ unresolved: string[];
21
+ location: DataReferenceLocation;
22
+ };
18
23
  export type AppValidationResult = {
19
24
  path: string;
20
25
  name: string | null;
@@ -23,6 +28,7 @@ export type AppValidationResult = {
23
28
  errors: AppsValidationIssue[];
24
29
  warnings: AppsValidationIssue[];
25
30
  coverage: AppsValidationCoverage;
31
+ unanalyzedReferences: AppsValidationUnanalyzedReference[];
26
32
  };
27
33
  export type AppsValidationReport = {
28
34
  build: boolean;
@@ -64,7 +70,8 @@ export declare const validateDataAppBuild: (args: {
64
70
  export declare const fetchLiveDataAppExploreIndex: (projectUuid: string) => Promise<DataAppExploreIndex>;
65
71
  export declare const validateLocalDataApp: (appPath: string, options: ValidateAppOptions) => Promise<AppValidationResult>;
66
72
  export declare const buildAppsValidationReport: (apps: AppValidationResult[], live: boolean, build?: boolean) => AppsValidationReport;
67
- export declare const renderAppsValidationHuman: (report: AppsValidationReport) => string;
73
+ export declare const renderAppsValidationHuman: (report: AppsValidationReport, verbose?: boolean) => string;
74
+ export declare const renderAppsValidationJson: (report: AppsValidationReport) => string;
68
75
  export declare const appsValidateHandler: (pathArgs: string[] | undefined, options: AppsValidateOptions) => Promise<void>;
69
76
  export {};
70
77
  //# sourceMappingURL=validate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/handlers/apps/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAeH,KAAK,WAAW,EAChB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EAGxB,KAAK,qBAAqB,EAC7B,MAAM,mBAAmB,CAAC;AAsB3B,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,MAAM,CAAC;AAElD,MAAM,MAAM,mBAAmB,GAAG;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,kBAAkB,CAAC;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAC7B,OAAO,GACP,QAAQ,GACR,cAAc,GACd,qBAAqB,GACrB,UAAU,GACV,gBAAgB,GAChB,oBAAoB,GACpB,cAAc,CAAC;AAErB,MAAM,MAAM,mBAAmB,GAAG;IAC9B,IAAI,EAAE,uBAAuB,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,qBAAqB,GAAG,IAAI,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,qBAAqB,CAAC,OAAO,CAAC,GAAG;IAClE,UAAU,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC9B,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,QAAQ,EAAE,sBAAsB,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,OAAO,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,mBAAmB,EAAE,MAAM,CAAC;KAC/B,CAAC;IACF,IAAI,EAAE,mBAAmB,EAAE,CAAC;CAC/B,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACrE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,WAAW,CAAC;KACvB,KAAK,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAAC;CACxC,CAAC;AAmLF,KAAK,mBAAmB,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,CACjC,OAAO,EAAE,mBAAmB,KAC3B,OAAO,CAAC,IAAI,CAAC,CAAC;AAmEnB,eAAO,MAAM,oBAAoB,SAAgB;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,CAAC,EAAE,sBAAsB,CAAC;CACvC,KAAG,OAAO,CAAC,mBAAmB,EAAE,CA+HhC,CAAC;AAUF,eAAO,MAAM,4BAA4B,gBACxB,MAAM,KACpB,OAAO,CAAC,mBAAmB,CAqB7B,CAAC;AAEF,eAAO,MAAM,oBAAoB,YACpB,MAAM,WACN,kBAAkB,KAC5B,OAAO,CAAC,mBAAmB,CAsI7B,CAAC;AAEF,eAAO,MAAM,yBAAyB,SAC5B,mBAAmB,EAAE,QACrB,OAAO,sBAEd,oBAyBF,CAAC;AAmBF,eAAO,MAAM,yBAAyB,WAC1B,oBAAoB,KAC7B,MA4CF,CAAC;AAEF,eAAO,MAAM,mBAAmB,aAClB,MAAM,EAAE,GAAG,SAAS,WACrB,mBAAmB,KAC7B,OAAO,CAAC,IAAI,CA4Cd,CAAC"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../src/handlers/apps/validate.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.appsValidateHandler = exports.renderAppsValidationHuman = exports.buildAppsValidationReport = exports.validateLocalDataApp = exports.fetchLiveDataAppExploreIndex = exports.validateDataAppBuild = void 0;
3
+ exports.appsValidateHandler = exports.renderAppsValidationJson = exports.renderAppsValidationHuman = exports.buildAppsValidationReport = exports.validateLocalDataApp = exports.fetchLiveDataAppExploreIndex = exports.validateDataAppBuild = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const common_1 = require("@lightdash/common");
6
6
  const execa_1 = tslib_1.__importDefault(require("execa"));
@@ -293,6 +293,7 @@ const validateLocalDataApp = async (appPath, options) => {
293
293
  errors: [issue('bundle', (0, common_1.getErrorMessage)(error))],
294
294
  warnings,
295
295
  coverage: emptyCoverage(),
296
+ unanalyzedReferences: [],
296
297
  };
297
298
  }
298
299
  const { manifest } = bundle;
@@ -306,6 +307,13 @@ const validateLocalDataApp = async (appPath, options) => {
306
307
  }
307
308
  const extracted = (0, common_1.extractDataAppDataReferences)(sourceFiles);
308
309
  const coverage = toCoverage(extracted.stats);
310
+ const unanalyzedReferences = extracted.references
311
+ .filter((reference) => reference.unresolved.length > 0)
312
+ .map((reference) => ({
313
+ kind: reference.kind,
314
+ unresolved: [...reference.unresolved],
315
+ location: reference.location,
316
+ }));
309
317
  warnings.push(...extracted.parseErrors.map((parseError) => issue('source_parse', `Could not statically analyze ${parseError.path}: ${parseError.message}`)));
310
318
  for (const ref of extracted.references) {
311
319
  if (ref.kind === 'externalFetch' &&
@@ -370,6 +378,7 @@ const validateLocalDataApp = async (appPath, options) => {
370
378
  errors,
371
379
  warnings,
372
380
  coverage,
381
+ unanalyzedReferences,
373
382
  };
374
383
  };
375
384
  exports.validateLocalDataApp = validateLocalDataApp;
@@ -406,7 +415,14 @@ const formatIssue = (entry) => {
406
415
  : '';
407
416
  return `${prefix}${entry.message}`;
408
417
  };
409
- const renderAppsValidationHuman = (report) => {
418
+ const referenceKindLabels = {
419
+ query: 'query',
420
+ savedChart: 'saved chart',
421
+ externalFetch: 'external fetch',
422
+ globalFilter: 'global filter',
423
+ };
424
+ const formatUnanalyzedReference = (reference) => `${reference.location.path}:${reference.location.line}:${reference.location.column} — ${referenceKindLabels[reference.kind]} (unresolved: ${reference.unresolved.join(', ')})`;
425
+ const renderAppsValidationHuman = (report, verbose = false) => {
410
426
  const lines = [
411
427
  `Validating ${report.summary.apps} data app(s) using ${report.mode === 'live'
412
428
  ? 'the live project semantic layer'
@@ -420,6 +436,12 @@ const renderAppsValidationHuman = (report) => {
420
436
  const label = app.name ? `${app.name} (${app.path})` : app.path;
421
437
  lines.push(`${app.valid ? styles.success('✓') : styles.error('✗')} ${label}`);
422
438
  lines.push(` ${formatCoverage(app.coverage)}`);
439
+ if (verbose && app.unanalyzedReferences.length > 0) {
440
+ lines.push(' Static analysis gaps:');
441
+ for (const reference of app.unanalyzedReferences) {
442
+ lines.push(` ${formatUnanalyzedReference(reference)}`);
443
+ }
444
+ }
423
445
  for (const warning of app.warnings) {
424
446
  lines.push(` ${styles.warning('warning')} ${formatIssue(warning)}`);
425
447
  }
@@ -434,6 +456,8 @@ const renderAppsValidationHuman = (report) => {
434
456
  return `${lines.join('\n')}\n`;
435
457
  };
436
458
  exports.renderAppsValidationHuman = renderAppsValidationHuman;
459
+ const renderAppsValidationJson = (report) => `${JSON.stringify(report, (key, value) => (key === 'unanalyzedReferences' ? undefined : value), 2)}\n`;
460
+ exports.renderAppsValidationJson = renderAppsValidationJson;
437
461
  const appsValidateHandler = async (pathArgs, options) => {
438
462
  globalState_1.default.setVerbose(options.verbose);
439
463
  const paths = pathArgs && pathArgs.length > 0 ? pathArgs : ['.'];
@@ -460,8 +484,8 @@ const appsValidateHandler = async (pathArgs, options) => {
460
484
  })));
461
485
  const report = (0, exports.buildAppsValidationReport)(apps, options.live, options.build);
462
486
  process.stdout.write(options.format === 'json'
463
- ? `${JSON.stringify(report, null, 2)}\n`
464
- : (0, exports.renderAppsValidationHuman)(report));
487
+ ? (0, exports.renderAppsValidationJson)(report)
488
+ : (0, exports.renderAppsValidationHuman)(report, options.verbose));
465
489
  if (!report.valid) {
466
490
  throw new common_1.ParameterError(`Data app validation failed with ${report.summary.errors} error(s).`);
467
491
  }
@@ -392,29 +392,69 @@ describe('validateDataAppBuild', () => {
392
392
  });
393
393
  });
394
394
  describe('renderAppsValidationHuman', () => {
395
- it('makes partial green coverage explicit', () => {
396
- const report = (0, validate_1.buildAppsValidationReport)([
397
- {
398
- path: '/tmp/orders-app',
399
- name: 'Orders app',
400
- projectUuid: 'project-uuid',
401
- valid: true,
402
- errors: [],
403
- warnings: [],
404
- coverage: {
405
- callSites: 14,
406
- fullyResolved: 11,
407
- partiallyResolved: 2,
408
- unresolved: 1,
409
- unanalyzed: 3,
410
- },
395
+ const report = (0, validate_1.buildAppsValidationReport)([
396
+ {
397
+ path: '/tmp/orders-app',
398
+ name: 'Orders app',
399
+ projectUuid: 'project-uuid',
400
+ valid: true,
401
+ errors: [],
402
+ warnings: [],
403
+ coverage: {
404
+ callSites: 14,
405
+ fullyResolved: 11,
406
+ partiallyResolved: 2,
407
+ unresolved: 1,
408
+ unanalyzed: 3,
411
409
  },
412
- ], false, true);
410
+ unanalyzedReferences: [
411
+ {
412
+ kind: 'query',
413
+ unresolved: ['explore', 'dimensions'],
414
+ location: {
415
+ path: 'src/DynamicQuery.tsx',
416
+ line: 8,
417
+ column: 17,
418
+ },
419
+ },
420
+ {
421
+ kind: 'globalFilter',
422
+ unresolved: ['field'],
423
+ location: {
424
+ path: 'src/ResultsTable.tsx',
425
+ line: 42,
426
+ column: 21,
427
+ },
428
+ },
429
+ {
430
+ kind: 'externalFetch',
431
+ unresolved: ['alias'],
432
+ location: {
433
+ path: 'src/ExternalData.tsx',
434
+ line: 12,
435
+ column: 9,
436
+ },
437
+ },
438
+ ],
439
+ },
440
+ ], false, true);
441
+ it('makes partial green coverage explicit', () => {
413
442
  const output = (0, validate_1.renderAppsValidationHuman)(report);
414
443
  expect(output).toContain("3 of 14 data-reference call site(s) couldn't be fully analyzed");
415
444
  expect(output).toContain('unresolved values were skipped');
416
445
  expect(output).toContain('Validation passed');
417
446
  expect(output).toContain('Offline snapshots may be stale');
418
447
  expect(output).toContain('running Vite production builds');
448
+ expect(output).not.toContain('Static analysis gaps');
449
+ });
450
+ it('lists unresolved call sites and parts in verbose output', () => {
451
+ const output = (0, validate_1.renderAppsValidationHuman)(report, true);
452
+ expect(output).toContain('Static analysis gaps:');
453
+ expect(output).toContain('src/DynamicQuery.tsx:8:17 — query (unresolved: explore, dimensions)');
454
+ expect(output).toContain('src/ResultsTable.tsx:42:21 — global filter (unresolved: field)');
455
+ });
456
+ it('keeps verbose-only reference details out of JSON output', () => {
457
+ const output = (0, validate_1.renderAppsValidationJson)(report);
458
+ expect(JSON.parse(output)).not.toHaveProperty('apps.0.unanalyzedReferences');
419
459
  });
420
460
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightdash/cli",
3
- "version": "1.94.0",
3
+ "version": "1.95.1",
4
4
  "description": "Lightdash CLI tool",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -41,8 +41,8 @@
41
41
  "unique-names-generator": "4.7.1",
42
42
  "uuid": "11.1.1",
43
43
  "yaml": "2.8.3",
44
- "@lightdash/common": "1.94.0",
45
- "@lightdash/warehouses": "1.94.0"
44
+ "@lightdash/common": "1.95.1",
45
+ "@lightdash/warehouses": "1.95.1"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/inquirer": "8.2.4",