@caracal-lynx/sluice 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.
- package/CLAUDE.md +1822 -0
- package/LICENCE-FAQ.md +74 -0
- package/LICENSE +92 -0
- package/README.md +582 -0
- package/dist/adapters/source/csv.d.ts +10 -0
- package/dist/adapters/source/csv.d.ts.map +1 -0
- package/dist/adapters/source/csv.js +110 -0
- package/dist/adapters/source/csv.js.map +1 -0
- package/dist/adapters/source/index.d.ts +9 -0
- package/dist/adapters/source/index.d.ts.map +1 -0
- package/dist/adapters/source/index.js +26 -0
- package/dist/adapters/source/index.js.map +1 -0
- package/dist/adapters/source/mssql.d.ts +11 -0
- package/dist/adapters/source/mssql.d.ts.map +1 -0
- package/dist/adapters/source/mssql.js +230 -0
- package/dist/adapters/source/mssql.js.map +1 -0
- package/dist/adapters/source/pg.d.ts +11 -0
- package/dist/adapters/source/pg.d.ts.map +1 -0
- package/dist/adapters/source/pg.js +88 -0
- package/dist/adapters/source/pg.js.map +1 -0
- package/dist/adapters/source/registry.d.ts +10 -0
- package/dist/adapters/source/registry.d.ts.map +1 -0
- package/dist/adapters/source/registry.js +36 -0
- package/dist/adapters/source/registry.js.map +1 -0
- package/dist/adapters/source/rest.d.ts +16 -0
- package/dist/adapters/source/rest.d.ts.map +1 -0
- package/dist/adapters/source/rest.js +182 -0
- package/dist/adapters/source/rest.js.map +1 -0
- package/dist/adapters/source/rest.types.d.ts +15 -0
- package/dist/adapters/source/rest.types.d.ts.map +1 -0
- package/dist/adapters/source/rest.types.js +6 -0
- package/dist/adapters/source/rest.types.js.map +1 -0
- package/dist/adapters/source/types.d.ts +23 -0
- package/dist/adapters/source/types.d.ts.map +1 -0
- package/dist/adapters/source/types.js +4 -0
- package/dist/adapters/source/types.js.map +1 -0
- package/dist/adapters/source/xlsx.d.ts +10 -0
- package/dist/adapters/source/xlsx.d.ts.map +1 -0
- package/dist/adapters/source/xlsx.js +71 -0
- package/dist/adapters/source/xlsx.js.map +1 -0
- package/dist/adapters/target/bc.d.ts +21 -0
- package/dist/adapters/target/bc.d.ts.map +1 -0
- package/dist/adapters/target/bc.js +188 -0
- package/dist/adapters/target/bc.js.map +1 -0
- package/dist/adapters/target/bluecherry.d.ts +10 -0
- package/dist/adapters/target/bluecherry.d.ts.map +1 -0
- package/dist/adapters/target/bluecherry.js +127 -0
- package/dist/adapters/target/bluecherry.js.map +1 -0
- package/dist/adapters/target/csv.d.ts +10 -0
- package/dist/adapters/target/csv.d.ts.map +1 -0
- package/dist/adapters/target/csv.js +40 -0
- package/dist/adapters/target/csv.js.map +1 -0
- package/dist/adapters/target/ifs.d.ts +10 -0
- package/dist/adapters/target/ifs.d.ts.map +1 -0
- package/dist/adapters/target/ifs.js +55 -0
- package/dist/adapters/target/ifs.js.map +1 -0
- package/dist/adapters/target/index.d.ts +8 -0
- package/dist/adapters/target/index.d.ts.map +1 -0
- package/dist/adapters/target/index.js +22 -0
- package/dist/adapters/target/index.js.map +1 -0
- package/dist/adapters/target/pg.d.ts +11 -0
- package/dist/adapters/target/pg.d.ts.map +1 -0
- package/dist/adapters/target/pg.js +103 -0
- package/dist/adapters/target/pg.js.map +1 -0
- package/dist/adapters/target/registry.d.ts +9 -0
- package/dist/adapters/target/registry.d.ts.map +1 -0
- package/dist/adapters/target/registry.js +29 -0
- package/dist/adapters/target/registry.js.map +1 -0
- package/dist/adapters/target/types.d.ts +15 -0
- package/dist/adapters/target/types.d.ts.map +1 -0
- package/dist/adapters/target/types.js +4 -0
- package/dist/adapters/target/types.js.map +1 -0
- package/dist/cli.d.ts +25 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +354 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +6 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/loader.d.ts +5 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +135 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/schema.d.ts +4162 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +263 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/types.d.ts +3 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +4 -0
- package/dist/config/types.js.map +1 -0
- package/dist/dq/engine.d.ts +10 -0
- package/dist/dq/engine.d.ts.map +1 -0
- package/dist/dq/engine.js +114 -0
- package/dist/dq/engine.js.map +1 -0
- package/dist/dq/index.d.ts +6 -0
- package/dist/dq/index.d.ts.map +1 -0
- package/dist/dq/index.js +6 -0
- package/dist/dq/index.js.map +1 -0
- package/dist/dq/reporter.d.ts +5 -0
- package/dist/dq/reporter.d.ts.map +1 -0
- package/dist/dq/reporter.js +41 -0
- package/dist/dq/reporter.js.map +1 -0
- package/dist/dq/rules/allowedValues.d.ts +7 -0
- package/dist/dq/rules/allowedValues.d.ts.map +1 -0
- package/dist/dq/rules/allowedValues.js +26 -0
- package/dist/dq/rules/allowedValues.js.map +1 -0
- package/dist/dq/rules/email.d.ts +7 -0
- package/dist/dq/rules/email.d.ts.map +1 -0
- package/dist/dq/rules/email.js +24 -0
- package/dist/dq/rules/email.js.map +1 -0
- package/dist/dq/rules/index.d.ts +15 -0
- package/dist/dq/rules/index.d.ts.map +1 -0
- package/dist/dq/rules/index.js +30 -0
- package/dist/dq/rules/index.js.map +1 -0
- package/dist/dq/rules/maxLength.d.ts +7 -0
- package/dist/dq/rules/maxLength.d.ts.map +1 -0
- package/dist/dq/rules/maxLength.js +25 -0
- package/dist/dq/rules/maxLength.js.map +1 -0
- package/dist/dq/rules/minMax.d.ts +11 -0
- package/dist/dq/rules/minMax.d.ts.map +1 -0
- package/dist/dq/rules/minMax.js +52 -0
- package/dist/dq/rules/minMax.js.map +1 -0
- package/dist/dq/rules/notNull.d.ts +7 -0
- package/dist/dq/rules/notNull.d.ts.map +1 -0
- package/dist/dq/rules/notNull.js +21 -0
- package/dist/dq/rules/notNull.js.map +1 -0
- package/dist/dq/rules/pattern.d.ts +7 -0
- package/dist/dq/rules/pattern.d.ts.map +1 -0
- package/dist/dq/rules/pattern.js +31 -0
- package/dist/dq/rules/pattern.js.map +1 -0
- package/dist/dq/rules/types.d.ts +6 -0
- package/dist/dq/rules/types.d.ts.map +1 -0
- package/dist/dq/rules/types.js +4 -0
- package/dist/dq/rules/types.js.map +1 -0
- package/dist/dq/rules/ukPostcode.d.ts +7 -0
- package/dist/dq/rules/ukPostcode.d.ts.map +1 -0
- package/dist/dq/rules/ukPostcode.js +24 -0
- package/dist/dq/rules/ukPostcode.js.map +1 -0
- package/dist/dq/rules/unique.d.ts +14 -0
- package/dist/dq/rules/unique.d.ts.map +1 -0
- package/dist/dq/rules/unique.js +9 -0
- package/dist/dq/rules/unique.js.map +1 -0
- package/dist/dq/types.d.ts +29 -0
- package/dist/dq/types.d.ts.map +1 -0
- package/dist/dq/types.js +4 -0
- package/dist/dq/types.js.map +1 -0
- package/dist/enrich/types.d.ts +87 -0
- package/dist/enrich/types.d.ts.map +1 -0
- package/dist/enrich/types.js +4 -0
- package/dist/enrich/types.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/merge/conflict-log.d.ts +9 -0
- package/dist/merge/conflict-log.d.ts.map +1 -0
- package/dist/merge/conflict-log.js +28 -0
- package/dist/merge/conflict-log.js.map +1 -0
- package/dist/merge/engine.d.ts +7 -0
- package/dist/merge/engine.d.ts.map +1 -0
- package/dist/merge/engine.js +19 -0
- package/dist/merge/engine.js.map +1 -0
- package/dist/merge/index.d.ts +11 -0
- package/dist/merge/index.d.ts.map +1 -0
- package/dist/merge/index.js +34 -0
- package/dist/merge/index.js.map +1 -0
- package/dist/merge/sql-builder.d.ts +19 -0
- package/dist/merge/sql-builder.d.ts.map +1 -0
- package/dist/merge/sql-builder.js +148 -0
- package/dist/merge/sql-builder.js.map +1 -0
- package/dist/merge/strategies/coalesce.d.ts +17 -0
- package/dist/merge/strategies/coalesce.d.ts.map +1 -0
- package/dist/merge/strategies/coalesce.js +77 -0
- package/dist/merge/strategies/coalesce.js.map +1 -0
- package/dist/merge/strategies/index.d.ts +5 -0
- package/dist/merge/strategies/index.d.ts.map +1 -0
- package/dist/merge/strategies/index.js +7 -0
- package/dist/merge/strategies/index.js.map +1 -0
- package/dist/merge/strategies/intersect.d.ts +17 -0
- package/dist/merge/strategies/intersect.d.ts.map +1 -0
- package/dist/merge/strategies/intersect.js +75 -0
- package/dist/merge/strategies/intersect.js.map +1 -0
- package/dist/merge/strategies/priority-override.d.ts +16 -0
- package/dist/merge/strategies/priority-override.d.ts.map +1 -0
- package/dist/merge/strategies/priority-override.js +78 -0
- package/dist/merge/strategies/priority-override.js.map +1 -0
- package/dist/merge/strategies/registry.d.ts +8 -0
- package/dist/merge/strategies/registry.d.ts.map +1 -0
- package/dist/merge/strategies/registry.js +19 -0
- package/dist/merge/strategies/registry.js.map +1 -0
- package/dist/merge/strategies/union.d.ts +15 -0
- package/dist/merge/strategies/union.d.ts.map +1 -0
- package/dist/merge/strategies/union.js +75 -0
- package/dist/merge/strategies/union.js.map +1 -0
- package/dist/merge/types.d.ts +24 -0
- package/dist/merge/types.d.ts.map +1 -0
- package/dist/merge/types.js +4 -0
- package/dist/merge/types.js.map +1 -0
- package/dist/multi-source-runner.d.ts +22 -0
- package/dist/multi-source-runner.d.ts.map +1 -0
- package/dist/multi-source-runner.js +398 -0
- package/dist/multi-source-runner.js.map +1 -0
- package/dist/plugins/index.d.ts +4 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +5 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/loader.d.ts +22 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +151 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/registry.d.ts +25 -0
- package/dist/plugins/registry.d.ts.map +1 -0
- package/dist/plugins/registry.js +42 -0
- package/dist/plugins/registry.js.map +1 -0
- package/dist/plugins/types.d.ts +61 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +4 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/runner.d.ts +97 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +520 -0
- package/dist/runner.js.map +1 -0
- package/dist/staging/index.d.ts +3 -0
- package/dist/staging/index.d.ts.map +1 -0
- package/dist/staging/index.js +5 -0
- package/dist/staging/index.js.map +1 -0
- package/dist/staging/schema.d.ts +19 -0
- package/dist/staging/schema.d.ts.map +1 -0
- package/dist/staging/schema.js +15 -0
- package/dist/staging/schema.js.map +1 -0
- package/dist/staging/store.d.ts +71 -0
- package/dist/staging/store.d.ts.map +1 -0
- package/dist/staging/store.js +270 -0
- package/dist/staging/store.js.map +1 -0
- package/dist/transform/cleanse.d.ts +2 -0
- package/dist/transform/cleanse.d.ts.map +1 -0
- package/dist/transform/cleanse.js +59 -0
- package/dist/transform/cleanse.js.map +1 -0
- package/dist/transform/engine.d.ts +10 -0
- package/dist/transform/engine.d.ts.map +1 -0
- package/dist/transform/engine.js +225 -0
- package/dist/transform/engine.js.map +1 -0
- package/dist/transform/expression.d.ts +5 -0
- package/dist/transform/expression.d.ts.map +1 -0
- package/dist/transform/expression.js +52 -0
- package/dist/transform/expression.js.map +1 -0
- package/dist/transform/index.d.ts +6 -0
- package/dist/transform/index.d.ts.map +1 -0
- package/dist/transform/index.js +7 -0
- package/dist/transform/index.js.map +1 -0
- package/dist/transform/lookup.d.ts +10 -0
- package/dist/transform/lookup.d.ts.map +1 -0
- package/dist/transform/lookup.js +66 -0
- package/dist/transform/lookup.js.map +1 -0
- package/dist/transform/types.d.ts +10 -0
- package/dist/transform/types.d.ts.map +1 -0
- package/dist/transform/types.js +4 -0
- package/dist/transform/types.js.map +1 -0
- package/dist/utils/env.d.ts +3 -0
- package/dist/utils/env.d.ts.map +1 -0
- package/dist/utils/env.js +26 -0
- package/dist/utils/env.js.map +1 -0
- package/dist/utils/errors.d.ts +26 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +39 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +7 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +16 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/progress.d.ts +66 -0
- package/dist/utils/progress.d.ts.map +1 -0
- package/dist/utils/progress.js +283 -0
- package/dist/utils/progress.js.map +1 -0
- package/package.json +92 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SPDX-License-Identifier: Elastic-2.0
|
|
3
|
+
// Copyright (c) 2026 Caracal Lynx Ltd.
|
|
4
|
+
/**
|
|
5
|
+
* Sluice CLI.
|
|
6
|
+
*
|
|
7
|
+
* Commands (per CLAUDE.md):
|
|
8
|
+
* sluice run <pipeline.yaml> Full pipeline run
|
|
9
|
+
* sluice validate <pipeline.yaml> DQ + transform only; no load
|
|
10
|
+
* sluice profile <pipeline.yaml> Extract + column profiling; no DQ
|
|
11
|
+
* sluice check <pipeline.yaml> Config validation only; no execution
|
|
12
|
+
*
|
|
13
|
+
* Exit codes:
|
|
14
|
+
* 0 success
|
|
15
|
+
* 1 pipeline error
|
|
16
|
+
* 2 DQ critical violations
|
|
17
|
+
* 3 config error
|
|
18
|
+
* 4 enrich error (Phase 4)
|
|
19
|
+
*/
|
|
20
|
+
import { Command } from 'commander';
|
|
21
|
+
import * as path from 'node:path';
|
|
22
|
+
import { ConfigLoader } from './config/loader.js';
|
|
23
|
+
import { isMultiSource } from './config/types.js';
|
|
24
|
+
import { MultiSourcePipelineRunner } from './multi-source-runner.js';
|
|
25
|
+
import { PipelineRunner, _isEnrichPhaseRegistered, } from './runner.js';
|
|
26
|
+
import { RuleRegistry, TransformRegistry, loadPlugins, loadNpmPlugins } from './plugins/index.js';
|
|
27
|
+
import { MergeStrategyRegistry } from './merge/index.js';
|
|
28
|
+
import { loadEnv } from './utils/env.js';
|
|
29
|
+
import { ConfigError, EnrichError, PipelineDQError, PipelineError } from './utils/errors.js';
|
|
30
|
+
import { logger } from './utils/logger.js';
|
|
31
|
+
import { ProgressReporter } from './utils/progress.js';
|
|
32
|
+
export function resolvePluginDirs(cwd, pluginDirs = []) {
|
|
33
|
+
return Array.from(new Set([
|
|
34
|
+
path.resolve(cwd, 'plugins'),
|
|
35
|
+
...pluginDirs.map((dir) => path.resolve(cwd, dir)),
|
|
36
|
+
]));
|
|
37
|
+
}
|
|
38
|
+
export function exitCodeFor(err) {
|
|
39
|
+
if (err instanceof PipelineDQError)
|
|
40
|
+
return 2;
|
|
41
|
+
if (err instanceof ConfigError)
|
|
42
|
+
return 3;
|
|
43
|
+
if (err instanceof EnrichError)
|
|
44
|
+
return 4;
|
|
45
|
+
if (err instanceof PipelineError)
|
|
46
|
+
return 1;
|
|
47
|
+
return 1;
|
|
48
|
+
}
|
|
49
|
+
function applyGlobals(opts) {
|
|
50
|
+
loadEnv(opts.env);
|
|
51
|
+
if (opts.logLevel)
|
|
52
|
+
logger.level = opts.logLevel;
|
|
53
|
+
if (opts.silent) {
|
|
54
|
+
// Errors still reach stderr via the logger's multistream; info/warn are dropped.
|
|
55
|
+
logger.level = 'error';
|
|
56
|
+
}
|
|
57
|
+
const overrides = {};
|
|
58
|
+
if (opts.output !== undefined)
|
|
59
|
+
overrides.outputDir = opts.output;
|
|
60
|
+
if (opts.dryRun)
|
|
61
|
+
overrides.dryRun = true;
|
|
62
|
+
if (opts.plugins?.length)
|
|
63
|
+
overrides.pluginDirs = opts.plugins;
|
|
64
|
+
return overrides;
|
|
65
|
+
}
|
|
66
|
+
function phaseCountForRun(config, skipEnrich) {
|
|
67
|
+
const willLoad = !(config.run.dryRun || config.run.mode === 'validate-only');
|
|
68
|
+
// Enrich runs only when: enrich block configured, run isn't validate/dry-run,
|
|
69
|
+
// --no-enrich wasn't passed, and the private package has registered a factory.
|
|
70
|
+
const willEnrich = Boolean(config.enrich) &&
|
|
71
|
+
willLoad &&
|
|
72
|
+
!skipEnrich &&
|
|
73
|
+
_isEnrichPhaseRegistered();
|
|
74
|
+
const enrichPhases = willEnrich ? 1 : 0;
|
|
75
|
+
if (isMultiSource(config)) {
|
|
76
|
+
const sourcesWithPreMergeRules = new Set(config.dq.rules.filter((r) => r.sourceId).map((r) => r.sourceId));
|
|
77
|
+
// Extract per source + DQ per source with rules + Merge [+ Enrich] + post-merge DQ + Transform [+ Load]
|
|
78
|
+
return (config.sources.length +
|
|
79
|
+
sourcesWithPreMergeRules.size +
|
|
80
|
+
1 + // merge
|
|
81
|
+
enrichPhases +
|
|
82
|
+
1 + // post-merge DQ
|
|
83
|
+
1 + // transform
|
|
84
|
+
(willLoad ? 1 : 0));
|
|
85
|
+
}
|
|
86
|
+
// Single source: Extract [+ Enrich] + DQ + Transform [+ Load]
|
|
87
|
+
return 3 + enrichPhases + (willLoad ? 1 : 0);
|
|
88
|
+
}
|
|
89
|
+
function buildProgressReporter(opts, config, skipEnrich = false) {
|
|
90
|
+
return new ProgressReporter({
|
|
91
|
+
silent: opts.silent ?? false,
|
|
92
|
+
totalPhases: phaseCountForRun(config, skipEnrich),
|
|
93
|
+
logLevel: (opts.logLevel ?? 'info'),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
export async function createRunnerForPipeline(yaml) {
|
|
97
|
+
const config = await ConfigLoader.load(yaml);
|
|
98
|
+
return isMultiSource(config)
|
|
99
|
+
? new MultiSourcePipelineRunner()
|
|
100
|
+
: new PipelineRunner();
|
|
101
|
+
}
|
|
102
|
+
async function cmdRun(yaml, program, cmdOpts = {}) {
|
|
103
|
+
const opts = program.opts();
|
|
104
|
+
const overrides = applyGlobals(opts);
|
|
105
|
+
if (cmdOpts.enrich === false)
|
|
106
|
+
overrides.skipEnrich = true;
|
|
107
|
+
let progress;
|
|
108
|
+
try {
|
|
109
|
+
const runner = await createRunnerForPipeline(yaml);
|
|
110
|
+
const config = await ConfigLoader.load(yaml);
|
|
111
|
+
progress = buildProgressReporter(opts, config, overrides.skipEnrich ?? false);
|
|
112
|
+
overrides.progress = progress;
|
|
113
|
+
const result = await runner.run(yaml, overrides);
|
|
114
|
+
logger.info({
|
|
115
|
+
pipeline: result.pipeline,
|
|
116
|
+
mode: result.mode,
|
|
117
|
+
rowsExtracted: result.extract.rowsExtracted,
|
|
118
|
+
rowsMerged: result.merge?.rowsMerged,
|
|
119
|
+
mergeConflicts: result.merge?.conflicts,
|
|
120
|
+
unmatchedRows: result.merge?.unmatched,
|
|
121
|
+
rowsLoaded: result.load?.rowsLoaded ?? 0,
|
|
122
|
+
stateFile: result.stateFilePath,
|
|
123
|
+
}, 'sluice run: complete');
|
|
124
|
+
process.exit(0);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
progress?.stop();
|
|
128
|
+
logger.error({ err }, 'sluice run: failed');
|
|
129
|
+
process.exit(exitCodeFor(err));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function cmdValidate(yaml, program) {
|
|
133
|
+
const opts = program.opts();
|
|
134
|
+
const overrides = applyGlobals(opts);
|
|
135
|
+
overrides.mode = 'validate-only';
|
|
136
|
+
let progress;
|
|
137
|
+
try {
|
|
138
|
+
const runner = await createRunnerForPipeline(yaml);
|
|
139
|
+
const config = await ConfigLoader.load(yaml);
|
|
140
|
+
progress = buildProgressReporter(opts, { ...config, run: { ...config.run, mode: 'validate-only' } });
|
|
141
|
+
overrides.progress = progress;
|
|
142
|
+
const result = await runner.run(yaml, overrides);
|
|
143
|
+
logger.info({
|
|
144
|
+
pipeline: result.pipeline,
|
|
145
|
+
rowsMerged: result.merge?.rowsMerged,
|
|
146
|
+
rowsChecked: result.dq.rowsChecked,
|
|
147
|
+
critical: result.dq.violations.critical,
|
|
148
|
+
warnings: result.dq.violations.warning,
|
|
149
|
+
}, 'sluice validate: complete');
|
|
150
|
+
process.exit(0);
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
progress?.stop();
|
|
154
|
+
logger.error({ err }, 'sluice validate: failed');
|
|
155
|
+
process.exit(exitCodeFor(err));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async function cmdProfile(yaml, program) {
|
|
159
|
+
const opts = program.opts();
|
|
160
|
+
const overrides = applyGlobals(opts);
|
|
161
|
+
let progress;
|
|
162
|
+
try {
|
|
163
|
+
const runner = await createRunnerForPipeline(yaml);
|
|
164
|
+
const config = await ConfigLoader.load(yaml);
|
|
165
|
+
// profile = extract-only for single-source; extract+merge for multi-source.
|
|
166
|
+
progress = new ProgressReporter({
|
|
167
|
+
silent: opts.silent ?? false,
|
|
168
|
+
totalPhases: isMultiSource(config) ? config.sources.length + 1 : 1,
|
|
169
|
+
logLevel: (opts.logLevel ?? 'info'),
|
|
170
|
+
});
|
|
171
|
+
overrides.progress = progress;
|
|
172
|
+
const result = await runner.profile(yaml, overrides);
|
|
173
|
+
logger.info({ pipeline: result.pipeline, rowsExtracted: result.extract.rowsExtracted, profilePath: result.profilePath }, 'sluice profile: complete');
|
|
174
|
+
process.exit(0);
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
progress?.stop();
|
|
178
|
+
logger.error({ err }, 'sluice profile: failed');
|
|
179
|
+
process.exit(exitCodeFor(err));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function cmdCheck(yaml, program) {
|
|
183
|
+
applyGlobals(program.opts());
|
|
184
|
+
try {
|
|
185
|
+
const config = await ConfigLoader.load(yaml);
|
|
186
|
+
const isMulti = isMultiSource(config);
|
|
187
|
+
logger.info({
|
|
188
|
+
pipeline: config.pipeline.name,
|
|
189
|
+
source: config.source?.adapter ?? 'multi',
|
|
190
|
+
sourceCount: isMulti ? config.sources.length : 1,
|
|
191
|
+
mergeStrategy: isMulti ? config.merge.strategy : undefined,
|
|
192
|
+
target: config.target.adapter,
|
|
193
|
+
rules: config.dq.rules.length,
|
|
194
|
+
fields: config.transform.fields.length,
|
|
195
|
+
}, 'sluice check: config is valid');
|
|
196
|
+
process.exit(0);
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
logger.error({ err }, 'sluice check: failed');
|
|
200
|
+
process.exit(exitCodeFor(err));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
async function cmdPlugins(program) {
|
|
204
|
+
const opts = program.opts();
|
|
205
|
+
const overrides = applyGlobals(opts);
|
|
206
|
+
try {
|
|
207
|
+
const cwd = process.cwd();
|
|
208
|
+
const ruleRegistry = new RuleRegistry();
|
|
209
|
+
const transformRegistry = new TransformRegistry();
|
|
210
|
+
const pluginDirs = resolvePluginDirs(cwd, overrides.pluginDirs ?? []);
|
|
211
|
+
// Load both tier 2 (file-based) and tier 3 (npm) plugins
|
|
212
|
+
for (const dir of pluginDirs) {
|
|
213
|
+
await loadPlugins(dir, ruleRegistry, transformRegistry, MergeStrategyRegistry);
|
|
214
|
+
}
|
|
215
|
+
const configPath = path.join(cwd, 'sluice.config.yaml');
|
|
216
|
+
await loadNpmPlugins(configPath, ruleRegistry, transformRegistry, MergeStrategyRegistry);
|
|
217
|
+
const ruleIds = ruleRegistry.list();
|
|
218
|
+
const transformIds = transformRegistry.list();
|
|
219
|
+
const mergeStrategyIds = MergeStrategyRegistry.list();
|
|
220
|
+
logger.info({
|
|
221
|
+
rules: ruleIds,
|
|
222
|
+
transforms: transformIds,
|
|
223
|
+
mergeStrategies: mergeStrategyIds,
|
|
224
|
+
}, 'sluice plugins: loaded');
|
|
225
|
+
process.exit(0);
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
logger.error({ err }, 'sluice plugins: failed');
|
|
229
|
+
process.exit(exitCodeFor(err));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async function cmdMergeListStrategies(program) {
|
|
233
|
+
const overrides = applyGlobals(program.opts());
|
|
234
|
+
try {
|
|
235
|
+
const cwd = process.cwd();
|
|
236
|
+
const ruleRegistry = new RuleRegistry();
|
|
237
|
+
const transformRegistry = new TransformRegistry();
|
|
238
|
+
const pluginDirs = resolvePluginDirs(cwd, overrides.pluginDirs ?? []);
|
|
239
|
+
for (const dir of pluginDirs) {
|
|
240
|
+
await loadPlugins(dir, ruleRegistry, transformRegistry, MergeStrategyRegistry);
|
|
241
|
+
}
|
|
242
|
+
const configPath = path.join(cwd, 'sluice.config.yaml');
|
|
243
|
+
await loadNpmPlugins(configPath, ruleRegistry, transformRegistry, MergeStrategyRegistry);
|
|
244
|
+
const strategyIds = MergeStrategyRegistry.list();
|
|
245
|
+
const strategies = strategyIds.map((id) => {
|
|
246
|
+
const strategy = MergeStrategyRegistry.get(id);
|
|
247
|
+
return { id: strategy.id, description: strategy.description ?? strategy.id };
|
|
248
|
+
});
|
|
249
|
+
logger.info({ count: strategies.length, strategies }, 'sluice merge list-strategies: loaded');
|
|
250
|
+
process.exit(0);
|
|
251
|
+
}
|
|
252
|
+
catch (err) {
|
|
253
|
+
logger.error({ err }, 'sluice merge list-strategies: failed');
|
|
254
|
+
process.exit(exitCodeFor(err));
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async function cmdMergeInfo(strategyId, program) {
|
|
258
|
+
const overrides = applyGlobals(program.opts());
|
|
259
|
+
try {
|
|
260
|
+
const cwd = process.cwd();
|
|
261
|
+
const ruleRegistry = new RuleRegistry();
|
|
262
|
+
const transformRegistry = new TransformRegistry();
|
|
263
|
+
const pluginDirs = resolvePluginDirs(cwd, overrides.pluginDirs ?? []);
|
|
264
|
+
for (const dir of pluginDirs) {
|
|
265
|
+
await loadPlugins(dir, ruleRegistry, transformRegistry, MergeStrategyRegistry);
|
|
266
|
+
}
|
|
267
|
+
const configPath = path.join(cwd, 'sluice.config.yaml');
|
|
268
|
+
await loadNpmPlugins(configPath, ruleRegistry, transformRegistry, MergeStrategyRegistry);
|
|
269
|
+
const strategy = MergeStrategyRegistry.get(strategyId);
|
|
270
|
+
logger.info({
|
|
271
|
+
strategy: strategy.id,
|
|
272
|
+
description: strategy.description ?? strategy.id,
|
|
273
|
+
}, 'sluice merge info: complete');
|
|
274
|
+
process.exit(0);
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
logger.error({ err, strategyId }, 'sluice merge info: failed');
|
|
278
|
+
process.exit(exitCodeFor(err));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
export function buildProgram() {
|
|
282
|
+
const program = new Command();
|
|
283
|
+
program
|
|
284
|
+
.name('sluice')
|
|
285
|
+
.description('Config-driven ETL toolkit for ERP data migrations')
|
|
286
|
+
.version('0.1.0')
|
|
287
|
+
.option('--log-level <level>', 'debug | info | warn | error')
|
|
288
|
+
.option('--env <file>', 'Path to .env file', './.env')
|
|
289
|
+
.option('--output <dir>', 'Override run.outputDir')
|
|
290
|
+
.option('--plugins <dir...>', 'Additional plugin directory/directories to load')
|
|
291
|
+
.option('--dry-run', 'Force run.dryRun = true')
|
|
292
|
+
.option('--silent', 'Suppress the progress bar on stdout (logs still go to stderr)');
|
|
293
|
+
program
|
|
294
|
+
.command('run <pipeline>')
|
|
295
|
+
.description('Execute a full pipeline run')
|
|
296
|
+
.option('--no-enrich', 'Skip the Phase 4a enrich phase even if enrich: is configured')
|
|
297
|
+
.action((yaml, cmdOpts) => {
|
|
298
|
+
void cmdRun(yaml, program, cmdOpts);
|
|
299
|
+
});
|
|
300
|
+
program
|
|
301
|
+
.command('validate <pipeline>')
|
|
302
|
+
.description('DQ + transform only; no load')
|
|
303
|
+
.action((yaml) => {
|
|
304
|
+
void cmdValidate(yaml, program);
|
|
305
|
+
});
|
|
306
|
+
program
|
|
307
|
+
.command('profile <pipeline>')
|
|
308
|
+
.description('Extract + column profiling; no DQ')
|
|
309
|
+
.action((yaml) => {
|
|
310
|
+
void cmdProfile(yaml, program);
|
|
311
|
+
});
|
|
312
|
+
program
|
|
313
|
+
.command('check <pipeline>')
|
|
314
|
+
.description('Validate config only; no execution')
|
|
315
|
+
.action((yaml) => {
|
|
316
|
+
void cmdCheck(yaml, program);
|
|
317
|
+
});
|
|
318
|
+
program
|
|
319
|
+
.command('plugins')
|
|
320
|
+
.description('List all loaded plugins (Tier 2 and Tier 3)')
|
|
321
|
+
.action(() => {
|
|
322
|
+
void cmdPlugins(program);
|
|
323
|
+
});
|
|
324
|
+
const mergeCmd = program
|
|
325
|
+
.command('merge')
|
|
326
|
+
.description('Merge strategy operations');
|
|
327
|
+
mergeCmd
|
|
328
|
+
.command('list-strategies')
|
|
329
|
+
.description('List all available merge strategies')
|
|
330
|
+
.action(() => {
|
|
331
|
+
void cmdMergeListStrategies(program);
|
|
332
|
+
});
|
|
333
|
+
mergeCmd
|
|
334
|
+
.command('info <strategy>')
|
|
335
|
+
.description('Show details about a specific merge strategy')
|
|
336
|
+
.action((strategyId) => {
|
|
337
|
+
void cmdMergeInfo(strategyId, program);
|
|
338
|
+
});
|
|
339
|
+
return program;
|
|
340
|
+
}
|
|
341
|
+
// Only parse when invoked as the entry point (not when imported from tests).
|
|
342
|
+
const invoked = process.argv[1] ?? '';
|
|
343
|
+
if (invoked.endsWith('cli.ts') ||
|
|
344
|
+
invoked.endsWith('cli.js') ||
|
|
345
|
+
invoked.endsWith('sluice') ||
|
|
346
|
+
invoked.endsWith('sluice.cmd')) {
|
|
347
|
+
buildProgram()
|
|
348
|
+
.parseAsync(process.argv)
|
|
349
|
+
.catch((err) => {
|
|
350
|
+
logger.error({ err }, 'sluice CLI: unexpected error');
|
|
351
|
+
process.exit(1);
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,uCAAuC;AAEvC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAI5C,qBAAa,YAAY;WACV,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;CAmCvD"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Elastic-2.0
|
|
2
|
+
// Copyright (c) 2026 Caracal Lynx Ltd.
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { readFile } from 'node:fs/promises';
|
|
5
|
+
import { load as yamlLoad } from 'js-yaml';
|
|
6
|
+
import { PipelineSchema, CompositeRuleLibrarySchema, CheckType } from './schema.js';
|
|
7
|
+
import { ConfigError } from '../utils/errors.js';
|
|
8
|
+
import { requireEnv } from '../utils/env.js';
|
|
9
|
+
export class ConfigLoader {
|
|
10
|
+
static async load(yamlPath) {
|
|
11
|
+
// 1. Read file
|
|
12
|
+
let raw;
|
|
13
|
+
try {
|
|
14
|
+
raw = await readFile(yamlPath, 'utf-8');
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
if (isEnoent(err)) {
|
|
18
|
+
throw new ConfigError(`Pipeline file not found: ${yamlPath}`, err);
|
|
19
|
+
}
|
|
20
|
+
throw err;
|
|
21
|
+
}
|
|
22
|
+
// 2. Interpolate ${ENV_VAR} tokens.
|
|
23
|
+
// Operates on the raw YAML text, so tokens anywhere — including inside
|
|
24
|
+
// comments or unrelated string values — are resolved. Missing vars throw
|
|
25
|
+
// ConfigError before the YAML is parsed. This is intentional: it keeps
|
|
26
|
+
// the resolver trivial and predictable for single-pass pipelines.
|
|
27
|
+
const interpolated = raw.replace(/\$\{([^}]+)\}/g, (_match, name) => requireEnv(name));
|
|
28
|
+
// 3. Parse YAML
|
|
29
|
+
let parsed;
|
|
30
|
+
try {
|
|
31
|
+
parsed = yamlLoad(interpolated);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
throw new ConfigError(`Invalid YAML in pipeline file: ${yamlPath}`, err);
|
|
35
|
+
}
|
|
36
|
+
// 4. Expand composite DQ rules (rulesFile → built-in checks)
|
|
37
|
+
parsed = await expandCompositeRules(parsed, yamlPath);
|
|
38
|
+
// 5. Validate with Zod schema (let ZodError propagate to the caller)
|
|
39
|
+
return PipelineSchema.parse(parsed);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* If the raw parsed pipeline object references `dq.rulesFile`, load the
|
|
44
|
+
* composite rule library, build a map of id → checks, then walk
|
|
45
|
+
* `dq.rules[].checks[]` replacing any composite check entries with their
|
|
46
|
+
* constituent built-in checks (applying a severity override if present).
|
|
47
|
+
*
|
|
48
|
+
* Mutates and returns `raw` so downstream code sees built-in check types only.
|
|
49
|
+
*/
|
|
50
|
+
async function expandCompositeRules(raw, pipelineYamlPath) {
|
|
51
|
+
const obj = raw;
|
|
52
|
+
const dq = obj['dq'];
|
|
53
|
+
if (!dq || !dq['rulesFile']) {
|
|
54
|
+
return raw;
|
|
55
|
+
}
|
|
56
|
+
const rulesFileRel = dq['rulesFile'];
|
|
57
|
+
const rulesFilePath = path.resolve(path.dirname(pipelineYamlPath), rulesFileRel);
|
|
58
|
+
// Load the composite rule library
|
|
59
|
+
let rulesFileContent;
|
|
60
|
+
try {
|
|
61
|
+
rulesFileContent = await readFile(rulesFilePath, 'utf-8');
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
if (isEnoent(err)) {
|
|
65
|
+
throw new ConfigError(`rulesFile not found: ${rulesFilePath}`, err);
|
|
66
|
+
}
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
69
|
+
let rawLibrary;
|
|
70
|
+
try {
|
|
71
|
+
rawLibrary = yamlLoad(rulesFileContent);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
throw new ConfigError(`Invalid YAML in rulesFile: ${rulesFilePath}`, err);
|
|
75
|
+
}
|
|
76
|
+
// Validate library schema (let ZodError propagate)
|
|
77
|
+
const library = CompositeRuleLibrarySchema.parse(rawLibrary);
|
|
78
|
+
// Reject duplicate ids explicitly — silently picking the last one would
|
|
79
|
+
// surprise anyone authoring a rules library.
|
|
80
|
+
const seen = new Set();
|
|
81
|
+
for (const r of library.rules) {
|
|
82
|
+
if (seen.has(r.id)) {
|
|
83
|
+
throw new ConfigError(`Duplicate composite rule id "${r.id}" in ${rulesFilePath}. ` +
|
|
84
|
+
`Each id in the rules library must be unique.`);
|
|
85
|
+
}
|
|
86
|
+
seen.add(r.id);
|
|
87
|
+
}
|
|
88
|
+
// Build composite map: id → checks[]
|
|
89
|
+
const compositeMap = new Map(library.rules.map(r => [r.id, r.checks]));
|
|
90
|
+
// Built-in check type names
|
|
91
|
+
const builtInTypes = new Set(CheckType.options);
|
|
92
|
+
// Expand checks in each dq rule
|
|
93
|
+
const rules = dq['rules'];
|
|
94
|
+
if (!Array.isArray(rules)) {
|
|
95
|
+
return raw;
|
|
96
|
+
}
|
|
97
|
+
// rulesFile has served its purpose — drop it so the post-expansion shape
|
|
98
|
+
// matches the engine's expectation that only built-in check types exist.
|
|
99
|
+
delete dq['rulesFile'];
|
|
100
|
+
dq['rules'] = rules.map((rule) => {
|
|
101
|
+
const r = rule;
|
|
102
|
+
const checks = r['checks'];
|
|
103
|
+
if (!Array.isArray(checks))
|
|
104
|
+
return r;
|
|
105
|
+
const expanded = [];
|
|
106
|
+
for (const check of checks) {
|
|
107
|
+
const c = check;
|
|
108
|
+
const checkType = c['type'];
|
|
109
|
+
if (builtInTypes.has(checkType)) {
|
|
110
|
+
// Built-in check — keep as-is
|
|
111
|
+
expanded.push(c);
|
|
112
|
+
}
|
|
113
|
+
else if (compositeMap.has(checkType)) {
|
|
114
|
+
// Composite rule — expand, applying severity override if present
|
|
115
|
+
const compositeChecks = compositeMap.get(checkType);
|
|
116
|
+
const severityOverride = c['severity'];
|
|
117
|
+
for (const cc of compositeChecks) {
|
|
118
|
+
expanded.push(severityOverride !== undefined
|
|
119
|
+
? { ...cc, severity: severityOverride }
|
|
120
|
+
: { ...cc });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
throw new ConfigError(`Unknown rule type "${checkType}" in field rule — not a built-in check and not found in rulesFile. ` +
|
|
125
|
+
`Available composite rules: [${[...compositeMap.keys()].join(', ')}]`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return { ...r, checks: expanded };
|
|
129
|
+
});
|
|
130
|
+
return raw;
|
|
131
|
+
}
|
|
132
|
+
function isEnoent(err) {
|
|
133
|
+
return err instanceof Error && err.code === 'ENOENT';
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
|