@lightdash/cli 1.93.2 → 1.95.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.
|
@@ -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;
|
|
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
|
|
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
|
-
?
|
|
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
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
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
|
-
|
|
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.
|
|
3
|
+
"version": "1.95.0",
|
|
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.
|
|
45
|
-
"@lightdash/warehouses": "1.
|
|
44
|
+
"@lightdash/common": "1.95.0",
|
|
45
|
+
"@lightdash/warehouses": "1.95.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/inquirer": "8.2.4",
|