helm-env-delta 1.8.0 → 1.8.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.
- package/README.md +1 -1
- package/dist/fileUpdater.js +105 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -780,7 +780,7 @@ git push origin main
|
|
|
780
780
|
|
|
781
781
|
✅ **Flexibility** - Per-file patterns. Config inheritance. Regex transforms.
|
|
782
782
|
|
|
783
|
-
✅ **Reliability** -
|
|
783
|
+
✅ **Reliability** - 990+ tests, 84% coverage. Battle-tested.
|
|
784
784
|
|
|
785
785
|
---
|
|
786
786
|
|
package/dist/fileUpdater.js
CHANGED
|
@@ -10,6 +10,7 @@ const yaml_1 = __importDefault(require("yaml"));
|
|
|
10
10
|
const consoleFormatter_1 = require("./consoleFormatter");
|
|
11
11
|
const errors_1 = require("./utils/errors");
|
|
12
12
|
const fileType_1 = require("./utils/fileType");
|
|
13
|
+
const jsonPath_1 = require("./utils/jsonPath");
|
|
13
14
|
const transformer_1 = require("./utils/transformer");
|
|
14
15
|
const yamlFormatter_1 = require("./yamlFormatter");
|
|
15
16
|
const FileUpdaterErrorClass = (0, errors_1.createErrorClass)('File Updater Error', {
|
|
@@ -61,15 +62,112 @@ const ensureParentDirectory = async (filePath) => {
|
|
|
61
62
|
});
|
|
62
63
|
}
|
|
63
64
|
};
|
|
64
|
-
const
|
|
65
|
+
const getApplicableArrayFilters = (currentPath, skipPaths) => {
|
|
66
|
+
const filters = [];
|
|
67
|
+
for (const skipPath of skipPaths) {
|
|
68
|
+
const segments = (0, jsonPath_1.parseJsonPath)(skipPath);
|
|
69
|
+
if (segments.length <= currentPath.length)
|
|
70
|
+
continue;
|
|
71
|
+
let isPrefix = true;
|
|
72
|
+
for (let index = 0; index < currentPath.length; index++)
|
|
73
|
+
if (segments[index] !== currentPath[index]) {
|
|
74
|
+
isPrefix = false;
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
if (!isPrefix)
|
|
78
|
+
continue;
|
|
79
|
+
const nextSegment = segments[currentPath.length];
|
|
80
|
+
if (!nextSegment || !(0, jsonPath_1.isFilterSegment)(nextSegment))
|
|
81
|
+
continue;
|
|
82
|
+
const filter = (0, jsonPath_1.parseFilterSegment)(nextSegment);
|
|
83
|
+
if (!filter)
|
|
84
|
+
continue;
|
|
85
|
+
const remainingPath = segments.slice(currentPath.length + 1);
|
|
86
|
+
filters.push({ filter, remainingPath });
|
|
87
|
+
}
|
|
88
|
+
return filters;
|
|
89
|
+
};
|
|
90
|
+
const itemMatchesAnyFilter = (item, applicableFilters) => {
|
|
91
|
+
if (!item || typeof item !== 'object')
|
|
92
|
+
return { matches: false };
|
|
93
|
+
const itemObject = item;
|
|
94
|
+
for (const applicableFilter of applicableFilters) {
|
|
95
|
+
const itemValue = itemObject[applicableFilter.filter.property];
|
|
96
|
+
if (itemValue !== undefined && (0, jsonPath_1.matchesFilter)(itemValue, applicableFilter.filter))
|
|
97
|
+
return { matches: true, matchedFilter: applicableFilter };
|
|
98
|
+
}
|
|
99
|
+
return { matches: false };
|
|
100
|
+
};
|
|
101
|
+
const findMatchingTargetItem = (sourceItem, fullTargetArray, applicableFilters) => {
|
|
102
|
+
if (!sourceItem || typeof sourceItem !== 'object')
|
|
103
|
+
return undefined;
|
|
104
|
+
const sourceObject = sourceItem;
|
|
105
|
+
for (const targetItem of fullTargetArray) {
|
|
106
|
+
if (!targetItem || typeof targetItem !== 'object')
|
|
107
|
+
continue;
|
|
108
|
+
const targetObject = targetItem;
|
|
109
|
+
for (const { filter } of applicableFilters)
|
|
110
|
+
if (sourceObject[filter.property] === targetObject[filter.property])
|
|
111
|
+
return targetItem;
|
|
112
|
+
}
|
|
113
|
+
return undefined;
|
|
114
|
+
};
|
|
115
|
+
const shouldPreserveItem = (item, applicableFilters, existingResult) => {
|
|
116
|
+
if (!item || typeof item !== 'object')
|
|
117
|
+
return false;
|
|
118
|
+
const itemObject = item;
|
|
119
|
+
const { matches } = itemMatchesAnyFilter(item, applicableFilters);
|
|
120
|
+
if (!matches)
|
|
121
|
+
return false;
|
|
122
|
+
for (const existingItem of existingResult) {
|
|
123
|
+
if (!existingItem || typeof existingItem !== 'object')
|
|
124
|
+
continue;
|
|
125
|
+
const existingObject = existingItem;
|
|
126
|
+
let isDuplicate = true;
|
|
127
|
+
for (const { filter } of applicableFilters)
|
|
128
|
+
if (existingObject[filter.property] !== itemObject[filter.property]) {
|
|
129
|
+
isDuplicate = false;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
if (isDuplicate)
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
};
|
|
137
|
+
const deepMerge = (fullTarget, filteredSource, filteredTarget, currentPath = [], skipPaths = []) => {
|
|
65
138
|
if (filteredSource === null || filteredSource === undefined)
|
|
66
139
|
return fullTarget;
|
|
67
140
|
if (fullTarget === null || fullTarget === undefined)
|
|
68
141
|
return filteredSource;
|
|
69
142
|
if (typeof fullTarget !== typeof filteredSource)
|
|
70
143
|
return filteredSource;
|
|
71
|
-
if (Array.isArray(filteredSource))
|
|
72
|
-
|
|
144
|
+
if (Array.isArray(filteredSource)) {
|
|
145
|
+
const fullTargetArray = Array.isArray(fullTarget) ? fullTarget : [];
|
|
146
|
+
const filteredTargetArray = Array.isArray(filteredTarget) ? filteredTarget : [];
|
|
147
|
+
const applicableFilters = getApplicableArrayFilters(currentPath, skipPaths);
|
|
148
|
+
if (applicableFilters.length === 0)
|
|
149
|
+
return filteredSource;
|
|
150
|
+
const hasNestedFilters = applicableFilters.some((f) => f.remainingPath.length > 0);
|
|
151
|
+
const result = [];
|
|
152
|
+
for (const sourceItem of filteredSource) {
|
|
153
|
+
if (hasNestedFilters && sourceItem && typeof sourceItem === 'object') {
|
|
154
|
+
const { matches, matchedFilter } = itemMatchesAnyFilter(sourceItem, applicableFilters);
|
|
155
|
+
if (matches && matchedFilter && matchedFilter.remainingPath.length > 0) {
|
|
156
|
+
const matchingTargetItem = findMatchingTargetItem(sourceItem, fullTargetArray, applicableFilters);
|
|
157
|
+
const matchingFilteredTargetItem = findMatchingTargetItem(sourceItem, filteredTargetArray, applicableFilters);
|
|
158
|
+
if (matchingTargetItem) {
|
|
159
|
+
result.push(deepMerge(matchingTargetItem, sourceItem, matchingFilteredTargetItem, currentPath, skipPaths));
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
result.push(sourceItem);
|
|
165
|
+
}
|
|
166
|
+
for (const item of fullTargetArray)
|
|
167
|
+
if (shouldPreserveItem(item, applicableFilters, result))
|
|
168
|
+
result.push(item);
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
73
171
|
if (typeof filteredSource === 'object' && typeof fullTarget === 'object') {
|
|
74
172
|
const sourceObject = filteredSource;
|
|
75
173
|
const fullTargetObject = fullTarget;
|
|
@@ -80,12 +178,12 @@ const deepMerge = (fullTarget, filteredSource, filteredTarget) => {
|
|
|
80
178
|
result[key] = value;
|
|
81
179
|
for (const [key, value] of Object.entries(sourceObject))
|
|
82
180
|
if (key in fullTargetObject)
|
|
83
|
-
result[key] = deepMerge(fullTargetObject[key], value, filteredTargetObject[key]);
|
|
181
|
+
result[key] = deepMerge(fullTargetObject[key], value, filteredTargetObject[key], [...currentPath, key], skipPaths);
|
|
84
182
|
return result;
|
|
85
183
|
}
|
|
86
184
|
return filteredSource;
|
|
87
185
|
};
|
|
88
|
-
const mergeYamlContent = (destinationContent, processedSourceContent, filteredDestinationContent, filePath) => {
|
|
186
|
+
const mergeYamlContent = (destinationContent, processedSourceContent, filteredDestinationContent, filePath, skipPaths = []) => {
|
|
89
187
|
let destinationParsed;
|
|
90
188
|
try {
|
|
91
189
|
destinationParsed = yaml_1.default.parse(destinationContent);
|
|
@@ -104,7 +202,7 @@ const mergeYamlContent = (destinationContent, processedSourceContent, filteredDe
|
|
|
104
202
|
}
|
|
105
203
|
let merged;
|
|
106
204
|
try {
|
|
107
|
-
merged = deepMerge(destinationParsed, processedSourceContent, filteredDestinationContent);
|
|
205
|
+
merged = deepMerge(destinationParsed, processedSourceContent, filteredDestinationContent, [], skipPaths);
|
|
108
206
|
}
|
|
109
207
|
catch (error) {
|
|
110
208
|
throw new FileUpdaterError('Failed to merge YAML content', {
|
|
@@ -168,7 +266,7 @@ const updateFile = async (options) => {
|
|
|
168
266
|
return;
|
|
169
267
|
}
|
|
170
268
|
let contentToWrite = (0, fileType_1.isYamlFile)(changedFile.path)
|
|
171
|
-
? mergeYamlContent(changedFile.destinationContent, changedFile.rawParsedSource, changedFile.rawParsedDest, changedFile.path)
|
|
269
|
+
? mergeYamlContent(changedFile.destinationContent, changedFile.rawParsedSource, changedFile.rawParsedDest, changedFile.path, changedFile.skipPaths)
|
|
172
270
|
: changedFile.sourceContent;
|
|
173
271
|
if ((0, fileType_1.isYamlFile)(changedFile.path)) {
|
|
174
272
|
const effectiveOutputFormat = skipFormat ? undefined : config.outputFormat;
|