@memberjunction/metadata-sync 2.51.0 → 2.53.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 +138 -1
- package/dist/commands/file-reset/index.d.ts +15 -0
- package/dist/commands/file-reset/index.js +221 -0
- package/dist/commands/file-reset/index.js.map +1 -0
- package/dist/commands/push/index.d.ts +21 -0
- package/dist/commands/push/index.js +502 -42
- package/dist/commands/push/index.js.map +1 -1
- package/dist/commands/watch/index.js +39 -1
- package/dist/commands/watch/index.js.map +1 -1
- package/dist/config.d.ts +30 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/file-backup-manager.d.ts +90 -0
- package/dist/lib/file-backup-manager.js +186 -0
- package/dist/lib/file-backup-manager.js.map +1 -0
- package/dist/lib/provider-utils.d.ts +4 -2
- package/dist/lib/provider-utils.js +26 -4
- package/dist/lib/provider-utils.js.map +1 -1
- package/dist/lib/sync-engine.d.ts +4 -1
- package/dist/lib/sync-engine.js +50 -16
- package/dist/lib/sync-engine.js.map +1 -1
- package/dist/services/FormattingService.d.ts +1 -0
- package/dist/services/FormattingService.js +4 -1
- package/dist/services/FormattingService.js.map +1 -1
- package/dist/services/ValidationService.d.ts +9 -0
- package/dist/services/ValidationService.js +268 -70
- package/dist/services/ValidationService.js.map +1 -1
- package/dist/types/validation.d.ts +6 -2
- package/dist/types/validation.js.map +1 -1
- package/oclif.manifest.json +114 -45
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -718,14 +718,27 @@ Examples:
|
|
|
718
718
|
### @lookup: References (ENHANCED)
|
|
719
719
|
Enable entity relationships using human-readable values:
|
|
720
720
|
- Basic syntax: `@lookup:EntityName.FieldName=Value`
|
|
721
|
+
- Multi-field syntax: `@lookup:EntityName.Field1=Value1&Field2=Value2`
|
|
721
722
|
- Auto-create syntax: `@lookup:EntityName.FieldName=Value?create`
|
|
722
723
|
- With additional fields: `@lookup:EntityName.FieldName=Value?create&Field2=Value2`
|
|
723
724
|
|
|
724
725
|
Examples:
|
|
725
|
-
- `@lookup:AI Prompt Types.Name=Chat` -
|
|
726
|
+
- `@lookup:AI Prompt Types.Name=Chat` - Single field lookup, fails if not found
|
|
727
|
+
- `@lookup:Users.Email=john@example.com&Department=Sales` - Multi-field lookup for precise matching
|
|
726
728
|
- `@lookup:AI Prompt Categories.Name=Examples?create` - Creates if missing
|
|
727
729
|
- `@lookup:AI Prompt Categories.Name=Examples?create&Description=Example prompts` - Creates with description
|
|
728
730
|
|
|
731
|
+
#### Multi-Field Lookups (NEW)
|
|
732
|
+
When you need to match records based on multiple criteria, use the multi-field syntax:
|
|
733
|
+
```json
|
|
734
|
+
{
|
|
735
|
+
"CategoryID": "@lookup:AI Prompt Categories.Name=Actions&Status=Active",
|
|
736
|
+
"ManagerID": "@lookup:Users.Email=manager@company.com&Department=Engineering&Status=Active"
|
|
737
|
+
}
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
This ensures you get the exact record you want when multiple records might have the same value in a single field.
|
|
741
|
+
|
|
729
742
|
### @parent: References (NEW)
|
|
730
743
|
Reference fields from the immediate parent entity in embedded collections:
|
|
731
744
|
- `@parent:ID` - Get the parent's ID field
|
|
@@ -818,6 +831,9 @@ mj-sync validate --verbose
|
|
|
818
831
|
# Validate with JSON output for CI/CD
|
|
819
832
|
mj-sync validate --format=json
|
|
820
833
|
|
|
834
|
+
# Save validation report to markdown file
|
|
835
|
+
mj-sync validate --save-report
|
|
836
|
+
|
|
821
837
|
# Initialize a directory for metadata sync
|
|
822
838
|
mj-sync init
|
|
823
839
|
|
|
@@ -898,6 +914,53 @@ Directory order is configured in the root-level `.mj-sync.json` file only (not i
|
|
|
898
914
|
2. **Categories → Items**: Create category records before items that reference them
|
|
899
915
|
3. **Parent → Child**: Process parent entities before child entities with foreign key dependencies
|
|
900
916
|
|
|
917
|
+
### Ignore Directories
|
|
918
|
+
|
|
919
|
+
The MetadataSync tool supports ignoring specific directories during push/pull operations. This is useful for:
|
|
920
|
+
- Excluding output or example directories from processing
|
|
921
|
+
- Skipping temporary or build directories
|
|
922
|
+
- Organizing support files without them being processed as metadata
|
|
923
|
+
|
|
924
|
+
#### Configuration
|
|
925
|
+
|
|
926
|
+
Ignore directories are configured in `.mj-sync.json` files and are **cumulative** through the directory hierarchy:
|
|
927
|
+
|
|
928
|
+
```json
|
|
929
|
+
{
|
|
930
|
+
"version": "1.0.0",
|
|
931
|
+
"ignoreDirectories": [
|
|
932
|
+
"output",
|
|
933
|
+
"examples",
|
|
934
|
+
"templates"
|
|
935
|
+
]
|
|
936
|
+
}
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
#### How It Works
|
|
940
|
+
|
|
941
|
+
- **Cumulative Inheritance**: Each directory inherits ignore patterns from its parent directories
|
|
942
|
+
- **Relative Paths**: Directory names are relative to the location of the `.mj-sync.json` file
|
|
943
|
+
- **Simple Patterns**: Supports exact directory names (e.g., "output", "temp")
|
|
944
|
+
- **Additive**: Child directories can add their own ignore patterns to parent patterns
|
|
945
|
+
|
|
946
|
+
#### Example
|
|
947
|
+
|
|
948
|
+
```
|
|
949
|
+
metadata/.mj-sync.json → ignoreDirectories: ["output", "temp"]
|
|
950
|
+
├── prompts/.mj-sync.json → ignoreDirectories: ["examples"]
|
|
951
|
+
│ ├── output/ → IGNORED (from root)
|
|
952
|
+
│ ├── examples/ → IGNORED (from prompts)
|
|
953
|
+
│ └── production/.mj-sync.json → ignoreDirectories: ["drafts"]
|
|
954
|
+
│ ├── drafts/ → IGNORED (from production)
|
|
955
|
+
│ └── output/ → IGNORED (inherited from root)
|
|
956
|
+
```
|
|
957
|
+
|
|
958
|
+
In this example:
|
|
959
|
+
- Root level ignores "output" and "temp" everywhere
|
|
960
|
+
- Prompts directory adds "examples" to the ignore list
|
|
961
|
+
- Production subdirectory further adds "drafts"
|
|
962
|
+
- All patterns are cumulative, so production inherits all parent ignores
|
|
963
|
+
|
|
901
964
|
### SQL Logging (NEW)
|
|
902
965
|
|
|
903
966
|
The MetadataSync tool now supports SQL logging for capturing all database operations during push commands. This feature is useful for:
|
|
@@ -973,6 +1036,75 @@ Migration files include:
|
|
|
973
1036
|
|
|
974
1037
|
The SQL logging runs in parallel with the actual database operations, ensuring minimal performance impact while capturing all SQL statements for review and potential migration use.
|
|
975
1038
|
|
|
1039
|
+
### User Role Validation (NEW)
|
|
1040
|
+
|
|
1041
|
+
MetadataSync now supports validating UserID fields against specific roles in the MemberJunction system. This ensures that only users with appropriate roles can be referenced in metadata files.
|
|
1042
|
+
|
|
1043
|
+
#### Configuration
|
|
1044
|
+
|
|
1045
|
+
Add the `userRoleValidation` configuration to your root `.mj-sync.json` file:
|
|
1046
|
+
|
|
1047
|
+
```json
|
|
1048
|
+
{
|
|
1049
|
+
"version": "1.0.0",
|
|
1050
|
+
"userRoleValidation": {
|
|
1051
|
+
"enabled": true,
|
|
1052
|
+
"allowedRoles": [
|
|
1053
|
+
"Administrator",
|
|
1054
|
+
"Developer",
|
|
1055
|
+
"Content Manager"
|
|
1056
|
+
],
|
|
1057
|
+
"allowUsersWithoutRoles": false
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
```
|
|
1061
|
+
|
|
1062
|
+
#### Configuration Options
|
|
1063
|
+
|
|
1064
|
+
| Option | Type | Default | Description |
|
|
1065
|
+
|--------|------|---------|-------------|
|
|
1066
|
+
| `enabled` | boolean | false | Enable user role validation for UserID fields |
|
|
1067
|
+
| `allowedRoles` | string[] | [] | List of role names that are allowed |
|
|
1068
|
+
| `allowUsersWithoutRoles` | boolean | false | Allow users without any assigned roles |
|
|
1069
|
+
|
|
1070
|
+
#### How It Works
|
|
1071
|
+
|
|
1072
|
+
1. During validation, all user roles are loaded from the database and cached
|
|
1073
|
+
2. For each UserID field in metadata files, the validator checks:
|
|
1074
|
+
- If the user exists and has roles assigned
|
|
1075
|
+
- If the user has at least one of the allowed roles
|
|
1076
|
+
3. Validation fails if:
|
|
1077
|
+
- A UserID references a user without any roles (unless `allowUsersWithoutRoles` is true)
|
|
1078
|
+
- A UserID references a user whose roles are not in the `allowedRoles` list
|
|
1079
|
+
|
|
1080
|
+
#### Example
|
|
1081
|
+
|
|
1082
|
+
Given a metadata file with a UserID field:
|
|
1083
|
+
|
|
1084
|
+
```json
|
|
1085
|
+
{
|
|
1086
|
+
"fields": {
|
|
1087
|
+
"Name": "Admin Action",
|
|
1088
|
+
"UserID": "user-123"
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
The validation will:
|
|
1094
|
+
1. Check if user-123 exists in the system
|
|
1095
|
+
2. Verify that user-123 has one of the allowed roles
|
|
1096
|
+
3. Report an error if the user doesn't have appropriate roles
|
|
1097
|
+
|
|
1098
|
+
#### Error Messages
|
|
1099
|
+
|
|
1100
|
+
```
|
|
1101
|
+
✗ UserID 'user-123' does not have any assigned roles
|
|
1102
|
+
Suggestion: User must have one of these roles: Administrator, Developer
|
|
1103
|
+
|
|
1104
|
+
✗ UserID 'user-456' has roles [Viewer] but none are in allowed list
|
|
1105
|
+
Suggestion: Allowed roles: Administrator, Developer, Content Manager
|
|
1106
|
+
```
|
|
1107
|
+
|
|
976
1108
|
### Root Configuration (metadata/.mj-sync.json)
|
|
977
1109
|
```json
|
|
978
1110
|
{
|
|
@@ -990,6 +1122,11 @@ The SQL logging runs in parallel with the actual database operations, ensuring m
|
|
|
990
1122
|
"outputDirectory": "./sql_logging",
|
|
991
1123
|
"formatAsMigration": false
|
|
992
1124
|
},
|
|
1125
|
+
"userRoleValidation": {
|
|
1126
|
+
"enabled": true,
|
|
1127
|
+
"allowedRoles": ["Administrator", "Developer"],
|
|
1128
|
+
"allowUsersWithoutRoles": false
|
|
1129
|
+
},
|
|
993
1130
|
"watch": {
|
|
994
1131
|
"debounceMs": 1000,
|
|
995
1132
|
"ignorePatterns": ["*.tmp", "*.bak"]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class FileReset extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
sections: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
7
|
+
'dry-run': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
'no-backup': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
yes: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
};
|
|
12
|
+
run(): Promise<void>;
|
|
13
|
+
private countSections;
|
|
14
|
+
private removeSections;
|
|
15
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const core_1 = require("@oclif/core");
|
|
7
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const prompts_1 = require("@inquirer/prompts");
|
|
10
|
+
const ora_classic_1 = __importDefault(require("ora-classic"));
|
|
11
|
+
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
12
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
13
|
+
const config_1 = require("../../config");
|
|
14
|
+
const config_manager_1 = require("../../lib/config-manager");
|
|
15
|
+
class FileReset extends core_1.Command {
|
|
16
|
+
static description = 'Remove primaryKey and sync sections from metadata JSON files';
|
|
17
|
+
static examples = [
|
|
18
|
+
`<%= config.bin %> <%= command.id %>`,
|
|
19
|
+
`<%= config.bin %> <%= command.id %> --sections=primaryKey`,
|
|
20
|
+
`<%= config.bin %> <%= command.id %> --sections=sync`,
|
|
21
|
+
`<%= config.bin %> <%= command.id %> --dry-run`,
|
|
22
|
+
`<%= config.bin %> <%= command.id %> --no-backup`,
|
|
23
|
+
`<%= config.bin %> <%= command.id %> --yes`,
|
|
24
|
+
];
|
|
25
|
+
static flags = {
|
|
26
|
+
sections: core_1.Flags.string({
|
|
27
|
+
description: 'Which sections to remove',
|
|
28
|
+
options: ['both', 'primaryKey', 'sync'],
|
|
29
|
+
default: 'both',
|
|
30
|
+
}),
|
|
31
|
+
'dry-run': core_1.Flags.boolean({
|
|
32
|
+
description: 'Show what would be removed without actually removing'
|
|
33
|
+
}),
|
|
34
|
+
'no-backup': core_1.Flags.boolean({
|
|
35
|
+
description: 'Skip creating backup files'
|
|
36
|
+
}),
|
|
37
|
+
yes: core_1.Flags.boolean({
|
|
38
|
+
char: 'y',
|
|
39
|
+
description: 'Skip confirmation prompt'
|
|
40
|
+
}),
|
|
41
|
+
verbose: core_1.Flags.boolean({
|
|
42
|
+
char: 'v',
|
|
43
|
+
description: 'Show detailed output'
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
46
|
+
async run() {
|
|
47
|
+
const { flags } = await this.parse(FileReset);
|
|
48
|
+
const spinner = (0, ora_classic_1.default)();
|
|
49
|
+
try {
|
|
50
|
+
// Load sync config
|
|
51
|
+
const syncConfig = await (0, config_1.loadSyncConfig)(config_manager_1.configManager.getOriginalCwd());
|
|
52
|
+
if (!syncConfig) {
|
|
53
|
+
this.error('No .mj-sync.json found in current directory');
|
|
54
|
+
}
|
|
55
|
+
// Find all metadata JSON files
|
|
56
|
+
spinner.start('Finding metadata files');
|
|
57
|
+
const pattern = syncConfig.filePattern || '.*.json';
|
|
58
|
+
const files = await (0, fast_glob_1.default)(pattern, {
|
|
59
|
+
cwd: config_manager_1.configManager.getOriginalCwd(),
|
|
60
|
+
absolute: true,
|
|
61
|
+
ignore: ['.mj-sync.json', '.mj-folder.json'],
|
|
62
|
+
});
|
|
63
|
+
spinner.stop();
|
|
64
|
+
if (files.length === 0) {
|
|
65
|
+
this.log('No metadata files found');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
this.log(`Found ${files.length} metadata file${files.length === 1 ? '' : 's'}`);
|
|
69
|
+
// Count what will be removed
|
|
70
|
+
let filesWithPrimaryKey = 0;
|
|
71
|
+
let filesWithSync = 0;
|
|
72
|
+
let totalPrimaryKeys = 0;
|
|
73
|
+
let totalSyncs = 0;
|
|
74
|
+
for (const file of files) {
|
|
75
|
+
const content = await fs_extra_1.default.readJson(file);
|
|
76
|
+
const stats = this.countSections(content);
|
|
77
|
+
if (stats.primaryKeyCount > 0) {
|
|
78
|
+
filesWithPrimaryKey++;
|
|
79
|
+
totalPrimaryKeys += stats.primaryKeyCount;
|
|
80
|
+
}
|
|
81
|
+
if (stats.syncCount > 0) {
|
|
82
|
+
filesWithSync++;
|
|
83
|
+
totalSyncs += stats.syncCount;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Show what will be removed
|
|
87
|
+
this.log('');
|
|
88
|
+
if (flags.sections === 'both' || flags.sections === 'primaryKey') {
|
|
89
|
+
this.log(`Will remove ${chalk_1.default.yellow(totalPrimaryKeys)} primaryKey section${totalPrimaryKeys === 1 ? '' : 's'} from ${chalk_1.default.yellow(filesWithPrimaryKey)} file${filesWithPrimaryKey === 1 ? '' : 's'}`);
|
|
90
|
+
}
|
|
91
|
+
if (flags.sections === 'both' || flags.sections === 'sync') {
|
|
92
|
+
this.log(`Will remove ${chalk_1.default.yellow(totalSyncs)} sync section${totalSyncs === 1 ? '' : 's'} from ${chalk_1.default.yellow(filesWithSync)} file${filesWithSync === 1 ? '' : 's'}`);
|
|
93
|
+
}
|
|
94
|
+
if (flags['dry-run']) {
|
|
95
|
+
this.log('');
|
|
96
|
+
this.log(chalk_1.default.cyan('Dry run mode - no files will be modified'));
|
|
97
|
+
if (flags.verbose) {
|
|
98
|
+
this.log('');
|
|
99
|
+
for (const file of files) {
|
|
100
|
+
const content = await fs_extra_1.default.readJson(file);
|
|
101
|
+
const stats = this.countSections(content);
|
|
102
|
+
if (stats.primaryKeyCount > 0 || stats.syncCount > 0) {
|
|
103
|
+
this.log(`${path_1.default.relative(config_manager_1.configManager.getOriginalCwd(), file)}:`);
|
|
104
|
+
if (stats.primaryKeyCount > 0) {
|
|
105
|
+
this.log(` - ${stats.primaryKeyCount} primaryKey section${stats.primaryKeyCount === 1 ? '' : 's'}`);
|
|
106
|
+
}
|
|
107
|
+
if (stats.syncCount > 0) {
|
|
108
|
+
this.log(` - ${stats.syncCount} sync section${stats.syncCount === 1 ? '' : 's'}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
// Confirm before proceeding
|
|
116
|
+
if (!flags.yes) {
|
|
117
|
+
const confirmed = await (0, prompts_1.confirm)({
|
|
118
|
+
message: 'Do you want to proceed?',
|
|
119
|
+
default: false,
|
|
120
|
+
});
|
|
121
|
+
if (!confirmed) {
|
|
122
|
+
this.log('Operation cancelled');
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Process files
|
|
127
|
+
spinner.start('Processing files');
|
|
128
|
+
let processedFiles = 0;
|
|
129
|
+
let modifiedFiles = 0;
|
|
130
|
+
for (const file of files) {
|
|
131
|
+
processedFiles++;
|
|
132
|
+
const content = await fs_extra_1.default.readJson(file);
|
|
133
|
+
const originalContent = JSON.stringify(content);
|
|
134
|
+
// Remove sections
|
|
135
|
+
const cleanedContent = this.removeSections(content, flags.sections);
|
|
136
|
+
// Only write if content changed
|
|
137
|
+
if (JSON.stringify(cleanedContent) !== originalContent) {
|
|
138
|
+
// Create backup if requested
|
|
139
|
+
if (!flags['no-backup']) {
|
|
140
|
+
const backupPath = `${file}.backup`;
|
|
141
|
+
await fs_extra_1.default.writeJson(backupPath, content, { spaces: 2 });
|
|
142
|
+
}
|
|
143
|
+
// Write cleaned content
|
|
144
|
+
await fs_extra_1.default.writeJson(file, cleanedContent, { spaces: 2 });
|
|
145
|
+
modifiedFiles++;
|
|
146
|
+
if (flags.verbose) {
|
|
147
|
+
spinner.stop();
|
|
148
|
+
this.log(`✓ ${path_1.default.relative(config_manager_1.configManager.getOriginalCwd(), file)}`);
|
|
149
|
+
spinner.start('Processing files');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
spinner.stop();
|
|
154
|
+
// Show summary
|
|
155
|
+
this.log('');
|
|
156
|
+
this.log(chalk_1.default.green(`✓ Reset complete`));
|
|
157
|
+
this.log(` Processed: ${processedFiles} file${processedFiles === 1 ? '' : 's'}`);
|
|
158
|
+
this.log(` Modified: ${modifiedFiles} file${modifiedFiles === 1 ? '' : 's'}`);
|
|
159
|
+
if (!flags['no-backup'] && modifiedFiles > 0) {
|
|
160
|
+
this.log(` Backups created: ${modifiedFiles}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
spinner.stop();
|
|
165
|
+
this.error(error instanceof Error ? error.message : String(error));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
countSections(data) {
|
|
169
|
+
let primaryKeyCount = 0;
|
|
170
|
+
let syncCount = 0;
|
|
171
|
+
if (Array.isArray(data)) {
|
|
172
|
+
for (const item of data) {
|
|
173
|
+
const stats = this.countSections(item);
|
|
174
|
+
primaryKeyCount += stats.primaryKeyCount;
|
|
175
|
+
syncCount += stats.syncCount;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
else if (data && typeof data === 'object') {
|
|
179
|
+
if ('primaryKey' in data)
|
|
180
|
+
primaryKeyCount++;
|
|
181
|
+
if ('sync' in data)
|
|
182
|
+
syncCount++;
|
|
183
|
+
// Check related entities
|
|
184
|
+
if (data.relatedEntities) {
|
|
185
|
+
for (const entityData of Object.values(data.relatedEntities)) {
|
|
186
|
+
const stats = this.countSections(entityData);
|
|
187
|
+
primaryKeyCount += stats.primaryKeyCount;
|
|
188
|
+
syncCount += stats.syncCount;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return { primaryKeyCount, syncCount };
|
|
193
|
+
}
|
|
194
|
+
removeSections(data, sections) {
|
|
195
|
+
if (Array.isArray(data)) {
|
|
196
|
+
return data.map(item => this.removeSections(item, sections));
|
|
197
|
+
}
|
|
198
|
+
else if (data && typeof data === 'object') {
|
|
199
|
+
const cleaned = { ...data };
|
|
200
|
+
// Remove specified sections
|
|
201
|
+
if (sections === 'both' || sections === 'primaryKey') {
|
|
202
|
+
delete cleaned.primaryKey;
|
|
203
|
+
}
|
|
204
|
+
if (sections === 'both' || sections === 'sync') {
|
|
205
|
+
delete cleaned.sync;
|
|
206
|
+
}
|
|
207
|
+
// Process related entities
|
|
208
|
+
if (cleaned.relatedEntities) {
|
|
209
|
+
const cleanedRelated = {};
|
|
210
|
+
for (const [entityName, entityData] of Object.entries(cleaned.relatedEntities)) {
|
|
211
|
+
cleanedRelated[entityName] = this.removeSections(entityData, sections);
|
|
212
|
+
}
|
|
213
|
+
cleaned.relatedEntities = cleanedRelated;
|
|
214
|
+
}
|
|
215
|
+
return cleaned;
|
|
216
|
+
}
|
|
217
|
+
return data;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
exports.default = FileReset;
|
|
221
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/file-reset/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { Command, Flags } from '@oclif/core';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport { confirm } from '@inquirer/prompts';\nimport ora from 'ora-classic';\nimport fastGlob from 'fast-glob';\nimport chalk from 'chalk';\nimport { loadSyncConfig } from '../../config';\nimport { configManager } from '../../lib/config-manager';\n\nexport default class FileReset extends Command {\n static description = 'Remove primaryKey and sync sections from metadata JSON files';\n \n static examples = [\n `<%= config.bin %> <%= command.id %>`,\n `<%= config.bin %> <%= command.id %> --sections=primaryKey`,\n `<%= config.bin %> <%= command.id %> --sections=sync`,\n `<%= config.bin %> <%= command.id %> --dry-run`,\n `<%= config.bin %> <%= command.id %> --no-backup`,\n `<%= config.bin %> <%= command.id %> --yes`,\n ];\n \n static flags = {\n sections: Flags.string({\n description: 'Which sections to remove',\n options: ['both', 'primaryKey', 'sync'],\n default: 'both',\n }),\n 'dry-run': Flags.boolean({ \n description: 'Show what would be removed without actually removing' \n }),\n 'no-backup': Flags.boolean({ \n description: 'Skip creating backup files' \n }),\n yes: Flags.boolean({ \n char: 'y', \n description: 'Skip confirmation prompt' \n }),\n verbose: Flags.boolean({ \n char: 'v', \n description: 'Show detailed output' \n }),\n };\n \n async run(): Promise<void> {\n const { flags } = await this.parse(FileReset);\n const spinner = ora();\n \n try {\n // Load sync config\n const syncConfig = await loadSyncConfig(configManager.getOriginalCwd());\n if (!syncConfig) {\n this.error('No .mj-sync.json found in current directory');\n }\n \n // Find all metadata JSON files\n spinner.start('Finding metadata files');\n const pattern = syncConfig.filePattern || '.*.json';\n const files = await fastGlob(pattern, {\n cwd: configManager.getOriginalCwd(),\n absolute: true,\n ignore: ['.mj-sync.json', '.mj-folder.json'],\n });\n \n spinner.stop();\n \n if (files.length === 0) {\n this.log('No metadata files found');\n return;\n }\n \n this.log(`Found ${files.length} metadata file${files.length === 1 ? '' : 's'}`);\n \n // Count what will be removed\n let filesWithPrimaryKey = 0;\n let filesWithSync = 0;\n let totalPrimaryKeys = 0;\n let totalSyncs = 0;\n \n for (const file of files) {\n const content = await fs.readJson(file);\n const stats = this.countSections(content);\n if (stats.primaryKeyCount > 0) {\n filesWithPrimaryKey++;\n totalPrimaryKeys += stats.primaryKeyCount;\n }\n if (stats.syncCount > 0) {\n filesWithSync++;\n totalSyncs += stats.syncCount;\n }\n }\n \n // Show what will be removed\n this.log('');\n if (flags.sections === 'both' || flags.sections === 'primaryKey') {\n this.log(`Will remove ${chalk.yellow(totalPrimaryKeys)} primaryKey section${totalPrimaryKeys === 1 ? '' : 's'} from ${chalk.yellow(filesWithPrimaryKey)} file${filesWithPrimaryKey === 1 ? '' : 's'}`);\n }\n if (flags.sections === 'both' || flags.sections === 'sync') {\n this.log(`Will remove ${chalk.yellow(totalSyncs)} sync section${totalSyncs === 1 ? '' : 's'} from ${chalk.yellow(filesWithSync)} file${filesWithSync === 1 ? '' : 's'}`);\n }\n \n if (flags['dry-run']) {\n this.log('');\n this.log(chalk.cyan('Dry run mode - no files will be modified'));\n \n if (flags.verbose) {\n this.log('');\n for (const file of files) {\n const content = await fs.readJson(file);\n const stats = this.countSections(content);\n if (stats.primaryKeyCount > 0 || stats.syncCount > 0) {\n this.log(`${path.relative(configManager.getOriginalCwd(), file)}:`);\n if (stats.primaryKeyCount > 0) {\n this.log(` - ${stats.primaryKeyCount} primaryKey section${stats.primaryKeyCount === 1 ? '' : 's'}`);\n }\n if (stats.syncCount > 0) {\n this.log(` - ${stats.syncCount} sync section${stats.syncCount === 1 ? '' : 's'}`);\n }\n }\n }\n }\n return;\n }\n \n // Confirm before proceeding\n if (!flags.yes) {\n const confirmed = await confirm({\n message: 'Do you want to proceed?',\n default: false,\n });\n \n if (!confirmed) {\n this.log('Operation cancelled');\n return;\n }\n }\n \n // Process files\n spinner.start('Processing files');\n let processedFiles = 0;\n let modifiedFiles = 0;\n \n for (const file of files) {\n processedFiles++;\n const content = await fs.readJson(file);\n const originalContent = JSON.stringify(content);\n \n // Remove sections\n const cleanedContent = this.removeSections(content, flags.sections);\n \n // Only write if content changed\n if (JSON.stringify(cleanedContent) !== originalContent) {\n // Create backup if requested\n if (!flags['no-backup']) {\n const backupPath = `${file}.backup`;\n await fs.writeJson(backupPath, content, { spaces: 2 });\n }\n \n // Write cleaned content\n await fs.writeJson(file, cleanedContent, { spaces: 2 });\n modifiedFiles++;\n \n if (flags.verbose) {\n spinner.stop();\n this.log(`✓ ${path.relative(configManager.getOriginalCwd(), file)}`);\n spinner.start('Processing files');\n }\n }\n }\n \n spinner.stop();\n \n // Show summary\n this.log('');\n this.log(chalk.green(`✓ Reset complete`));\n this.log(` Processed: ${processedFiles} file${processedFiles === 1 ? '' : 's'}`);\n this.log(` Modified: ${modifiedFiles} file${modifiedFiles === 1 ? '' : 's'}`);\n if (!flags['no-backup'] && modifiedFiles > 0) {\n this.log(` Backups created: ${modifiedFiles}`);\n }\n \n } catch (error) {\n spinner.stop();\n this.error(error instanceof Error ? error.message : String(error));\n }\n }\n \n private countSections(data: any): { primaryKeyCount: number; syncCount: number } {\n let primaryKeyCount = 0;\n let syncCount = 0;\n \n if (Array.isArray(data)) {\n for (const item of data) {\n const stats = this.countSections(item);\n primaryKeyCount += stats.primaryKeyCount;\n syncCount += stats.syncCount;\n }\n } else if (data && typeof data === 'object') {\n if ('primaryKey' in data) primaryKeyCount++;\n if ('sync' in data) syncCount++;\n \n // Check related entities\n if (data.relatedEntities) {\n for (const entityData of Object.values(data.relatedEntities)) {\n const stats = this.countSections(entityData);\n primaryKeyCount += stats.primaryKeyCount;\n syncCount += stats.syncCount;\n }\n }\n }\n \n return { primaryKeyCount, syncCount };\n }\n \n private removeSections(data: any, sections: string): any {\n if (Array.isArray(data)) {\n return data.map(item => this.removeSections(item, sections));\n } else if (data && typeof data === 'object') {\n const cleaned = { ...data };\n \n // Remove specified sections\n if (sections === 'both' || sections === 'primaryKey') {\n delete cleaned.primaryKey;\n }\n if (sections === 'both' || sections === 'sync') {\n delete cleaned.sync;\n }\n \n // Process related entities\n if (cleaned.relatedEntities) {\n const cleanedRelated: any = {};\n for (const [entityName, entityData] of Object.entries(cleaned.relatedEntities)) {\n cleanedRelated[entityName] = this.removeSections(entityData, sections);\n }\n cleaned.relatedEntities = cleanedRelated;\n }\n \n return cleaned;\n }\n \n return data;\n }\n}"]}
|
|
@@ -3,6 +3,7 @@ export default class Push extends Command {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
private warnings;
|
|
5
5
|
private errors;
|
|
6
|
+
private processedRecords;
|
|
6
7
|
static examples: string[];
|
|
7
8
|
static flags: {
|
|
8
9
|
dir: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
@@ -17,4 +18,24 @@ export default class Push extends Command {
|
|
|
17
18
|
private processJsonFiles;
|
|
18
19
|
private pushRecord;
|
|
19
20
|
private processRelatedEntities;
|
|
21
|
+
/**
|
|
22
|
+
* Generate a unique tracking key for a record based on entity name and primary key values
|
|
23
|
+
*/
|
|
24
|
+
private generateRecordKey;
|
|
25
|
+
/**
|
|
26
|
+
* Check if a record has already been processed and warn if duplicate
|
|
27
|
+
*/
|
|
28
|
+
private checkAndTrackRecord;
|
|
29
|
+
/**
|
|
30
|
+
* Format field value for console display
|
|
31
|
+
*/
|
|
32
|
+
private formatFieldValue;
|
|
33
|
+
/**
|
|
34
|
+
* Parse JSON file and track line numbers for array elements
|
|
35
|
+
*/
|
|
36
|
+
private parseJsonWithLineNumbers;
|
|
37
|
+
/**
|
|
38
|
+
* Format file location with clickable link for VSCode
|
|
39
|
+
*/
|
|
40
|
+
private formatFileLocation;
|
|
20
41
|
}
|