@pgpmjs/transform 0.21.0 → 0.22.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/esm/index.js +1 -1
- package/esm/module-source.js +29 -9
- package/esm/semantic-diff-driver.js +35 -0
- package/index.d.ts +2 -2
- package/index.js +2 -1
- package/module-source.js +28 -8
- package/package.json +8 -8
- package/semantic-diff-driver.d.ts +35 -0
- package/semantic-diff-driver.js +36 -0
package/esm/index.js
CHANGED
|
@@ -11,7 +11,7 @@ export { PartitionCycleError, partitionUnits, RESIDUAL_UNIT_PATH, } from './part
|
|
|
11
11
|
export { emitSqlProgram, parseSqlProgram } from './program';
|
|
12
12
|
export { classifyScript, isStubScript, regenerateScripts, } from './regen';
|
|
13
13
|
export { EXPORT_GRANULARITIES, isExportGranularity, restructureExportRows } from './restructure';
|
|
14
|
-
export { diffChangeSets, diffSchemas, } from './semantic-diff-driver';
|
|
14
|
+
export { coverChanges, diffChangeSets, diffSchemas, } from './semantic-diff-driver';
|
|
15
15
|
export { nameUnnamedConstraints, subObjectIdentityOf } from './sub-object';
|
|
16
16
|
export * from '@pgsql/transform';
|
|
17
17
|
export { loadModule } from 'plpgsql-parser';
|
package/esm/module-source.js
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Module ingestion for the dials pipeline: load an on-disk pgpm module into
|
|
3
|
-
* the flattened, classified change list the transform/partition drivers
|
|
4
|
-
* consume. `pgpm transform` uses this today; a future `pgpm import` (dumps)
|
|
5
|
-
* and `pgpm diff` are expected to reuse the same seam.
|
|
6
|
-
*/
|
|
7
|
-
import { parsePgpmHeader, parsePlanFile, readScript } from '@pgpmjs/ast';
|
|
1
|
+
import { parsePgpmHeader, parsePlanFile, readScript, resolveReference } from '@pgpmjs/ast';
|
|
8
2
|
import * as path from 'path';
|
|
9
3
|
const TX_LINE = /^\s*(BEGIN|COMMIT|ROLLBACK)\s*;\s*$/i;
|
|
10
4
|
/**
|
|
@@ -17,6 +11,31 @@ export const stripTransactionWrapper = (sql) => sql
|
|
|
17
11
|
.filter(line => !TX_LINE.test(line))
|
|
18
12
|
.join('\n')
|
|
19
13
|
.trim();
|
|
14
|
+
/**
|
|
15
|
+
* Resolve a plan dependency token to a concrete change name.
|
|
16
|
+
*
|
|
17
|
+
* Non-tag tokens (a bare change name, or a `pkg:change` cross-package name)
|
|
18
|
+
* pass through unchanged — they are already the identity the ledger and
|
|
19
|
+
* generated plans record. A tag token (`@tag`) is resolved to its change via
|
|
20
|
+
* the plan that defines it, so a dependency written against a tag is not
|
|
21
|
+
* re-emitted verbatim into a generated plan or a ledger row. Cross-package
|
|
22
|
+
* tags (`pkg:@tag`) cannot be resolved from a single module's plan and are
|
|
23
|
+
* left as-is with a warning; the resolver returns them unchanged. Anything
|
|
24
|
+
* that fails to resolve is kept verbatim (never dropped) with a warning.
|
|
25
|
+
*/
|
|
26
|
+
const resolveDependencyToken = (token, plan, warnings, changeName) => {
|
|
27
|
+
if (!token.includes('@'))
|
|
28
|
+
return token;
|
|
29
|
+
const resolved = resolveReference(token, plan, plan.package);
|
|
30
|
+
if (resolved.error || !resolved.change) {
|
|
31
|
+
warnings.push(`${changeName}: could not resolve dependency tag "${token}" (${resolved.error ?? 'no matching change'}); left as-is`);
|
|
32
|
+
return token;
|
|
33
|
+
}
|
|
34
|
+
if (resolved.change === token) {
|
|
35
|
+
warnings.push(`${changeName}: dependency tag "${token}" is cross-package; left unresolved (resolve it in workspace context)`);
|
|
36
|
+
}
|
|
37
|
+
return resolved.change;
|
|
38
|
+
};
|
|
20
39
|
/**
|
|
21
40
|
* Load a pgpm module from disk: parse pgpm.plan and read each change's
|
|
22
41
|
* deploy script, stripping pgpm headers and transaction wrappers so the
|
|
@@ -30,9 +49,10 @@ export const loadModuleSource = (moduleDir) => {
|
|
|
30
49
|
const reasons = planResult.errors.map(e => e.message).join(', ');
|
|
31
50
|
throw new Error(`Failed to parse pgpm.plan in ${modulePath}: ${reasons}`);
|
|
32
51
|
}
|
|
52
|
+
const plan = planResult.data;
|
|
33
53
|
const warnings = [];
|
|
34
54
|
const changes = [];
|
|
35
|
-
for (const change of
|
|
55
|
+
for (const change of plan.changes) {
|
|
36
56
|
const raw = readScript(modulePath, 'deploy', change.name);
|
|
37
57
|
if (!raw) {
|
|
38
58
|
warnings.push(`${change.name}: no deploy script found, skipping`);
|
|
@@ -41,7 +61,7 @@ export const loadModuleSource = (moduleDir) => {
|
|
|
41
61
|
const { body } = parsePgpmHeader(raw);
|
|
42
62
|
changes.push({
|
|
43
63
|
name: change.name,
|
|
44
|
-
dependencies: change.dependencies ?? [],
|
|
64
|
+
dependencies: (change.dependencies ?? []).map(dep => resolveDependencyToken(dep, plan, warnings, change.name)),
|
|
45
65
|
deploy: stripTransactionWrapper(body)
|
|
46
66
|
});
|
|
47
67
|
}
|
|
@@ -502,3 +502,38 @@ export function diffChangeSets(from, to, options = {}) {
|
|
|
502
502
|
const flatten = (changes) => changes.map(c => c.deploy.trim()).filter(Boolean).join('\n\n');
|
|
503
503
|
return diffSchemas(flatten(from), flatten(to), options);
|
|
504
504
|
}
|
|
505
|
+
/**
|
|
506
|
+
* Cover each `to`-side change against a semantic diff's per-object delta:
|
|
507
|
+
* which of the objects the change touches are already present and identical
|
|
508
|
+
* on the `from` side. A `satisfied` change deploys nothing new — its ledger
|
|
509
|
+
* entry can be backfilled instead of executing it; an `unsatisfied` change is
|
|
510
|
+
* the genuine delta. Identity keying is shared with the diff itself, so
|
|
511
|
+
* regrouped/renamed/reordered authorship of the same objects covers the same.
|
|
512
|
+
*
|
|
513
|
+
* `diff` must come from diffing the same `from` side against these changes
|
|
514
|
+
* (`diffChangeSets(fromChanges, toChanges)`).
|
|
515
|
+
*/
|
|
516
|
+
export function coverChanges(changes, diff, options = {}) {
|
|
517
|
+
const style = options.style ?? 'directory';
|
|
518
|
+
const deltaByKey = new Map();
|
|
519
|
+
for (const obj of diff.objects) {
|
|
520
|
+
deltaByKey.set(identityKey(obj.identity), obj.delta);
|
|
521
|
+
}
|
|
522
|
+
return changes.map(change => {
|
|
523
|
+
const sideWarnings = [];
|
|
524
|
+
const side = readSide(change.deploy, sideWarnings, change.name);
|
|
525
|
+
const objects = side.order.map(key => {
|
|
526
|
+
const unit = side.units.get(key);
|
|
527
|
+
return {
|
|
528
|
+
path: pathFor(unit.identity, { style }),
|
|
529
|
+
delta: deltaByKey.get(key) ?? 'unchanged'
|
|
530
|
+
};
|
|
531
|
+
});
|
|
532
|
+
const touched = objects.filter(o => o.delta !== 'unchanged').length;
|
|
533
|
+
const status = objects.length === 0 ? 'inert'
|
|
534
|
+
: touched === 0 ? 'satisfied'
|
|
535
|
+
: touched === objects.length ? 'unsatisfied'
|
|
536
|
+
: 'partial';
|
|
537
|
+
return { name: change.name, status, objects };
|
|
538
|
+
});
|
|
539
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -24,8 +24,8 @@ export type { GeneratedScript, RegeneratedScripts, } from './regen';
|
|
|
24
24
|
export { classifyScript, isStubScript, regenerateScripts, } from './regen';
|
|
25
25
|
export type { ExportGranularity, RestructureExportRowsOptions, RestructureExportRowsResult } from './restructure';
|
|
26
26
|
export { EXPORT_GRANULARITIES, isExportGranularity, restructureExportRows } from './restructure';
|
|
27
|
-
export type { DiffInputChange, ObjectDelta, SemanticDeltaChange, SemanticDiffOptions, SemanticDiffResult, SemanticObjectDiff, } from './semantic-diff-driver';
|
|
28
|
-
export { diffChangeSets, diffSchemas, } from './semantic-diff-driver';
|
|
27
|
+
export type { ChangeCoverage, ChangeObjectCoverage, ChangeObjectDelta, ChangeSatisfaction, DiffInputChange, ObjectDelta, SemanticDeltaChange, SemanticDiffOptions, SemanticDiffResult, SemanticObjectDiff, } from './semantic-diff-driver';
|
|
28
|
+
export { coverChanges, diffChangeSets, diffSchemas, } from './semantic-diff-driver';
|
|
29
29
|
export { nameUnnamedConstraints, subObjectIdentityOf } from './sub-object';
|
|
30
30
|
export * from '@pgsql/transform';
|
|
31
31
|
export { loadModule } from 'plpgsql-parser';
|
package/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.loadModule = exports.subObjectIdentityOf = exports.nameUnnamedConstraints = exports.diffSchemas = exports.diffChangeSets = exports.restructureExportRows = exports.isExportGranularity = exports.EXPORT_GRANULARITIES = exports.regenerateScripts = exports.isStubScript = exports.classifyScript = exports.parseSqlProgram = exports.emitSqlProgram = exports.RESIDUAL_UNIT_PATH = exports.partitionUnits = exports.PartitionCycleError = exports.partitionExportRows = exports.parsePartitionConfig = exports.stripTransactionWrapper = exports.loadModuleSource = exports.writeModule = exports.writeControlFile = exports.checkOverwrite = exports.appendModule = exports.restructureChanges = exports.isChangeGranularity = exports.defaultChangeName = exports.CHANGE_GRANULARITIES = exports.resolveFixtureClosure = exports.firstColumnRef = exports.defaultConstraintName = exports.TIER_PROFILE = exports.categorizeChange = exports.buildCategoryOf = exports.withoutColumnOrder = exports.snapshotCatalog = exports.diffCatalogSnapshots = exports.makeSchemaTranspiler = exports.makeNamespaceValidator = exports.buildSchemaRouter = exports.buildExtensionRouter = void 0;
|
|
17
|
+
exports.loadModule = exports.subObjectIdentityOf = exports.nameUnnamedConstraints = exports.diffSchemas = exports.diffChangeSets = exports.coverChanges = exports.restructureExportRows = exports.isExportGranularity = exports.EXPORT_GRANULARITIES = exports.regenerateScripts = exports.isStubScript = exports.classifyScript = exports.parseSqlProgram = exports.emitSqlProgram = exports.RESIDUAL_UNIT_PATH = exports.partitionUnits = exports.PartitionCycleError = exports.partitionExportRows = exports.parsePartitionConfig = exports.stripTransactionWrapper = exports.loadModuleSource = exports.writeModule = exports.writeControlFile = exports.checkOverwrite = exports.appendModule = exports.restructureChanges = exports.isChangeGranularity = exports.defaultChangeName = exports.CHANGE_GRANULARITIES = exports.resolveFixtureClosure = exports.firstColumnRef = exports.defaultConstraintName = exports.TIER_PROFILE = exports.categorizeChange = exports.buildCategoryOf = exports.withoutColumnOrder = exports.snapshotCatalog = exports.diffCatalogSnapshots = exports.makeSchemaTranspiler = exports.makeNamespaceValidator = exports.buildSchemaRouter = exports.buildExtensionRouter = void 0;
|
|
18
18
|
var bundle_driver_1 = require("./bundle-driver");
|
|
19
19
|
Object.defineProperty(exports, "buildExtensionRouter", { enumerable: true, get: function () { return bundle_driver_1.buildExtensionRouter; } });
|
|
20
20
|
Object.defineProperty(exports, "buildSchemaRouter", { enumerable: true, get: function () { return bundle_driver_1.buildSchemaRouter; } });
|
|
@@ -65,6 +65,7 @@ Object.defineProperty(exports, "EXPORT_GRANULARITIES", { enumerable: true, get:
|
|
|
65
65
|
Object.defineProperty(exports, "isExportGranularity", { enumerable: true, get: function () { return restructure_1.isExportGranularity; } });
|
|
66
66
|
Object.defineProperty(exports, "restructureExportRows", { enumerable: true, get: function () { return restructure_1.restructureExportRows; } });
|
|
67
67
|
var semantic_diff_driver_1 = require("./semantic-diff-driver");
|
|
68
|
+
Object.defineProperty(exports, "coverChanges", { enumerable: true, get: function () { return semantic_diff_driver_1.coverChanges; } });
|
|
68
69
|
Object.defineProperty(exports, "diffChangeSets", { enumerable: true, get: function () { return semantic_diff_driver_1.diffChangeSets; } });
|
|
69
70
|
Object.defineProperty(exports, "diffSchemas", { enumerable: true, get: function () { return semantic_diff_driver_1.diffSchemas; } });
|
|
70
71
|
var sub_object_1 = require("./sub-object");
|
package/module-source.js
CHANGED
|
@@ -34,12 +34,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.loadModuleSource = exports.stripTransactionWrapper = void 0;
|
|
37
|
-
/**
|
|
38
|
-
* Module ingestion for the dials pipeline: load an on-disk pgpm module into
|
|
39
|
-
* the flattened, classified change list the transform/partition drivers
|
|
40
|
-
* consume. `pgpm transform` uses this today; a future `pgpm import` (dumps)
|
|
41
|
-
* and `pgpm diff` are expected to reuse the same seam.
|
|
42
|
-
*/
|
|
43
37
|
const ast_1 = require("@pgpmjs/ast");
|
|
44
38
|
const path = __importStar(require("path"));
|
|
45
39
|
const TX_LINE = /^\s*(BEGIN|COMMIT|ROLLBACK)\s*;\s*$/i;
|
|
@@ -54,6 +48,31 @@ const stripTransactionWrapper = (sql) => sql
|
|
|
54
48
|
.join('\n')
|
|
55
49
|
.trim();
|
|
56
50
|
exports.stripTransactionWrapper = stripTransactionWrapper;
|
|
51
|
+
/**
|
|
52
|
+
* Resolve a plan dependency token to a concrete change name.
|
|
53
|
+
*
|
|
54
|
+
* Non-tag tokens (a bare change name, or a `pkg:change` cross-package name)
|
|
55
|
+
* pass through unchanged — they are already the identity the ledger and
|
|
56
|
+
* generated plans record. A tag token (`@tag`) is resolved to its change via
|
|
57
|
+
* the plan that defines it, so a dependency written against a tag is not
|
|
58
|
+
* re-emitted verbatim into a generated plan or a ledger row. Cross-package
|
|
59
|
+
* tags (`pkg:@tag`) cannot be resolved from a single module's plan and are
|
|
60
|
+
* left as-is with a warning; the resolver returns them unchanged. Anything
|
|
61
|
+
* that fails to resolve is kept verbatim (never dropped) with a warning.
|
|
62
|
+
*/
|
|
63
|
+
const resolveDependencyToken = (token, plan, warnings, changeName) => {
|
|
64
|
+
if (!token.includes('@'))
|
|
65
|
+
return token;
|
|
66
|
+
const resolved = (0, ast_1.resolveReference)(token, plan, plan.package);
|
|
67
|
+
if (resolved.error || !resolved.change) {
|
|
68
|
+
warnings.push(`${changeName}: could not resolve dependency tag "${token}" (${resolved.error ?? 'no matching change'}); left as-is`);
|
|
69
|
+
return token;
|
|
70
|
+
}
|
|
71
|
+
if (resolved.change === token) {
|
|
72
|
+
warnings.push(`${changeName}: dependency tag "${token}" is cross-package; left unresolved (resolve it in workspace context)`);
|
|
73
|
+
}
|
|
74
|
+
return resolved.change;
|
|
75
|
+
};
|
|
57
76
|
/**
|
|
58
77
|
* Load a pgpm module from disk: parse pgpm.plan and read each change's
|
|
59
78
|
* deploy script, stripping pgpm headers and transaction wrappers so the
|
|
@@ -67,9 +86,10 @@ const loadModuleSource = (moduleDir) => {
|
|
|
67
86
|
const reasons = planResult.errors.map(e => e.message).join(', ');
|
|
68
87
|
throw new Error(`Failed to parse pgpm.plan in ${modulePath}: ${reasons}`);
|
|
69
88
|
}
|
|
89
|
+
const plan = planResult.data;
|
|
70
90
|
const warnings = [];
|
|
71
91
|
const changes = [];
|
|
72
|
-
for (const change of
|
|
92
|
+
for (const change of plan.changes) {
|
|
73
93
|
const raw = (0, ast_1.readScript)(modulePath, 'deploy', change.name);
|
|
74
94
|
if (!raw) {
|
|
75
95
|
warnings.push(`${change.name}: no deploy script found, skipping`);
|
|
@@ -78,7 +98,7 @@ const loadModuleSource = (moduleDir) => {
|
|
|
78
98
|
const { body } = (0, ast_1.parsePgpmHeader)(raw);
|
|
79
99
|
changes.push({
|
|
80
100
|
name: change.name,
|
|
81
|
-
dependencies: change.dependencies ?? [],
|
|
101
|
+
dependencies: (change.dependencies ?? []).map(dep => resolveDependencyToken(dep, plan, warnings, change.name)),
|
|
82
102
|
deploy: (0, exports.stripTransactionWrapper)(body)
|
|
83
103
|
});
|
|
84
104
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pgpmjs/transform",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"author": "Constructive <developers@constructive.io>",
|
|
5
5
|
"description": "Change-aware SQL transformation for PGPM — superset of @pgsql/transform plus change categorization, fixture closure, and bundle transpile/apply drivers",
|
|
6
6
|
"main": "index.js",
|
|
@@ -39,16 +39,16 @@
|
|
|
39
39
|
"plpgsql"
|
|
40
40
|
],
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@pgpmjs/bundle": "^0.14.
|
|
42
|
+
"@pgpmjs/bundle": "^0.14.1",
|
|
43
43
|
"makage": "^0.3.0"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@pgpmjs/ast": "^0.11.
|
|
46
|
+
"@pgpmjs/ast": "^0.11.1",
|
|
47
47
|
"@pgpmjs/naming-spec": "^0.3.0",
|
|
48
|
-
"@pgsql/scripts": "^18.3.
|
|
49
|
-
"@pgsql/semantics": "^18.1.
|
|
50
|
-
"@pgsql/transform": "^18.15.
|
|
51
|
-
"plpgsql-parser": "^18.5.
|
|
48
|
+
"@pgsql/scripts": "^18.3.4",
|
|
49
|
+
"@pgsql/semantics": "^18.1.2",
|
|
50
|
+
"@pgsql/transform": "^18.15.2",
|
|
51
|
+
"plpgsql-parser": "^18.5.3"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "6da0705f8aa49d62dc2defb8b135b71674611483"
|
|
54
54
|
}
|
|
@@ -90,3 +90,38 @@ export interface DiffInputChange {
|
|
|
90
90
|
* schema yields an identical diff.
|
|
91
91
|
*/
|
|
92
92
|
export declare function diffChangeSets(from: DiffInputChange[], to: DiffInputChange[], options?: SemanticDiffOptions): SemanticDiffResult;
|
|
93
|
+
/** How one object a change touches relates to the diff's delta. */
|
|
94
|
+
export type ChangeObjectDelta = ObjectDelta | 'unchanged';
|
|
95
|
+
/**
|
|
96
|
+
* Whether a `to`-side change is already satisfied by the `from` side:
|
|
97
|
+
* - `satisfied`: every object it touches is unchanged in the diff
|
|
98
|
+
* - `unsatisfied`: every object it touches is added/modified in the diff
|
|
99
|
+
* - `partial`: a mix of unchanged and delta objects
|
|
100
|
+
* - `inert`: no identifiable objects (seed data, grants-only, dynamic SQL)
|
|
101
|
+
*/
|
|
102
|
+
export type ChangeSatisfaction = 'satisfied' | 'unsatisfied' | 'partial' | 'inert';
|
|
103
|
+
export interface ChangeObjectCoverage {
|
|
104
|
+
/** Canonical naming-spec path for the object. */
|
|
105
|
+
path: string;
|
|
106
|
+
delta: ChangeObjectDelta;
|
|
107
|
+
}
|
|
108
|
+
export interface ChangeCoverage {
|
|
109
|
+
/** The input change's name (as given, e.g. `pkg:change`). */
|
|
110
|
+
name: string;
|
|
111
|
+
status: ChangeSatisfaction;
|
|
112
|
+
objects: ChangeObjectCoverage[];
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Cover each `to`-side change against a semantic diff's per-object delta:
|
|
116
|
+
* which of the objects the change touches are already present and identical
|
|
117
|
+
* on the `from` side. A `satisfied` change deploys nothing new — its ledger
|
|
118
|
+
* entry can be backfilled instead of executing it; an `unsatisfied` change is
|
|
119
|
+
* the genuine delta. Identity keying is shared with the diff itself, so
|
|
120
|
+
* regrouped/renamed/reordered authorship of the same objects covers the same.
|
|
121
|
+
*
|
|
122
|
+
* `diff` must come from diffing the same `from` side against these changes
|
|
123
|
+
* (`diffChangeSets(fromChanges, toChanges)`).
|
|
124
|
+
*/
|
|
125
|
+
export declare function coverChanges(changes: DiffInputChange[], diff: SemanticDiffResult, options?: {
|
|
126
|
+
style?: PathStyle;
|
|
127
|
+
}): ChangeCoverage[];
|
package/semantic-diff-driver.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.diffSchemas = diffSchemas;
|
|
4
4
|
exports.diffChangeSets = diffChangeSets;
|
|
5
|
+
exports.coverChanges = coverChanges;
|
|
5
6
|
/**
|
|
6
7
|
* Semantic diff driver: identity-keyed schema delta between two deploy
|
|
7
8
|
* surfaces.
|
|
@@ -506,3 +507,38 @@ function diffChangeSets(from, to, options = {}) {
|
|
|
506
507
|
const flatten = (changes) => changes.map(c => c.deploy.trim()).filter(Boolean).join('\n\n');
|
|
507
508
|
return diffSchemas(flatten(from), flatten(to), options);
|
|
508
509
|
}
|
|
510
|
+
/**
|
|
511
|
+
* Cover each `to`-side change against a semantic diff's per-object delta:
|
|
512
|
+
* which of the objects the change touches are already present and identical
|
|
513
|
+
* on the `from` side. A `satisfied` change deploys nothing new — its ledger
|
|
514
|
+
* entry can be backfilled instead of executing it; an `unsatisfied` change is
|
|
515
|
+
* the genuine delta. Identity keying is shared with the diff itself, so
|
|
516
|
+
* regrouped/renamed/reordered authorship of the same objects covers the same.
|
|
517
|
+
*
|
|
518
|
+
* `diff` must come from diffing the same `from` side against these changes
|
|
519
|
+
* (`diffChangeSets(fromChanges, toChanges)`).
|
|
520
|
+
*/
|
|
521
|
+
function coverChanges(changes, diff, options = {}) {
|
|
522
|
+
const style = options.style ?? 'directory';
|
|
523
|
+
const deltaByKey = new Map();
|
|
524
|
+
for (const obj of diff.objects) {
|
|
525
|
+
deltaByKey.set(identityKey(obj.identity), obj.delta);
|
|
526
|
+
}
|
|
527
|
+
return changes.map(change => {
|
|
528
|
+
const sideWarnings = [];
|
|
529
|
+
const side = readSide(change.deploy, sideWarnings, change.name);
|
|
530
|
+
const objects = side.order.map(key => {
|
|
531
|
+
const unit = side.units.get(key);
|
|
532
|
+
return {
|
|
533
|
+
path: (0, naming_spec_1.pathFor)(unit.identity, { style }),
|
|
534
|
+
delta: deltaByKey.get(key) ?? 'unchanged'
|
|
535
|
+
};
|
|
536
|
+
});
|
|
537
|
+
const touched = objects.filter(o => o.delta !== 'unchanged').length;
|
|
538
|
+
const status = objects.length === 0 ? 'inert'
|
|
539
|
+
: touched === 0 ? 'satisfied'
|
|
540
|
+
: touched === objects.length ? 'unsatisfied'
|
|
541
|
+
: 'partial';
|
|
542
|
+
return { name: change.name, status, objects };
|
|
543
|
+
});
|
|
544
|
+
}
|