helm-env-delta 1.11.1 → 1.13.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/README.md +18 -5
- package/dist/configFile.d.ts +16 -0
- package/dist/configFile.js +11 -0
- package/dist/configLoader.d.ts +19 -0
- package/dist/configLoader.js +28 -1
- package/dist/configMerger.js +4 -0
- package/dist/htmlReporter.d.ts +2 -1
- package/dist/htmlReporter.js +12 -2
- package/dist/index.js +3 -1
- package/dist/reporters/htmlStyles.d.ts +1 -1
- package/dist/reporters/htmlStyles.js +85 -0
- package/dist/reporters/htmlTemplate.d.ts +12 -1
- package/dist/reporters/htmlTemplate.js +47 -4
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.js +4 -2
- package/dist/utils/versionChecker.d.ts +7 -0
- package/dist/utils/versionChecker.js +6 -4
- package/dist/yamlFormatter.js +47 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -52,11 +52,11 @@ HelmEnvDelta (`hed`) automates environment synchronization for GitOps workflows
|
|
|
52
52
|
|
|
53
53
|
🛡️ **Safety Rules** - Block major version upgrades, scaling violations, and forbidden patterns. Load validation rules from external files. Scan globally or target specific fields.
|
|
54
54
|
|
|
55
|
-
🎨 **Format Enforcement** - Standardize YAML across all environments: key ordering, indentation, quoting, array sorting.
|
|
55
|
+
🎨 **Format Enforcement** - Standardize YAML across all environments: key ordering, alphabetical key sorting, indentation, quoting, array sorting.
|
|
56
56
|
|
|
57
57
|
📦 **Config Inheritance** - Reuse base configurations with environment-specific overrides.
|
|
58
58
|
|
|
59
|
-
📊 **Multiple Reports** - Console, HTML (visual, self-contained), and JSON (CI/CD) output formats. HTML reports include collapsible diff stats dashboard, synchronized side-by-side scrolling, copy diff buttons, file search, and collapse/expand controls. Empty categories are automatically hidden.
|
|
59
|
+
📊 **Multiple Reports** - Console, HTML (visual, self-contained), and JSON (CI/CD) output formats. HTML reports include collapsible diff stats dashboard, stop rule violations table (dry-run only), synchronized side-by-side scrolling, copy diff buttons, file search, and collapse/expand controls. Empty categories are automatically hidden.
|
|
60
60
|
|
|
61
61
|
🔍 **Discovery Tools** - Preview files (`-l`), inspect config (`--show-config`), filter by filename/content (`-f`), filter by change type (`-m`), validate with comprehensive warnings including unused pattern detection.
|
|
62
62
|
|
|
@@ -119,7 +119,7 @@ hed -c config.yaml
|
|
|
119
119
|
hed -c config.yaml -H
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
Self-contained HTML report — works offline, no CDN required. Includes collapsible diff stats dashboard, synchronized side-by-side scrolling, copy buttons, sidebar search, and collapse/expand controls. Empty categories are automatically hidden.
|
|
122
|
+
Self-contained HTML report — works offline, no CDN required. Includes collapsible diff stats dashboard, stop rule violations table (shown in dry-run mode), synchronized side-by-side scrolling, copy buttons, sidebar search, and collapse/expand controls. Empty categories are automatically hidden.
|
|
123
123
|
|
|
124
124
|
### 5️⃣ Get Smart Suggestions (Optional)
|
|
125
125
|
|
|
@@ -208,6 +208,9 @@ outputFormat:
|
|
|
208
208
|
- 'kind'
|
|
209
209
|
- 'metadata'
|
|
210
210
|
- 'spec'
|
|
211
|
+
keySort:
|
|
212
|
+
'**/*.yaml':
|
|
213
|
+
- path: 'spec.template.metadata.labels'
|
|
211
214
|
arraySort:
|
|
212
215
|
'**/*.yaml':
|
|
213
216
|
- path: 'env'
|
|
@@ -410,10 +413,13 @@ exclude: # Optional: Exclude patterns
|
|
|
410
413
|
|
|
411
414
|
prune: false # Optional: Delete dest files not in source
|
|
412
415
|
confirmationDelay: 3000 # Optional: Delay in ms before sync (default: 3000, 0 to disable)
|
|
416
|
+
requiredVersion: '1.10.0' # Optional: Minimum tool version required to process this config
|
|
413
417
|
```
|
|
414
418
|
|
|
415
419
|
**Note:** Source and destination paths cannot resolve to the same folder.
|
|
416
420
|
|
|
421
|
+
**`requiredVersion`:** When set, the CLI checks that the installed version of helm-env-delta meets this minimum. If the installed version is older, the CLI exits immediately with a clear upgrade message. This prevents running configs that depend on newer features with an outdated tool version. Supports `"1.2.3"` or `"v1.2.3"` format.
|
|
422
|
+
|
|
417
423
|
---
|
|
418
424
|
|
|
419
425
|
### 🔒 Path Filtering (skipPath)
|
|
@@ -664,6 +670,8 @@ stopRules:
|
|
|
664
670
|
|
|
665
671
|
**Override:** Use `--force` to bypass stop rules when needed.
|
|
666
672
|
|
|
673
|
+
**Visibility:** Stop rule violations appear in console output, JSON reports, and HTML reports (dry-run mode only, as a collapsible table in the header area).
|
|
674
|
+
|
|
667
675
|
---
|
|
668
676
|
|
|
669
677
|
### 🎨 Output Formatting
|
|
@@ -675,13 +683,18 @@ outputFormat:
|
|
|
675
683
|
indent: 2 # Indentation size
|
|
676
684
|
keySeparator: true # Blank line between top-level keys (or second-level keys when single top-level key)
|
|
677
685
|
|
|
678
|
-
keyOrders: # Custom key ordering
|
|
686
|
+
keyOrders: # Custom key ordering (pin specific keys to top)
|
|
679
687
|
'apps/*.yaml':
|
|
680
688
|
- 'apiVersion'
|
|
681
689
|
- 'kind'
|
|
682
690
|
- 'metadata'
|
|
683
691
|
- 'spec'
|
|
684
692
|
|
|
693
|
+
keySort: # Sort all keys alphabetically at path
|
|
694
|
+
'**/*.yaml':
|
|
695
|
+
- path: 'spec.template.metadata.labels'
|
|
696
|
+
- path: 'env.vars'
|
|
697
|
+
|
|
685
698
|
arraySort: # Sort arrays
|
|
686
699
|
'services/**/values.yaml':
|
|
687
700
|
- path: 'env'
|
|
@@ -767,7 +780,7 @@ stopRules: # Add production safety rules
|
|
|
767
780
|
|
|
768
781
|
**Merging:**
|
|
769
782
|
|
|
770
|
-
- Primitives (`source`, `destination`, `prune`, `confirmationDelay`): Child overrides parent
|
|
783
|
+
- Primitives (`source`, `destination`, `prune`, `confirmationDelay`, `requiredVersion`): Child overrides parent
|
|
771
784
|
- Arrays (`include`, `exclude`): Concatenated (parent + child)
|
|
772
785
|
- Per-file Records (`skipPath`, `transforms`, `stopRules`, `fixedValues`): Keys merged, arrays concatenated
|
|
773
786
|
- `outputFormat`: Shallow merged (child fields override parent)
|
package/dist/configFile.d.ts
CHANGED
|
@@ -77,6 +77,9 @@ declare const arraySortRuleSchema: z.ZodObject<{
|
|
|
77
77
|
desc: "desc";
|
|
78
78
|
}>>;
|
|
79
79
|
}, z.core.$strip>;
|
|
80
|
+
declare const keySortRuleSchema: z.ZodObject<{
|
|
81
|
+
path: z.ZodString;
|
|
82
|
+
}, z.core.$strip>;
|
|
80
83
|
declare const fixedValueRuleSchema: z.ZodObject<{
|
|
81
84
|
path: z.ZodString;
|
|
82
85
|
value: z.ZodUnknown;
|
|
@@ -99,6 +102,7 @@ declare const transformRulesSchema: z.ZodObject<{
|
|
|
99
102
|
}, z.core.$strip>;
|
|
100
103
|
declare const baseConfigSchema: z.ZodObject<{
|
|
101
104
|
extends: z.ZodOptional<z.ZodString>;
|
|
105
|
+
requiredVersion: z.ZodOptional<z.ZodString>;
|
|
102
106
|
source: z.ZodOptional<z.ZodString>;
|
|
103
107
|
destination: z.ZodOptional<z.ZodString>;
|
|
104
108
|
include: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -111,6 +115,9 @@ declare const baseConfigSchema: z.ZodObject<{
|
|
|
111
115
|
keySeparator: z.ZodOptional<z.ZodBoolean>;
|
|
112
116
|
quoteValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
|
|
113
117
|
keyOrders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
|
|
118
|
+
keySort: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodObject<{
|
|
119
|
+
path: z.ZodString;
|
|
120
|
+
}, z.core.$strip>>>>;
|
|
114
121
|
arraySort: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodObject<{
|
|
115
122
|
path: z.ZodString;
|
|
116
123
|
sortBy: z.ZodString;
|
|
@@ -182,6 +189,7 @@ declare const finalConfigSchema: z.ZodObject<{
|
|
|
182
189
|
contentFile: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
183
190
|
filenameFile: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
184
191
|
}, z.core.$strip>>>;
|
|
192
|
+
requiredVersion: z.ZodOptional<z.ZodString>;
|
|
185
193
|
source: z.ZodNonOptional<z.ZodOptional<z.ZodString>>;
|
|
186
194
|
destination: z.ZodNonOptional<z.ZodOptional<z.ZodString>>;
|
|
187
195
|
skipPath: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
|
|
@@ -230,6 +238,9 @@ declare const finalConfigSchema: z.ZodObject<{
|
|
|
230
238
|
keySeparator: z.ZodDefault<z.ZodBoolean>;
|
|
231
239
|
quoteValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
|
|
232
240
|
keyOrders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
|
|
241
|
+
keySort: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodObject<{
|
|
242
|
+
path: z.ZodString;
|
|
243
|
+
}, z.core.$strip>>>>;
|
|
233
244
|
arraySort: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodObject<{
|
|
234
245
|
path: z.ZodString;
|
|
235
246
|
sortBy: z.ZodString;
|
|
@@ -253,6 +264,7 @@ declare const formatOnlyConfigSchema: z.ZodObject<{
|
|
|
253
264
|
contentFile: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
254
265
|
filenameFile: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
255
266
|
}, z.core.$strip>>>;
|
|
267
|
+
requiredVersion: z.ZodOptional<z.ZodString>;
|
|
256
268
|
source: z.ZodOptional<z.ZodString>;
|
|
257
269
|
destination: z.ZodNonOptional<z.ZodOptional<z.ZodString>>;
|
|
258
270
|
skipPath: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
|
|
@@ -301,6 +313,9 @@ declare const formatOnlyConfigSchema: z.ZodObject<{
|
|
|
301
313
|
keySeparator: z.ZodDefault<z.ZodBoolean>;
|
|
302
314
|
quoteValues: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
|
|
303
315
|
keyOrders: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
|
|
316
|
+
keySort: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodObject<{
|
|
317
|
+
path: z.ZodString;
|
|
318
|
+
}, z.core.$strip>>>>;
|
|
304
319
|
arraySort: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodObject<{
|
|
305
320
|
path: z.ZodString;
|
|
306
321
|
sortBy: z.ZodString;
|
|
@@ -324,6 +339,7 @@ export type RegexFileRule = z.infer<typeof regexFileRuleSchema>;
|
|
|
324
339
|
export type RegexFileKeyRule = z.infer<typeof regexFileKeyRuleSchema>;
|
|
325
340
|
export type VersionFormatRule = z.infer<typeof versionFormatRuleSchema>;
|
|
326
341
|
export type ArraySortRule = z.infer<typeof arraySortRuleSchema>;
|
|
342
|
+
export type KeySortRule = z.infer<typeof keySortRuleSchema>;
|
|
327
343
|
export type TransformRule = z.infer<typeof transformRuleSchema>;
|
|
328
344
|
export type TransformRules = z.infer<typeof transformRulesSchema>;
|
|
329
345
|
export type TransformConfig = Record<string, TransformRules>;
|
package/dist/configFile.js
CHANGED
|
@@ -79,6 +79,7 @@ const arraySortRuleSchema = zod_1.z.object({
|
|
|
79
79
|
sortBy: zod_1.z.string().min(1),
|
|
80
80
|
order: zod_1.z.enum(['asc', 'desc']).default('asc')
|
|
81
81
|
});
|
|
82
|
+
const keySortRuleSchema = zod_1.z.object({ path: zod_1.z.string().min(1) });
|
|
82
83
|
const fixedValueRuleSchema = zod_1.z.object({
|
|
83
84
|
path: zod_1.z.string().min(1).describe('JSONPath to the value to set'),
|
|
84
85
|
value: zod_1.z.unknown().describe('The constant value to set (any type: string, number, boolean, null, object, array)')
|
|
@@ -115,6 +116,13 @@ const transformRulesSchema = zod_1.z
|
|
|
115
116
|
});
|
|
116
117
|
const baseConfigSchema = zod_1.z.object({
|
|
117
118
|
extends: zod_1.z.string().min(1).optional(),
|
|
119
|
+
requiredVersion: zod_1.z
|
|
120
|
+
.string()
|
|
121
|
+
.min(1)
|
|
122
|
+
.regex(/^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/, {
|
|
123
|
+
message: 'Must be a valid semver version (e.g., "1.2.3" or "v1.2.3")'
|
|
124
|
+
})
|
|
125
|
+
.optional(),
|
|
118
126
|
source: zod_1.z.string().min(1).optional(),
|
|
119
127
|
destination: zod_1.z.string().min(1).optional(),
|
|
120
128
|
include: zod_1.z.array(zod_1.z.string().min(1)).optional(),
|
|
@@ -128,6 +136,7 @@ const baseConfigSchema = zod_1.z.object({
|
|
|
128
136
|
keySeparator: zod_1.z.boolean().optional(),
|
|
129
137
|
quoteValues: zod_1.z.record(zod_1.z.string(), zod_1.z.array(zod_1.z.string())).optional(),
|
|
130
138
|
keyOrders: zod_1.z.record(zod_1.z.string(), zod_1.z.array(zod_1.z.string())).optional(),
|
|
139
|
+
keySort: zod_1.z.record(zod_1.z.string(), zod_1.z.array(keySortRuleSchema)).optional(),
|
|
131
140
|
arraySort: zod_1.z.record(zod_1.z.string(), zod_1.z.array(arraySortRuleSchema)).optional()
|
|
132
141
|
})
|
|
133
142
|
.optional(),
|
|
@@ -149,6 +158,7 @@ const finalConfigSchema = baseConfigSchema
|
|
|
149
158
|
keySeparator: zod_1.z.boolean().default(false),
|
|
150
159
|
quoteValues: zod_1.z.record(zod_1.z.string(), zod_1.z.array(zod_1.z.string())).optional(),
|
|
151
160
|
keyOrders: zod_1.z.record(zod_1.z.string(), zod_1.z.array(zod_1.z.string())).optional(),
|
|
161
|
+
keySort: zod_1.z.record(zod_1.z.string(), zod_1.z.array(keySortRuleSchema)).optional(),
|
|
152
162
|
arraySort: zod_1.z.record(zod_1.z.string(), zod_1.z.array(arraySortRuleSchema)).optional()
|
|
153
163
|
})
|
|
154
164
|
.optional()
|
|
@@ -176,6 +186,7 @@ const formatOnlyConfigSchema = baseConfigSchema
|
|
|
176
186
|
keySeparator: zod_1.z.boolean().default(false),
|
|
177
187
|
quoteValues: zod_1.z.record(zod_1.z.string(), zod_1.z.array(zod_1.z.string())).optional(),
|
|
178
188
|
keyOrders: zod_1.z.record(zod_1.z.string(), zod_1.z.array(zod_1.z.string())).optional(),
|
|
189
|
+
keySort: zod_1.z.record(zod_1.z.string(), zod_1.z.array(keySortRuleSchema)).optional(),
|
|
179
190
|
arraySort: zod_1.z.record(zod_1.z.string(), zod_1.z.array(arraySortRuleSchema)).optional()
|
|
180
191
|
})
|
|
181
192
|
.optional()
|
package/dist/configLoader.d.ts
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import { type FinalConfig, type FormatOnlyConfig } from './configFile';
|
|
2
|
+
declare const ConfigLoaderErrorClass: {
|
|
3
|
+
new (message: string, options?: import("./utils").ErrorOptions): {
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
readonly code?: string;
|
|
6
|
+
readonly path?: string;
|
|
7
|
+
readonly cause?: Error;
|
|
8
|
+
readonly hints?: string[];
|
|
9
|
+
name: string;
|
|
10
|
+
message: string;
|
|
11
|
+
stack?: string;
|
|
12
|
+
};
|
|
13
|
+
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
|
|
14
|
+
prepareStackTrace(err: Error, stackTraces: NodeJS.CallSite[]): any;
|
|
15
|
+
stackTraceLimit: number;
|
|
16
|
+
};
|
|
17
|
+
export declare class ConfigLoaderError extends ConfigLoaderErrorClass {
|
|
18
|
+
}
|
|
19
|
+
export declare const isConfigLoaderError: (error: unknown) => error is ConfigLoaderError;
|
|
2
20
|
export type Config = FinalConfig;
|
|
3
21
|
export type LoadConfigOptions = {
|
|
4
22
|
formatOnly?: boolean;
|
|
5
23
|
};
|
|
6
24
|
export declare const loadConfigFile: (configPath: string, quiet?: boolean, logger?: import("./logger").Logger, options?: LoadConfigOptions) => FinalConfig | FormatOnlyConfig;
|
|
25
|
+
export {};
|
package/dist/configLoader.js
CHANGED
|
@@ -3,11 +3,36 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.loadConfigFile = void 0;
|
|
6
|
+
exports.loadConfigFile = exports.isConfigLoaderError = exports.ConfigLoaderError = void 0;
|
|
7
7
|
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const package_json_1 = __importDefault(require("../package.json"));
|
|
8
9
|
const configFile_1 = require("./configFile");
|
|
9
10
|
const configMerger_1 = require("./configMerger");
|
|
10
11
|
const utils_1 = require("./utils");
|
|
12
|
+
const ConfigLoaderErrorClass = (0, utils_1.createErrorClass)('Config Loader Error', {
|
|
13
|
+
VERSION_REQUIREMENT: 'Installed version does not meet the required version'
|
|
14
|
+
}, (message, options) => {
|
|
15
|
+
let fullMessage = `Config Loader Error: ${message}`;
|
|
16
|
+
if (options['requiredVersion'])
|
|
17
|
+
fullMessage += `\n Required version: ${options['requiredVersion']}`;
|
|
18
|
+
if (options['currentVersion'])
|
|
19
|
+
fullMessage += `\n Current version: ${options['currentVersion']}`;
|
|
20
|
+
fullMessage += '\n\n Hint: Run "npm install" to update helm-env-delta to the required version.';
|
|
21
|
+
return fullMessage;
|
|
22
|
+
});
|
|
23
|
+
class ConfigLoaderError extends ConfigLoaderErrorClass {
|
|
24
|
+
}
|
|
25
|
+
exports.ConfigLoaderError = ConfigLoaderError;
|
|
26
|
+
exports.isConfigLoaderError = (0, utils_1.createErrorTypeGuard)(ConfigLoaderError);
|
|
27
|
+
const checkRequiredVersion = (requiredVersion) => {
|
|
28
|
+
const currentVersion = package_json_1.default.version;
|
|
29
|
+
if ((0, utils_1.isNewerVersion)(currentVersion, requiredVersion))
|
|
30
|
+
throw new ConfigLoaderError(`This config requires helm-env-delta v${requiredVersion} or newer`, {
|
|
31
|
+
code: 'VERSION_REQUIREMENT',
|
|
32
|
+
requiredVersion,
|
|
33
|
+
currentVersion
|
|
34
|
+
});
|
|
35
|
+
};
|
|
11
36
|
const expandTransformFiles = (config, configDirectory) => {
|
|
12
37
|
if (!config.transforms)
|
|
13
38
|
return config;
|
|
@@ -34,6 +59,8 @@ const loadConfigFile = (configPath, quiet = false, logger, options = {}) => {
|
|
|
34
59
|
const configDirectory = node_path_1.default.dirname(node_path_1.default.resolve(configPath));
|
|
35
60
|
const mergedConfig = (0, configMerger_1.resolveConfigWithExtends)(configPath, new Set(), 0, logger);
|
|
36
61
|
const expandedConfig = expandTransformFiles(mergedConfig, configDirectory);
|
|
62
|
+
if (expandedConfig.requiredVersion)
|
|
63
|
+
checkRequiredVersion(expandedConfig.requiredVersion);
|
|
37
64
|
const config = options.formatOnly
|
|
38
65
|
? (0, configFile_1.parseFormatOnlyConfig)(expandedConfig, configPath)
|
|
39
66
|
: (0, configFile_1.parseFinalConfig)(expandedConfig, configPath);
|
package/dist/configMerger.js
CHANGED
|
@@ -88,6 +88,10 @@ const mergeConfigs = (parent, child) => {
|
|
|
88
88
|
merged.confirmationDelay = child.confirmationDelay;
|
|
89
89
|
else if (parent.confirmationDelay !== undefined)
|
|
90
90
|
merged.confirmationDelay = parent.confirmationDelay;
|
|
91
|
+
if (child.requiredVersion !== undefined)
|
|
92
|
+
merged.requiredVersion = child.requiredVersion;
|
|
93
|
+
else if (parent.requiredVersion !== undefined)
|
|
94
|
+
merged.requiredVersion = parent.requiredVersion;
|
|
91
95
|
const parentInclude = parent.include ?? [];
|
|
92
96
|
const childInclude = child.include ?? [];
|
|
93
97
|
if (parentInclude.length > 0 || childInclude.length > 0)
|
package/dist/htmlReporter.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Config } from './configFile';
|
|
2
2
|
import { FileDiffResult } from './fileDiff';
|
|
3
|
+
import type { ValidationResult } from './stopRulesValidator';
|
|
3
4
|
export type { DiffStats, ReportMetadata } from './reporters/htmlTemplate';
|
|
4
5
|
declare const HtmlReporterErrorClass: {
|
|
5
6
|
new (message: string, options?: import("./utils/errors").ErrorOptions): {
|
|
@@ -19,4 +20,4 @@ declare const HtmlReporterErrorClass: {
|
|
|
19
20
|
export declare class HtmlReporterError extends HtmlReporterErrorClass {
|
|
20
21
|
}
|
|
21
22
|
export declare const isHtmlReporterError: (error: unknown) => error is HtmlReporterError;
|
|
22
|
-
export declare const generateHtmlReport: (diffResult: FileDiffResult, formattedFiles: string[], config: Config, dryRun: boolean, logger?: import("./logger").Logger) => Promise<void>;
|
|
23
|
+
export declare const generateHtmlReport: (diffResult: FileDiffResult, formattedFiles: string[], config: Config, dryRun: boolean, logger?: import("./logger").Logger, validationResult?: ValidationResult) => Promise<void>;
|
package/dist/htmlReporter.js
CHANGED
|
@@ -118,7 +118,7 @@ const writeHtmlFile = async (htmlContent, outputPath) => {
|
|
|
118
118
|
});
|
|
119
119
|
}
|
|
120
120
|
};
|
|
121
|
-
const generateHtmlReport = async (diffResult, formattedFiles, config, dryRun, logger) => {
|
|
121
|
+
const generateHtmlReport = async (diffResult, formattedFiles, config, dryRun, logger, validationResult) => {
|
|
122
122
|
const reportPath = generateTemporaryFilePath();
|
|
123
123
|
const metadata = {
|
|
124
124
|
timestamp: new Date().toISOString(),
|
|
@@ -151,7 +151,17 @@ const generateHtmlReport = async (diffResult, formattedFiles, config, dryRun, lo
|
|
|
151
151
|
}
|
|
152
152
|
statsArray.sort((a, b) => b.added + b.removed - (a.added + a.removed));
|
|
153
153
|
const diffStats = { totalAdded, totalRemoved, fileStats: statsArray };
|
|
154
|
-
const
|
|
154
|
+
const stopRuleViolations = validationResult && validationResult.violations.length > 0
|
|
155
|
+
? validationResult.violations.map((violation) => ({
|
|
156
|
+
file: violation.file,
|
|
157
|
+
rule: { type: violation.rule.type, path: violation.rule.path },
|
|
158
|
+
path: violation.path,
|
|
159
|
+
oldValue: violation.oldValue,
|
|
160
|
+
updatedValue: violation.updatedValue,
|
|
161
|
+
message: violation.message
|
|
162
|
+
}))
|
|
163
|
+
: undefined;
|
|
164
|
+
const htmlContent = (0, htmlTemplate_1.generateHtmlTemplate)(diffResult, formattedFiles, trulyUnchangedFiles, metadata, changedSections, changedFileIds, addedSections, addedFileIds, diffStats, stopRuleViolations);
|
|
155
165
|
await writeHtmlFile(htmlContent, reportPath);
|
|
156
166
|
logger?.log(`✓ HTML report generated: ${reportPath}, opening in browser...`);
|
|
157
167
|
try {
|
package/dist/index.js
CHANGED
|
@@ -326,7 +326,7 @@ const main = async () => {
|
|
|
326
326
|
}
|
|
327
327
|
const formattedFiles = await (0, fileUpdater_1.updateFiles)(diffResult, sourceFiles, destinationFiles, syncConfig, command.dryRun, command.skipFormat, logger);
|
|
328
328
|
if (command.diffHtml && !command.quiet)
|
|
329
|
-
await (0, htmlReporter_1.generateHtmlReport)(diffResult, formattedFiles, syncConfig, command.dryRun, logger);
|
|
329
|
+
await (0, htmlReporter_1.generateHtmlReport)(diffResult, formattedFiles, syncConfig, command.dryRun, logger, command.dryRun ? validationResult : undefined);
|
|
330
330
|
if (command.diffJson)
|
|
331
331
|
(0, jsonReporter_1.generateJsonReport)(diffResult, formattedFiles, validationResult, syncConfig, command.dryRun, package_json_1.default.version);
|
|
332
332
|
};
|
|
@@ -337,6 +337,8 @@ const main = async () => {
|
|
|
337
337
|
catch (error) {
|
|
338
338
|
if ((0, configMerger_1.isConfigMergerError)(error))
|
|
339
339
|
console.error(error.message);
|
|
340
|
+
else if ((0, configLoader_1.isConfigLoaderError)(error))
|
|
341
|
+
console.error(error.message);
|
|
340
342
|
else if ((0, ZodError_1.isZodValidationError)(error))
|
|
341
343
|
console.error(error.message);
|
|
342
344
|
else if ((0, fileLoader_1.isFileLoaderError)(error))
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export declare const DIFF2HTML_STYLES: string;
|
|
2
|
-
export declare const HTML_STYLES = "\n /* Custom styles */\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n margin: 0;\n padding: 20px;\n background: #f6f8fa;\n }\n\n header {\n background: white;\n padding: 20px;\n border-radius: 6px;\n margin-bottom: 20px;\n box-shadow: 0 1px 3px rgba(0,0,0,0.12);\n }\n\n h1 {\n margin: 0 0 10px 0;\n color: #24292e;\n }\n\n .metadata {\n display: flex;\n gap: 20px;\n margin: 10px 0;\n color: #586069;\n font-size: 14px;\n }\n\n .dry-run-badge {\n display: inline-block;\n padding: 4px 8px;\n background: #cfe2ff;\n color: #084298;\n border-radius: 4px;\n font-weight: bold;\n font-size: 12px;\n }\n\n .summary {\n display: flex;\n gap: 12px;\n margin: 15px 0;\n }\n\n .stat {\n padding: 8px 16px;\n border-radius: 6px;\n font-weight: 600;\n font-size: 14px;\n }\n\n .stat.added { background: #d4edda; color: #155724; }\n .stat.changed { background: #fff3cd; color: #856404; }\n .stat.deleted { background: #f8d7da; color: #721c24; }\n .stat.formatted { background: #d1ecf1; color: #0c5460; }\n .stat.unchanged { background: #e2e3e5; color: #383d41; }\n\n .tabs {\n display: flex;\n background: white;\n border-radius: 6px 6px 0 0;\n border-bottom: 1px solid #d0d7de;\n box-shadow: 0 1px 3px rgba(0,0,0,0.12);\n }\n\n .tab {\n padding: 12px 24px;\n border: none;\n background: transparent;\n cursor: pointer;\n font-size: 14px;\n color: #586069;\n transition: all 0.2s;\n }\n\n .tab:hover {\n color: #24292e;\n }\n\n .tab.active {\n border-bottom: 2px solid #0969da;\n color: #0969da;\n font-weight: 600;\n }\n\n main {\n background: white;\n padding: 20px;\n border-radius: 0 0 6px 6px;\n box-shadow: 0 1px 3px rgba(0,0,0,0.12);\n }\n\n .tab-content {\n display: none;\n }\n\n .tab-content.active {\n display: block;\n }\n\n .file-section {\n margin: 12px 0;\n border: 1px solid #d0d7de;\n border-radius: 6px;\n }\n\n .file-section summary {\n padding: 12px 16px;\n background: #f6f8fa;\n cursor: pointer;\n font-weight: 600;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n font-size: 13px;\n color: #24292e;\n }\n\n .file-section summary:hover {\n background: #eaeef2;\n }\n\n .file-section[open] > summary {\n position: sticky;\n top: 0;\n z-index: 10;\n border-bottom: 1px solid #d0d7de;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n }\n\n .filename-transform {\n color: #0969da;\n }\n\n .diff-container {\n padding: 0;\n }\n\n /* Hide diff2html file header with rename badge */\n .d2h-file-header {\n display: none;\n }\n\n .file-list {\n margin: 20px 0;\n }\n\n .file-list ul {\n list-style: none;\n padding: 0;\n margin: 10px 0;\n }\n\n .file-list li {\n padding: 8px 16px;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n font-size: 13px;\n color: #586069;\n border-bottom: 1px solid #f6f8fa;\n }\n\n .file-list li:hover {\n background: #f6f8fa;\n }\n\n /* Treeview styles */\n .tree-root {\n list-style: none;\n padding: 0;\n margin: 10px 0;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n font-size: 13px;\n }\n\n .tree-root ul {\n list-style: none;\n padding-left: 20px;\n margin: 0;\n }\n\n .tree-folder,\n .tree-file {\n padding: 4px 8px;\n border-radius: 4px;\n cursor: default;\n }\n\n .tree-folder:hover,\n .tree-file:hover {\n background: #f6f8fa;\n }\n\n .tree-toggle {\n display: inline-block;\n width: 16px;\n cursor: pointer;\n color: #586069;\n font-size: 10px;\n user-select: none;\n }\n\n .tree-folder.collapsed > .tree-toggle {\n transform: rotate(-90deg);\n }\n\n .tree-folder.collapsed > .tree-children {\n display: none;\n }\n\n .tree-folder-name {\n color: #0969da;\n font-weight: 500;\n }\n\n .tree-file-name {\n color: #586069;\n padding-left: 16px;\n }\n\n /* Sidebar styles */\n .sidebar-container {\n display: flex;\n gap: 0;\n }\n\n .sidebar {\n width: 280px;\n min-width: 280px;\n border-right: 1px solid #d0d7de;\n background: #f6f8fa;\n transition: width 0.2s, min-width 0.2s, padding 0.2s, opacity 0.2s;\n }\n\n .sidebar.collapsed {\n width: 0;\n min-width: 0;\n padding: 0;\n overflow: hidden;\n border-right: none;\n }\n\n .sidebar-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n border-bottom: 1px solid #d0d7de;\n background: #fff;\n font-weight: 600;\n font-size: 14px;\n color: #24292e;\n position: sticky;\n top: 0;\n z-index: 1;\n }\n\n .sidebar-toggle {\n background: none;\n border: 1px solid #d0d7de;\n border-radius: 4px;\n cursor: pointer;\n padding: 4px 8px;\n color: #586069;\n font-size: 12px;\n }\n\n .sidebar-toggle:hover {\n background: #f6f8fa;\n color: #24292e;\n }\n\n .sidebar-content {\n padding: 8px;\n }\n\n .sidebar-tree .tree-file-link {\n color: #586069;\n text-decoration: none;\n padding-left: 16px;\n display: block;\n }\n\n .sidebar-tree .tree-file-link:hover {\n color: #0969da;\n }\n\n .sidebar-tree .tree-file.active .tree-file-link {\n color: #0969da;\n font-weight: 600;\n }\n\n .changed-content {\n flex: 1;\n min-width: 0;\n padding-left: 20px;\n }\n\n .sidebar-expand-btn {\n display: none;\n position: fixed;\n left: 0;\n top: 50%;\n transform: translateY(-50%);\n background: #f6f8fa;\n border: 1px solid #d0d7de;\n border-left: none;\n border-radius: 0 4px 4px 0;\n padding: 8px 4px;\n cursor: pointer;\n color: #586069;\n z-index: 100;\n }\n\n .sidebar-expand-btn:hover {\n background: #eaeef2;\n color: #24292e;\n }\n\n .sidebar.collapsed ~ .sidebar-expand-btn {\n display: block;\n }\n\n /* Added content area (same as changed-content) */\n .added-content {\n flex: 1;\n min-width: 0;\n padding-left: 20px;\n }\n\n /* Content container for added files */\n .content-container {\n padding: 16px;\n background: #f6f8fa;\n border-top: 1px solid #d0d7de;\n }\n\n .content-actions {\n display: flex;\n gap: 8px;\n margin-bottom: 12px;\n }\n\n .copy-btn,\n .download-btn {\n padding: 6px 12px;\n border: 1px solid #d0d7de;\n border-radius: 6px;\n background: white;\n cursor: pointer;\n font-size: 13px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n color: #24292e;\n transition: all 0.2s;\n }\n\n .copy-btn:hover,\n .download-btn:hover {\n background: #f3f4f6;\n border-color: #b0b7be;\n }\n\n .copy-btn.copied {\n background: #d4edda;\n border-color: #28a745;\n color: #155724;\n }\n\n .file-content {\n margin: 0;\n padding: 16px;\n background: white;\n border: 1px solid #d0d7de;\n border-radius: 6px;\n overflow-x: auto;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n font-size: 12px;\n line-height: 1.5;\n white-space: pre;\n }\n\n .file-content code {\n font-family: inherit;\n }\n\n /* Scroll-to-top button */\n .scroll-to-top {\n display: none;\n position: fixed;\n bottom: 30px;\n right: 30px;\n width: 40px;\n height: 40px;\n border: none;\n border-radius: 50%;\n background: #0969da;\n color: white;\n font-size: 18px;\n cursor: pointer;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n transition: opacity 0.2s, background 0.2s;\n z-index: 200;\n line-height: 40px;\n text-align: center;\n padding: 0;\n }\n\n .scroll-to-top:hover {\n background: #0550ae;\n }\n\n .scroll-to-top.visible {\n display: block;\n }\n\n /* Content toolbar (collapse/expand buttons) */\n .content-toolbar {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n margin-bottom: 12px;\n }\n\n .collapse-all-btn,\n .expand-all-btn {\n padding: 4px 12px;\n border: 1px solid #d0d7de;\n border-radius: 4px;\n background: none;\n cursor: pointer;\n font-size: 12px;\n color: #586069;\n transition: all 0.2s;\n }\n\n .collapse-all-btn:hover,\n .expand-all-btn:hover {\n background: #f6f8fa;\n color: #24292e;\n }\n\n /* Line change count badges */\n .summary-badges {\n float: right;\n display: inline-flex;\n gap: 6px;\n margin-left: 12px;\n }\n\n .line-badge {\n display: inline-block;\n padding: 1px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n line-height: 18px;\n }\n\n .line-added {\n background: #d4edda;\n color: #155724;\n }\n\n .line-removed {\n background: #f8d7da;\n color: #721c24;\n }\n\n /* Diff toolbar */\n .diff-toolbar {\n display: flex;\n justify-content: flex-end;\n padding: 8px 16px;\n border-bottom: 1px solid #d0d7de;\n background: #f6f8fa;\n }\n\n .copy-diff-btn {\n padding: 4px 12px;\n border: 1px solid #d0d7de;\n border-radius: 6px;\n background: white;\n cursor: pointer;\n font-size: 12px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n color: #24292e;\n transition: all 0.2s;\n }\n\n .copy-diff-btn:hover {\n background: #f3f4f6;\n border-color: #b0b7be;\n }\n\n .copy-diff-btn.copied {\n background: #d4edda;\n border-color: #28a745;\n color: #155724;\n }\n\n /* Sidebar search */\n .sidebar-search {\n width: 100%;\n padding: 6px 8px;\n border: 1px solid #d0d7de;\n border-radius: 4px;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n font-size: 12px;\n margin-bottom: 8px;\n box-sizing: border-box;\n position: sticky;\n top: 0;\n z-index: 1;\n background: #fff;\n }\n\n .sidebar-search:focus {\n outline: none;\n border-color: #0969da;\n box-shadow: 0 0 0 3px rgba(9,105,218,0.15);\n }\n\n /* Stats toggle button */\n .stats-toggle-btn {\n padding: 4px 12px;\n border: 1px solid #d0d7de;\n border-radius: 4px;\n background: none;\n cursor: pointer;\n font-size: 12px;\n color: #586069;\n transition: all 0.2s;\n }\n\n .stats-toggle-btn:hover {\n background: #f6f8fa;\n color: #24292e;\n }\n\n /* Statistics dashboard */\n .stats-dashboard {\n margin: 15px 0 0;\n padding: 12px 0 0;\n border-top: 1px solid #e1e4e8;\n }\n\n .stats-summary {\n display: flex;\n gap: 16px;\n align-items: center;\n margin-bottom: 10px;\n }\n\n .stats-summary .total-added {\n font-weight: 700;\n color: #155724;\n font-size: 16px;\n }\n\n .stats-summary .total-removed {\n font-weight: 700;\n color: #721c24;\n font-size: 16px;\n }\n\n .stats-bar {\n display: flex;\n height: 8px;\n border-radius: 4px;\n overflow: hidden;\n background: #e1e4e8;\n margin-bottom: 10px;\n }\n\n .stats-segment {\n height: 100%;\n min-width: 2px;\n }\n\n .stats-segment.added-segment {\n background: #28a745;\n }\n\n .stats-segment.removed-segment {\n background: #d73a49;\n }\n\n .top-changed-files {\n list-style: none;\n padding: 0;\n margin: 0;\n font-size: 13px;\n }\n\n .top-changed-files li {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 3px 0;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n color: #586069;\n }\n\n .top-changed-files .file-path {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-right: 8px;\n }\n\n .top-changed-files .file-stats {\n white-space: nowrap;\n flex-shrink: 0;\n }\n";
|
|
2
|
+
export declare const HTML_STYLES = "\n /* Custom styles */\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n margin: 0;\n padding: 20px;\n background: #f6f8fa;\n }\n\n header {\n background: white;\n padding: 20px;\n border-radius: 6px;\n margin-bottom: 20px;\n box-shadow: 0 1px 3px rgba(0,0,0,0.12);\n }\n\n h1 {\n margin: 0 0 10px 0;\n color: #24292e;\n }\n\n .metadata {\n display: flex;\n gap: 20px;\n margin: 10px 0;\n color: #586069;\n font-size: 14px;\n }\n\n .dry-run-badge {\n display: inline-block;\n padding: 4px 8px;\n background: #cfe2ff;\n color: #084298;\n border-radius: 4px;\n font-weight: bold;\n font-size: 12px;\n }\n\n .summary {\n display: flex;\n gap: 12px;\n margin: 15px 0;\n }\n\n .stat {\n padding: 8px 16px;\n border-radius: 6px;\n font-weight: 600;\n font-size: 14px;\n }\n\n .stat.added { background: #d4edda; color: #155724; }\n .stat.changed { background: #fff3cd; color: #856404; }\n .stat.deleted { background: #f8d7da; color: #721c24; }\n .stat.formatted { background: #d1ecf1; color: #0c5460; }\n .stat.unchanged { background: #e2e3e5; color: #383d41; }\n\n .tabs {\n display: flex;\n background: white;\n border-radius: 6px 6px 0 0;\n border-bottom: 1px solid #d0d7de;\n box-shadow: 0 1px 3px rgba(0,0,0,0.12);\n }\n\n .tab {\n padding: 12px 24px;\n border: none;\n background: transparent;\n cursor: pointer;\n font-size: 14px;\n color: #586069;\n transition: all 0.2s;\n }\n\n .tab:hover {\n color: #24292e;\n }\n\n .tab.active {\n border-bottom: 2px solid #0969da;\n color: #0969da;\n font-weight: 600;\n }\n\n main {\n background: white;\n padding: 20px;\n border-radius: 0 0 6px 6px;\n box-shadow: 0 1px 3px rgba(0,0,0,0.12);\n }\n\n .tab-content {\n display: none;\n }\n\n .tab-content.active {\n display: block;\n }\n\n .file-section {\n margin: 12px 0;\n border: 1px solid #d0d7de;\n border-radius: 6px;\n }\n\n .file-section summary {\n padding: 12px 16px;\n background: #f6f8fa;\n cursor: pointer;\n font-weight: 600;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n font-size: 13px;\n color: #24292e;\n }\n\n .file-section summary:hover {\n background: #eaeef2;\n }\n\n .file-section[open] > summary {\n position: sticky;\n top: 0;\n z-index: 10;\n border-bottom: 1px solid #d0d7de;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n }\n\n .filename-transform {\n color: #0969da;\n }\n\n .diff-container {\n padding: 0;\n }\n\n /* Hide diff2html file header with rename badge */\n .d2h-file-header {\n display: none;\n }\n\n .file-list {\n margin: 20px 0;\n }\n\n .file-list ul {\n list-style: none;\n padding: 0;\n margin: 10px 0;\n }\n\n .file-list li {\n padding: 8px 16px;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n font-size: 13px;\n color: #586069;\n border-bottom: 1px solid #f6f8fa;\n }\n\n .file-list li:hover {\n background: #f6f8fa;\n }\n\n /* Treeview styles */\n .tree-root {\n list-style: none;\n padding: 0;\n margin: 10px 0;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n font-size: 13px;\n }\n\n .tree-root ul {\n list-style: none;\n padding-left: 20px;\n margin: 0;\n }\n\n .tree-folder,\n .tree-file {\n padding: 4px 8px;\n border-radius: 4px;\n cursor: default;\n }\n\n .tree-folder:hover,\n .tree-file:hover {\n background: #f6f8fa;\n }\n\n .tree-toggle {\n display: inline-block;\n width: 16px;\n cursor: pointer;\n color: #586069;\n font-size: 10px;\n user-select: none;\n }\n\n .tree-folder.collapsed > .tree-toggle {\n transform: rotate(-90deg);\n }\n\n .tree-folder.collapsed > .tree-children {\n display: none;\n }\n\n .tree-folder-name {\n color: #0969da;\n font-weight: 500;\n }\n\n .tree-file-name {\n color: #586069;\n padding-left: 16px;\n }\n\n /* Sidebar styles */\n .sidebar-container {\n display: flex;\n gap: 0;\n }\n\n .sidebar {\n width: 280px;\n min-width: 280px;\n border-right: 1px solid #d0d7de;\n background: #f6f8fa;\n transition: width 0.2s, min-width 0.2s, padding 0.2s, opacity 0.2s;\n }\n\n .sidebar.collapsed {\n width: 0;\n min-width: 0;\n padding: 0;\n overflow: hidden;\n border-right: none;\n }\n\n .sidebar-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 12px 16px;\n border-bottom: 1px solid #d0d7de;\n background: #fff;\n font-weight: 600;\n font-size: 14px;\n color: #24292e;\n position: sticky;\n top: 0;\n z-index: 1;\n }\n\n .sidebar-toggle {\n background: none;\n border: 1px solid #d0d7de;\n border-radius: 4px;\n cursor: pointer;\n padding: 4px 8px;\n color: #586069;\n font-size: 12px;\n }\n\n .sidebar-toggle:hover {\n background: #f6f8fa;\n color: #24292e;\n }\n\n .sidebar-content {\n padding: 8px;\n }\n\n .sidebar-tree .tree-file-link {\n color: #586069;\n text-decoration: none;\n padding-left: 16px;\n display: block;\n }\n\n .sidebar-tree .tree-file-link:hover {\n color: #0969da;\n }\n\n .sidebar-tree .tree-file.active .tree-file-link {\n color: #0969da;\n font-weight: 600;\n }\n\n .changed-content {\n flex: 1;\n min-width: 0;\n padding-left: 20px;\n }\n\n .sidebar-expand-btn {\n display: none;\n position: fixed;\n left: 0;\n top: 50%;\n transform: translateY(-50%);\n background: #f6f8fa;\n border: 1px solid #d0d7de;\n border-left: none;\n border-radius: 0 4px 4px 0;\n padding: 8px 4px;\n cursor: pointer;\n color: #586069;\n z-index: 100;\n }\n\n .sidebar-expand-btn:hover {\n background: #eaeef2;\n color: #24292e;\n }\n\n .sidebar.collapsed ~ .sidebar-expand-btn {\n display: block;\n }\n\n /* Added content area (same as changed-content) */\n .added-content {\n flex: 1;\n min-width: 0;\n padding-left: 20px;\n }\n\n /* Content container for added files */\n .content-container {\n padding: 16px;\n background: #f6f8fa;\n border-top: 1px solid #d0d7de;\n }\n\n .content-actions {\n display: flex;\n gap: 8px;\n margin-bottom: 12px;\n }\n\n .copy-btn,\n .download-btn {\n padding: 6px 12px;\n border: 1px solid #d0d7de;\n border-radius: 6px;\n background: white;\n cursor: pointer;\n font-size: 13px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n color: #24292e;\n transition: all 0.2s;\n }\n\n .copy-btn:hover,\n .download-btn:hover {\n background: #f3f4f6;\n border-color: #b0b7be;\n }\n\n .copy-btn.copied {\n background: #d4edda;\n border-color: #28a745;\n color: #155724;\n }\n\n .file-content {\n margin: 0;\n padding: 16px;\n background: white;\n border: 1px solid #d0d7de;\n border-radius: 6px;\n overflow-x: auto;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n font-size: 12px;\n line-height: 1.5;\n white-space: pre;\n }\n\n .file-content code {\n font-family: inherit;\n }\n\n /* Scroll-to-top button */\n .scroll-to-top {\n display: none;\n position: fixed;\n bottom: 30px;\n right: 30px;\n width: 40px;\n height: 40px;\n border: none;\n border-radius: 50%;\n background: #0969da;\n color: white;\n font-size: 18px;\n cursor: pointer;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n transition: opacity 0.2s, background 0.2s;\n z-index: 200;\n line-height: 40px;\n text-align: center;\n padding: 0;\n }\n\n .scroll-to-top:hover {\n background: #0550ae;\n }\n\n .scroll-to-top.visible {\n display: block;\n }\n\n /* Content toolbar (collapse/expand buttons) */\n .content-toolbar {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n margin-bottom: 12px;\n }\n\n .collapse-all-btn,\n .expand-all-btn {\n padding: 4px 12px;\n border: 1px solid #d0d7de;\n border-radius: 4px;\n background: none;\n cursor: pointer;\n font-size: 12px;\n color: #586069;\n transition: all 0.2s;\n }\n\n .collapse-all-btn:hover,\n .expand-all-btn:hover {\n background: #f6f8fa;\n color: #24292e;\n }\n\n /* Line change count badges */\n .summary-badges {\n float: right;\n display: inline-flex;\n gap: 6px;\n margin-left: 12px;\n }\n\n .line-badge {\n display: inline-block;\n padding: 1px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n line-height: 18px;\n }\n\n .line-added {\n background: #d4edda;\n color: #155724;\n }\n\n .line-removed {\n background: #f8d7da;\n color: #721c24;\n }\n\n /* Diff toolbar */\n .diff-toolbar {\n display: flex;\n justify-content: flex-end;\n padding: 8px 16px;\n border-bottom: 1px solid #d0d7de;\n background: #f6f8fa;\n }\n\n .copy-diff-btn {\n padding: 4px 12px;\n border: 1px solid #d0d7de;\n border-radius: 6px;\n background: white;\n cursor: pointer;\n font-size: 12px;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n color: #24292e;\n transition: all 0.2s;\n }\n\n .copy-diff-btn:hover {\n background: #f3f4f6;\n border-color: #b0b7be;\n }\n\n .copy-diff-btn.copied {\n background: #d4edda;\n border-color: #28a745;\n color: #155724;\n }\n\n /* Sidebar search */\n .sidebar-search {\n width: 100%;\n padding: 6px 8px;\n border: 1px solid #d0d7de;\n border-radius: 4px;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n font-size: 12px;\n margin-bottom: 8px;\n box-sizing: border-box;\n position: sticky;\n top: 0;\n z-index: 1;\n background: #fff;\n }\n\n .sidebar-search:focus {\n outline: none;\n border-color: #0969da;\n box-shadow: 0 0 0 3px rgba(9,105,218,0.15);\n }\n\n /* Stats toggle button */\n .stats-toggle-btn {\n padding: 4px 12px;\n border: 1px solid #d0d7de;\n border-radius: 4px;\n background: none;\n cursor: pointer;\n font-size: 12px;\n color: #586069;\n transition: all 0.2s;\n }\n\n .stats-toggle-btn:hover {\n background: #f6f8fa;\n color: #24292e;\n }\n\n /* Statistics dashboard */\n .stats-dashboard {\n margin: 15px 0 0;\n padding: 12px 0 0;\n border-top: 1px solid #e1e4e8;\n }\n\n .stats-summary {\n display: flex;\n gap: 16px;\n align-items: center;\n margin-bottom: 10px;\n }\n\n .stats-summary .total-added {\n font-weight: 700;\n color: #155724;\n font-size: 16px;\n }\n\n .stats-summary .total-removed {\n font-weight: 700;\n color: #721c24;\n font-size: 16px;\n }\n\n .stats-bar {\n display: flex;\n height: 8px;\n border-radius: 4px;\n overflow: hidden;\n background: #e1e4e8;\n margin-bottom: 10px;\n }\n\n .stats-segment {\n height: 100%;\n min-width: 2px;\n }\n\n .stats-segment.added-segment {\n background: #28a745;\n }\n\n .stats-segment.removed-segment {\n background: #d73a49;\n }\n\n .top-changed-files {\n list-style: none;\n padding: 0;\n margin: 0;\n font-size: 13px;\n }\n\n .top-changed-files li {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 3px 0;\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n color: #586069;\n }\n\n .top-changed-files .file-path {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-right: 8px;\n }\n\n .top-changed-files .file-stats {\n white-space: nowrap;\n flex-shrink: 0;\n }\n\n /* Stop rules violations badge */\n .stat.violations { background: #f8d7da; color: #721c24; }\n\n /* Violations section */\n .violations-section {\n margin: 15px 0 0;\n padding: 12px 0 0;\n border-top: 1px solid #e1e4e8;\n }\n\n .violations-toggle-btn {\n padding: 4px 12px;\n border: 1px solid #d0d7de;\n border-radius: 4px;\n background: none;\n cursor: pointer;\n font-size: 12px;\n color: #586069;\n transition: all 0.2s;\n }\n\n .violations-toggle-btn:hover {\n background: #f6f8fa;\n color: #24292e;\n }\n\n .violations-table {\n width: 100%;\n border-collapse: collapse;\n font-size: 13px;\n margin-top: 10px;\n }\n\n .violations-table th {\n background: #f6f8fa;\n text-align: left;\n padding: 8px 12px;\n border-bottom: 2px solid #d0d7de;\n font-weight: 600;\n color: #24292e;\n }\n\n .violations-table td {\n padding: 8px 12px;\n border-bottom: 1px solid #e1e4e8;\n color: #24292e;\n vertical-align: top;\n }\n\n .violations-table tr:hover td {\n background: #f6f8fa;\n }\n\n .violation-rule-badge {\n display: inline-block;\n padding: 2px 8px;\n border-radius: 10px;\n font-size: 11px;\n font-weight: 600;\n background: #fff3cd;\n color: #856404;\n white-space: nowrap;\n }\n\n .violation-value {\n font-family: ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace;\n font-size: 12px;\n background: #f6f8fa;\n padding: 2px 6px;\n border-radius: 3px;\n border: 1px solid #e1e4e8;\n }\n";
|
|
3
3
|
export declare const TAB_SCRIPT: string;
|
|
@@ -617,6 +617,79 @@ exports.HTML_STYLES = `
|
|
|
617
617
|
white-space: nowrap;
|
|
618
618
|
flex-shrink: 0;
|
|
619
619
|
}
|
|
620
|
+
|
|
621
|
+
/* Stop rules violations badge */
|
|
622
|
+
.stat.violations { background: #f8d7da; color: #721c24; }
|
|
623
|
+
|
|
624
|
+
/* Violations section */
|
|
625
|
+
.violations-section {
|
|
626
|
+
margin: 15px 0 0;
|
|
627
|
+
padding: 12px 0 0;
|
|
628
|
+
border-top: 1px solid #e1e4e8;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
.violations-toggle-btn {
|
|
632
|
+
padding: 4px 12px;
|
|
633
|
+
border: 1px solid #d0d7de;
|
|
634
|
+
border-radius: 4px;
|
|
635
|
+
background: none;
|
|
636
|
+
cursor: pointer;
|
|
637
|
+
font-size: 12px;
|
|
638
|
+
color: #586069;
|
|
639
|
+
transition: all 0.2s;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
.violations-toggle-btn:hover {
|
|
643
|
+
background: #f6f8fa;
|
|
644
|
+
color: #24292e;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
.violations-table {
|
|
648
|
+
width: 100%;
|
|
649
|
+
border-collapse: collapse;
|
|
650
|
+
font-size: 13px;
|
|
651
|
+
margin-top: 10px;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
.violations-table th {
|
|
655
|
+
background: #f6f8fa;
|
|
656
|
+
text-align: left;
|
|
657
|
+
padding: 8px 12px;
|
|
658
|
+
border-bottom: 2px solid #d0d7de;
|
|
659
|
+
font-weight: 600;
|
|
660
|
+
color: #24292e;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
.violations-table td {
|
|
664
|
+
padding: 8px 12px;
|
|
665
|
+
border-bottom: 1px solid #e1e4e8;
|
|
666
|
+
color: #24292e;
|
|
667
|
+
vertical-align: top;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
.violations-table tr:hover td {
|
|
671
|
+
background: #f6f8fa;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
.violation-rule-badge {
|
|
675
|
+
display: inline-block;
|
|
676
|
+
padding: 2px 8px;
|
|
677
|
+
border-radius: 10px;
|
|
678
|
+
font-size: 11px;
|
|
679
|
+
font-weight: 600;
|
|
680
|
+
background: #fff3cd;
|
|
681
|
+
color: #856404;
|
|
682
|
+
white-space: nowrap;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
.violation-value {
|
|
686
|
+
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
|
|
687
|
+
font-size: 12px;
|
|
688
|
+
background: #f6f8fa;
|
|
689
|
+
padding: 2px 6px;
|
|
690
|
+
border-radius: 3px;
|
|
691
|
+
border: 1px solid #e1e4e8;
|
|
692
|
+
}
|
|
620
693
|
`;
|
|
621
694
|
exports.TAB_SCRIPT = String.raw `
|
|
622
695
|
// Tab switching
|
|
@@ -915,6 +988,18 @@ exports.TAB_SCRIPT = String.raw `
|
|
|
915
988
|
});
|
|
916
989
|
}
|
|
917
990
|
|
|
991
|
+
// Violations section toggle
|
|
992
|
+
const violationsToggleBtn = document.getElementById('violations-toggle-btn');
|
|
993
|
+
const violationsContent = document.getElementById('violations-content');
|
|
994
|
+
if (violationsToggleBtn && violationsContent) {
|
|
995
|
+
violationsToggleBtn.addEventListener('click', () => {
|
|
996
|
+
const isHidden = violationsContent.style.display === 'none';
|
|
997
|
+
violationsContent.style.display = isHidden ? 'block' : 'none';
|
|
998
|
+
const count = violationsToggleBtn.textContent.match(/\d+/)?.[0] || '0';
|
|
999
|
+
violationsToggleBtn.textContent = isHidden ? 'Hide Violations (' + count + ')' : 'Show Violations (' + count + ')';
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
|
|
918
1003
|
// Synchronized horizontal scrolling for side-by-side diff panels
|
|
919
1004
|
document.querySelectorAll('.d2h-files-diff').forEach(container => {
|
|
920
1005
|
const panels = container.querySelectorAll('.d2h-file-side-diff');
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import { FileDiffResult } from '../fileDiff';
|
|
2
|
+
export interface HtmlStopRuleViolation {
|
|
3
|
+
file: string;
|
|
4
|
+
rule: {
|
|
5
|
+
type: string;
|
|
6
|
+
path?: string;
|
|
7
|
+
};
|
|
8
|
+
path: string;
|
|
9
|
+
oldValue: unknown;
|
|
10
|
+
updatedValue: unknown;
|
|
11
|
+
message: string;
|
|
12
|
+
}
|
|
2
13
|
export interface ReportMetadata {
|
|
3
14
|
timestamp: string;
|
|
4
15
|
source: string;
|
|
@@ -14,4 +25,4 @@ export interface DiffStats {
|
|
|
14
25
|
removed: number;
|
|
15
26
|
}>;
|
|
16
27
|
}
|
|
17
|
-
export declare const generateHtmlTemplate: (diffResult: FileDiffResult, formattedFiles: string[], trulyUnchangedFiles: string[], metadata: ReportMetadata, changedSections: string[], changedFileIds?: Map<string, string>, addedSections?: string[], addedFileIds?: Map<string, string>, diffStats?: DiffStats) => string;
|
|
28
|
+
export declare const generateHtmlTemplate: (diffResult: FileDiffResult, formattedFiles: string[], trulyUnchangedFiles: string[], metadata: ReportMetadata, changedSections: string[], changedFileIds?: Map<string, string>, addedSections?: string[], addedFileIds?: Map<string, string>, diffStats?: DiffStats, stopRuleViolations?: HtmlStopRuleViolation[]) => string;
|
|
@@ -4,6 +4,46 @@ exports.generateHtmlTemplate = void 0;
|
|
|
4
4
|
const htmlStyles_1 = require("./htmlStyles");
|
|
5
5
|
const treeBuilder_1 = require("./treeBuilder");
|
|
6
6
|
const treeRenderer_1 = require("./treeRenderer");
|
|
7
|
+
const formatViolationValue = (value) => {
|
|
8
|
+
if (value === undefined || value === null)
|
|
9
|
+
return '<span class="violation-value">-</span>';
|
|
10
|
+
return `<span class="violation-value">${(0, treeRenderer_1.escapeHtml)(String(value))}</span>`;
|
|
11
|
+
};
|
|
12
|
+
const renderStopRulesSection = (violations) => {
|
|
13
|
+
if (violations.length === 0)
|
|
14
|
+
return '';
|
|
15
|
+
const rows = violations
|
|
16
|
+
.map((v) => `<tr>
|
|
17
|
+
<td>${(0, treeRenderer_1.escapeHtml)(v.file)}</td>
|
|
18
|
+
<td><span class="violation-rule-badge">${(0, treeRenderer_1.escapeHtml)(v.rule.type)}</span></td>
|
|
19
|
+
<td>${(0, treeRenderer_1.escapeHtml)(v.path)}</td>
|
|
20
|
+
<td>${formatViolationValue(v.oldValue)}</td>
|
|
21
|
+
<td>${formatViolationValue(v.updatedValue)}</td>
|
|
22
|
+
<td>${(0, treeRenderer_1.escapeHtml)(v.message)}</td>
|
|
23
|
+
</tr>`)
|
|
24
|
+
.join('');
|
|
25
|
+
return `
|
|
26
|
+
<div class="violations-section">
|
|
27
|
+
<button class="violations-toggle-btn" id="violations-toggle-btn">Show Violations (${violations.length})</button>
|
|
28
|
+
<div id="violations-content" style="display: none">
|
|
29
|
+
<table class="violations-table">
|
|
30
|
+
<thead>
|
|
31
|
+
<tr>
|
|
32
|
+
<th>File</th>
|
|
33
|
+
<th>Rule</th>
|
|
34
|
+
<th>Path</th>
|
|
35
|
+
<th>Old Value</th>
|
|
36
|
+
<th>New Value</th>
|
|
37
|
+
<th>Message</th>
|
|
38
|
+
</tr>
|
|
39
|
+
</thead>
|
|
40
|
+
<tbody>
|
|
41
|
+
${rows}
|
|
42
|
+
</tbody>
|
|
43
|
+
</table>
|
|
44
|
+
</div>
|
|
45
|
+
</div>`;
|
|
46
|
+
};
|
|
7
47
|
const renderStatsDashboard = (diffStats) => {
|
|
8
48
|
const total = diffStats.totalAdded + diffStats.totalRemoved;
|
|
9
49
|
if (total === 0)
|
|
@@ -31,7 +71,7 @@ const renderStatsDashboard = (diffStats) => {
|
|
|
31
71
|
</div>
|
|
32
72
|
</div>`;
|
|
33
73
|
};
|
|
34
|
-
const generateHtmlTemplate = (diffResult, formattedFiles, trulyUnchangedFiles, metadata, changedSections, changedFileIds = new Map(), addedSections = [], addedFileIds = new Map(), diffStats) => {
|
|
74
|
+
const generateHtmlTemplate = (diffResult, formattedFiles, trulyUnchangedFiles, metadata, changedSections, changedFileIds = new Map(), addedSections = [], addedFileIds = new Map(), diffStats, stopRuleViolations) => {
|
|
35
75
|
const changedFilePaths = diffResult.changedFiles.map((f) => f.path);
|
|
36
76
|
const changedTree = (0, treeBuilder_1.buildFileTree)(changedFilePaths);
|
|
37
77
|
const addedFilePaths = diffResult.addedFiles.map((f) => f.path);
|
|
@@ -48,9 +88,11 @@ const generateHtmlTemplate = (diffResult, formattedFiles, trulyUnchangedFiles, m
|
|
|
48
88
|
];
|
|
49
89
|
const activeCategories = categories.filter((c) => c.count > 0);
|
|
50
90
|
const firstActiveTab = activeCategories[0]?.id ?? 'changed';
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
91
|
+
const violationsBadge = stopRuleViolations && stopRuleViolations.length > 0
|
|
92
|
+
? `<span class="stat violations">${stopRuleViolations.length} Violation${stopRuleViolations.length === 1 ? '' : 's'}</span>`
|
|
93
|
+
: '';
|
|
94
|
+
const summaryBadges = activeCategories.map((c) => `<span class="stat ${c.id}">${c.count} ${c.label}</span>`).join('\n ') +
|
|
95
|
+
(violationsBadge ? `\n ${violationsBadge}` : '');
|
|
54
96
|
const tabButtons = activeCategories
|
|
55
97
|
.map((c) => `<button class="tab${c.id === firstActiveTab ? ' active' : ''}" data-tab="${c.id}">${c.label} (${c.count})</button>`)
|
|
56
98
|
.join('\n ');
|
|
@@ -140,6 +182,7 @@ ${htmlStyles_1.HTML_STYLES}
|
|
|
140
182
|
${summaryBadges}
|
|
141
183
|
</div>
|
|
142
184
|
${diffStats ? renderStatsDashboard(diffStats) : ''}
|
|
185
|
+
${stopRuleViolations && stopRuleViolations.length > 0 ? renderStopRulesSection(stopRuleViolations) : ''}
|
|
143
186
|
</header>
|
|
144
187
|
|
|
145
188
|
<nav class="tabs">
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -7,7 +7,8 @@ export { clearJsonPathCache, getValueAtPath, isFilterSegment, matchesFilter, par
|
|
|
7
7
|
export { isYamlFile } from './fileType';
|
|
8
8
|
export { globalMatcher, PatternMatcher } from './patternMatcher';
|
|
9
9
|
export { generateUnifiedDiff } from './diffGenerator';
|
|
10
|
-
export {
|
|
10
|
+
export type { SemverParts } from './versionChecker';
|
|
11
|
+
export { checkForUpdates, isNewerVersion, isVersionCheckerError, parseVersion, VersionCheckerError } from './versionChecker';
|
|
11
12
|
export { escapeRegex, isYamlFileLoaderError, loadYamlFile, YamlFileLoaderError } from './yamlFileLoader';
|
|
12
13
|
export { isTransformFileLoaderError, loadTransformFile, loadTransformFiles, TransformFileLoaderError } from './transformFileLoader';
|
|
13
14
|
export { isRegexPatternFileLoaderError, loadRegexPatternArray, loadRegexPatternsFromKeys, RegexPatternFileLoaderError } from './regexPatternFileLoader';
|
package/dist/utils/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.parseFilterExpression = exports.isFilterParseError = exports.FilterParseError = exports.filterFileMaps = exports.filterFileMap = exports.fileMatchesFilter = exports.isCommentOnlyContent = exports.shouldPreserveItem = exports.itemMatchesAnyFilter = exports.getApplicableArrayFilters = exports.findMatchingTargetItem = exports.setValueAtPath = exports.getFixedValuesForFile = exports.applyFixedValues = exports.UUID_PATTERN = exports.SEMVER_PATTERN = exports.SEMANTIC_PATTERNS = exports.SEMANTIC_KEYWORDS = exports.PROBLEMATIC_REGEX_CHARS = void 0;
|
|
3
|
+
exports.MAX_EXAMPLES_PER_SUGGESTION = exports.ISO_TIMESTAMP_PATTERN = exports.FILTER_THRESHOLDS = exports.CONSTRAINT_FIELD_NAMES = exports.CONFIDENCE_DEFAULTS = exports.ARRAY_KEY_FIELDS = exports.ANTONYM_PAIRS = exports.isYamlSeq = exports.isYamlMap = exports.isYamlCollection = exports.isScalar = exports.extractScalarValue = exports.extractKeyValue = exports.validateVersionString = exports.applyRegexRulesSequentially = exports.validateTargetedRegex = exports.validatePathlessRegex = exports.getAllValuesRecursive = exports.RegexPatternFileLoaderError = exports.loadRegexPatternsFromKeys = exports.loadRegexPatternArray = exports.isRegexPatternFileLoaderError = exports.TransformFileLoaderError = exports.loadTransformFiles = exports.loadTransformFile = exports.isTransformFileLoaderError = exports.YamlFileLoaderError = exports.loadYamlFile = exports.isYamlFileLoaderError = exports.escapeRegex = exports.VersionCheckerError = exports.parseVersion = exports.isVersionCheckerError = exports.isNewerVersion = exports.checkForUpdates = exports.generateUnifiedDiff = exports.PatternMatcher = exports.globalMatcher = exports.isYamlFile = exports.parseJsonPath = exports.parseFilterSegment = exports.matchesFilter = exports.isFilterSegment = exports.getValueAtPath = exports.clearJsonPathCache = exports.serializeForDiff = exports.normalizeForComparison = exports.deepEqual = exports.createErrorTypeGuard = exports.createErrorClass = void 0;
|
|
4
|
+
exports.parseFilterExpression = exports.isFilterParseError = exports.FilterParseError = exports.filterFileMaps = exports.filterFileMap = exports.fileMatchesFilter = exports.isCommentOnlyContent = exports.shouldPreserveItem = exports.itemMatchesAnyFilter = exports.getApplicableArrayFilters = exports.findMatchingTargetItem = exports.setValueAtPath = exports.getFixedValuesForFile = exports.applyFixedValues = exports.UUID_PATTERN = exports.SEMVER_PATTERN = exports.SEMANTIC_PATTERNS = exports.SEMANTIC_KEYWORDS = exports.PROBLEMATIC_REGEX_CHARS = exports.NUMERIC_MIN_MULTIPLIER = exports.NUMERIC_MIN_FLOOR = void 0;
|
|
5
5
|
var errors_1 = require("./errors");
|
|
6
6
|
Object.defineProperty(exports, "createErrorClass", { enumerable: true, get: function () { return errors_1.createErrorClass; } });
|
|
7
7
|
Object.defineProperty(exports, "createErrorTypeGuard", { enumerable: true, get: function () { return errors_1.createErrorTypeGuard; } });
|
|
@@ -26,7 +26,9 @@ var diffGenerator_1 = require("./diffGenerator");
|
|
|
26
26
|
Object.defineProperty(exports, "generateUnifiedDiff", { enumerable: true, get: function () { return diffGenerator_1.generateUnifiedDiff; } });
|
|
27
27
|
var versionChecker_1 = require("./versionChecker");
|
|
28
28
|
Object.defineProperty(exports, "checkForUpdates", { enumerable: true, get: function () { return versionChecker_1.checkForUpdates; } });
|
|
29
|
+
Object.defineProperty(exports, "isNewerVersion", { enumerable: true, get: function () { return versionChecker_1.isNewerVersion; } });
|
|
29
30
|
Object.defineProperty(exports, "isVersionCheckerError", { enumerable: true, get: function () { return versionChecker_1.isVersionCheckerError; } });
|
|
31
|
+
Object.defineProperty(exports, "parseVersion", { enumerable: true, get: function () { return versionChecker_1.parseVersion; } });
|
|
30
32
|
Object.defineProperty(exports, "VersionCheckerError", { enumerable: true, get: function () { return versionChecker_1.VersionCheckerError; } });
|
|
31
33
|
var yamlFileLoader_1 = require("./yamlFileLoader");
|
|
32
34
|
Object.defineProperty(exports, "escapeRegex", { enumerable: true, get: function () { return yamlFileLoader_1.escapeRegex; } });
|
|
@@ -16,5 +16,12 @@ declare const VersionCheckerErrorClass: {
|
|
|
16
16
|
export declare class VersionCheckerError extends VersionCheckerErrorClass {
|
|
17
17
|
}
|
|
18
18
|
export declare const isVersionCheckerError: (error: unknown) => error is VersionCheckerError;
|
|
19
|
+
export interface SemverParts {
|
|
20
|
+
major: number;
|
|
21
|
+
minor: number;
|
|
22
|
+
patch: number;
|
|
23
|
+
}
|
|
24
|
+
export declare const parseVersion: (version: string) => SemverParts | undefined;
|
|
25
|
+
export declare const isNewerVersion: (current: string, latest: string) => boolean;
|
|
19
26
|
export declare const checkForUpdates: (currentVersion: string) => Promise<void>;
|
|
20
27
|
export {};
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.checkForUpdates = exports.isVersionCheckerError = exports.VersionCheckerError = void 0;
|
|
6
|
+
exports.checkForUpdates = exports.isNewerVersion = exports.parseVersion = exports.isVersionCheckerError = exports.VersionCheckerError = void 0;
|
|
7
7
|
const node_https_1 = __importDefault(require("node:https"));
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
9
|
const package_json_1 = __importDefault(require("../../package.json"));
|
|
@@ -44,9 +44,10 @@ const parseVersion = (version) => {
|
|
|
44
44
|
patch: Number.parseInt(match[3], 10)
|
|
45
45
|
};
|
|
46
46
|
};
|
|
47
|
+
exports.parseVersion = parseVersion;
|
|
47
48
|
const isNewerVersion = (current, latest) => {
|
|
48
|
-
const currentParts = parseVersion(current);
|
|
49
|
-
const latestParts = parseVersion(latest);
|
|
49
|
+
const currentParts = (0, exports.parseVersion)(current);
|
|
50
|
+
const latestParts = (0, exports.parseVersion)(latest);
|
|
50
51
|
if (!currentParts || !latestParts)
|
|
51
52
|
return false;
|
|
52
53
|
if (latestParts.major > currentParts.major)
|
|
@@ -59,6 +60,7 @@ const isNewerVersion = (current, latest) => {
|
|
|
59
60
|
return false;
|
|
60
61
|
return latestParts.patch > currentParts.patch;
|
|
61
62
|
};
|
|
63
|
+
exports.isNewerVersion = isNewerVersion;
|
|
62
64
|
const fetchLatestVersion = (packageName, timeout) => {
|
|
63
65
|
return new Promise((resolve, reject) => {
|
|
64
66
|
const url = `https://registry.npmjs.org/${packageName}/latest`;
|
|
@@ -108,7 +110,7 @@ const checkForUpdates = async (currentVersion) => {
|
|
|
108
110
|
return;
|
|
109
111
|
try {
|
|
110
112
|
const latestVersion = await fetchLatestVersion('helm-env-delta', 3000);
|
|
111
|
-
if (isNewerVersion(currentVersion, latestVersion))
|
|
113
|
+
if ((0, exports.isNewerVersion)(currentVersion, latestVersion))
|
|
112
114
|
displayUpdateNotification(currentVersion, latestVersion);
|
|
113
115
|
}
|
|
114
116
|
catch {
|
package/dist/yamlFormatter.js
CHANGED
|
@@ -20,12 +20,16 @@ exports.YamlFormatterError = (0, errors_1.createErrorClass)('YAML Formatter Erro
|
|
|
20
20
|
exports.isYamlFormatterError = (0, errors_1.createErrorTypeGuard)(exports.YamlFormatterError);
|
|
21
21
|
const getFormattingRules = (filePath, outputFormat) => {
|
|
22
22
|
const keyOrders = [];
|
|
23
|
+
const keySort = [];
|
|
23
24
|
const arraySort = [];
|
|
24
25
|
const quoteValues = [];
|
|
25
26
|
const allPatterns = new Set();
|
|
26
27
|
if (outputFormat?.keyOrders)
|
|
27
28
|
for (const pattern of Object.keys(outputFormat.keyOrders))
|
|
28
29
|
allPatterns.add(pattern);
|
|
30
|
+
if (outputFormat?.keySort)
|
|
31
|
+
for (const pattern of Object.keys(outputFormat.keySort))
|
|
32
|
+
allPatterns.add(pattern);
|
|
29
33
|
if (outputFormat?.arraySort)
|
|
30
34
|
for (const pattern of Object.keys(outputFormat.arraySort))
|
|
31
35
|
allPatterns.add(pattern);
|
|
@@ -38,6 +42,9 @@ const getFormattingRules = (filePath, outputFormat) => {
|
|
|
38
42
|
const keyOrder = outputFormat?.keyOrders?.[pattern];
|
|
39
43
|
if (keyOrder)
|
|
40
44
|
keyOrders.push(keyOrder);
|
|
45
|
+
const keySortRule = outputFormat?.keySort?.[pattern];
|
|
46
|
+
if (keySortRule)
|
|
47
|
+
keySort.push(keySortRule);
|
|
41
48
|
const arrayRule = outputFormat?.arraySort?.[pattern];
|
|
42
49
|
if (arrayRule)
|
|
43
50
|
arraySort.push(arrayRule);
|
|
@@ -45,7 +52,7 @@ const getFormattingRules = (filePath, outputFormat) => {
|
|
|
45
52
|
if (quoteValue)
|
|
46
53
|
quoteValues.push(quoteValue);
|
|
47
54
|
}
|
|
48
|
-
return { keyOrders, arraySort, quoteValues };
|
|
55
|
+
return { keyOrders, keySort, arraySort, quoteValues };
|
|
49
56
|
};
|
|
50
57
|
const preserveMultilineStrings = (yamlDocument) => {
|
|
51
58
|
if (!yamlDocument.contents)
|
|
@@ -81,6 +88,8 @@ const formatYaml = (content, filePath, outputFormat) => {
|
|
|
81
88
|
const rules = getFormattingRules(filePath, outputFormat);
|
|
82
89
|
if (rules.keyOrders.length > 0)
|
|
83
90
|
applyKeyOrdering(yamlDocument, rules.keyOrders);
|
|
91
|
+
if (rules.keySort.length > 0)
|
|
92
|
+
applyKeySort(yamlDocument, rules.keySort);
|
|
84
93
|
if (rules.arraySort.length > 0)
|
|
85
94
|
applyArraySorting(yamlDocument, rules.arraySort);
|
|
86
95
|
if (rules.quoteValues.length > 0)
|
|
@@ -171,6 +180,43 @@ const applyOrderingToMap = (map, currentPath, orderHierarchy) => {
|
|
|
171
180
|
}
|
|
172
181
|
}
|
|
173
182
|
};
|
|
183
|
+
const applyKeySort = (yamlDocument, sortRules) => {
|
|
184
|
+
if (sortRules.length === 0)
|
|
185
|
+
return;
|
|
186
|
+
const allRules = sortRules.flat();
|
|
187
|
+
for (const rule of allRules) {
|
|
188
|
+
const pathParts = (0, jsonPath_1.parseJsonPath)(rule.path);
|
|
189
|
+
if (pathParts.length === 0)
|
|
190
|
+
continue;
|
|
191
|
+
if (yamlDocument.contents)
|
|
192
|
+
traverseAndSortKeys(yamlDocument.contents, [], pathParts);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
const traverseAndSortKeys = (node, currentPath, targetPath) => {
|
|
196
|
+
if (!node || typeof node !== 'object')
|
|
197
|
+
return;
|
|
198
|
+
if (matchPath(currentPath, targetPath)) {
|
|
199
|
+
if ((0, yamlTypeGuards_1.isYamlMap)(node))
|
|
200
|
+
sortMapKeysAlphabetically(node);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if ((0, yamlTypeGuards_1.isYamlMap)(node))
|
|
204
|
+
for (const item of node.items) {
|
|
205
|
+
const keyValue = (0, yamlTypeGuards_1.extractKeyValue)(item);
|
|
206
|
+
if (keyValue && item.value) {
|
|
207
|
+
const childPath = [...currentPath, keyValue];
|
|
208
|
+
if (isPotentialMatch(childPath, targetPath))
|
|
209
|
+
traverseAndSortKeys(item.value, childPath, targetPath);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
const sortMapKeysAlphabetically = (map) => {
|
|
214
|
+
map.items.sort((a, b) => {
|
|
215
|
+
const aKey = a.key && typeof a.key === 'object' && 'value' in a.key ? String(a.key.value) : '';
|
|
216
|
+
const bKey = b.key && typeof b.key === 'object' && 'value' in b.key ? String(b.key.value) : '';
|
|
217
|
+
return aKey.localeCompare(bKey);
|
|
218
|
+
});
|
|
219
|
+
};
|
|
174
220
|
const applyValueQuoting = (yamlDocument, quoteLists) => {
|
|
175
221
|
if (quoteLists.length === 0)
|
|
176
222
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "helm-env-delta",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "HelmEnvDelta – environment-aware YAML delta and sync for GitOps",
|
|
5
5
|
"author": "BCsabaEngine",
|
|
6
6
|
"license": "ISC",
|
|
@@ -68,15 +68,15 @@
|
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@types/hogan.js": "^3.0.5",
|
|
71
|
-
"@types/node": "^25.2.
|
|
71
|
+
"@types/node": "^25.2.3",
|
|
72
72
|
"@types/picomatch": "^4.0.2",
|
|
73
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
74
|
-
"@typescript-eslint/parser": "^8.
|
|
73
|
+
"@typescript-eslint/eslint-plugin": "^8.55.0",
|
|
74
|
+
"@typescript-eslint/parser": "^8.55.0",
|
|
75
75
|
"@vitest/coverage-v8": "^4.0.18",
|
|
76
76
|
"eslint": "^9.39.2",
|
|
77
77
|
"eslint-config-prettier": "^10.1.8",
|
|
78
78
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
79
|
-
"eslint-plugin-unicorn": "^
|
|
79
|
+
"eslint-plugin-unicorn": "^63.0.0",
|
|
80
80
|
"prettier": "^3.8.1",
|
|
81
81
|
"tsx": "^4.21.0",
|
|
82
82
|
"typescript": "^5.9.3",
|