@git.zone/cli 2.13.10 → 2.13.12

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.
Files changed (105) hide show
  1. package/assets/templates/{npmextra/npmextra.json → smartconfig/_smartconfig.json} +3 -0
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/classes.gitzoneconfig.js +4 -4
  4. package/dist_ts/gitzone.cli.js +1 -15
  5. package/dist_ts/mod_commit/index.js +4 -4
  6. package/dist_ts/mod_config/classes.commitconfig.d.ts +3 -3
  7. package/dist_ts/mod_config/classes.commitconfig.js +20 -20
  8. package/dist_ts/mod_config/classes.releaseconfig.d.ts +3 -3
  9. package/dist_ts/mod_config/classes.releaseconfig.js +21 -21
  10. package/dist_ts/mod_config/index.js +12 -12
  11. package/dist_ts/mod_format/classes.baseformatter.d.ts +2 -9
  12. package/dist_ts/mod_format/classes.baseformatter.js +13 -26
  13. package/dist_ts/mod_format/classes.formatplanner.d.ts +1 -3
  14. package/dist_ts/mod_format/classes.formatplanner.js +11 -39
  15. package/dist_ts/mod_format/classes.formatstats.d.ts +0 -5
  16. package/dist_ts/mod_format/classes.formatstats.js +3 -35
  17. package/dist_ts/mod_format/formatters/cleanup.formatter.js +1 -2
  18. package/dist_ts/mod_format/formatters/copy.formatter.js +5 -8
  19. package/dist_ts/mod_format/formatters/gitignore.formatter.d.ts +5 -0
  20. package/dist_ts/mod_format/formatters/gitignore.formatter.js +23 -29
  21. package/dist_ts/mod_format/formatters/packagejson.formatter.js +5 -5
  22. package/dist_ts/mod_format/formatters/prettier.formatter.js +4 -12
  23. package/dist_ts/mod_format/formatters/{npmextra.formatter.d.ts → smartconfig.formatter.d.ts} +6 -1
  24. package/dist_ts/mod_format/formatters/smartconfig.formatter.js +180 -0
  25. package/dist_ts/mod_format/formatters/templates.formatter.d.ts +4 -0
  26. package/dist_ts/mod_format/formatters/templates.formatter.js +50 -43
  27. package/dist_ts/mod_format/formatters/tsconfig.formatter.js +6 -4
  28. package/dist_ts/mod_format/index.d.ts +0 -4
  29. package/dist_ts/mod_format/index.js +27 -78
  30. package/dist_ts/mod_format/interfaces.format.d.ts +1 -18
  31. package/dist_ts/mod_format/interfaces.format.js +16 -2
  32. package/dist_ts/mod_format/mod.plugins.d.ts +3 -7
  33. package/dist_ts/mod_format/mod.plugins.js +4 -8
  34. package/dist_ts/mod_services/classes.globalregistry.js +2 -2
  35. package/dist_ts/mod_services/classes.servicemanager.d.ts +2 -2
  36. package/dist_ts/mod_services/classes.servicemanager.js +21 -21
  37. package/dist_ts/plugins.d.ts +2 -2
  38. package/dist_ts/plugins.js +3 -3
  39. package/package.json +5 -11
  40. package/ts/00_commitinfo_data.ts +1 -1
  41. package/ts/classes.gitzoneconfig.ts +3 -3
  42. package/ts/gitzone.cli.ts +0 -17
  43. package/ts/mod_commit/index.ts +3 -3
  44. package/ts/mod_config/classes.commitconfig.ts +19 -19
  45. package/ts/mod_config/classes.releaseconfig.ts +20 -20
  46. package/ts/mod_config/index.ts +11 -11
  47. package/ts/mod_format/classes.baseformatter.ts +14 -25
  48. package/ts/mod_format/classes.formatplanner.ts +10 -39
  49. package/ts/mod_format/classes.formatstats.ts +2 -42
  50. package/ts/mod_format/formatters/cleanup.formatter.ts +0 -1
  51. package/ts/mod_format/formatters/copy.formatter.ts +4 -8
  52. package/ts/mod_format/formatters/gitignore.formatter.ts +25 -29
  53. package/ts/mod_format/formatters/packagejson.formatter.ts +4 -4
  54. package/ts/mod_format/formatters/prettier.formatter.ts +3 -13
  55. package/ts/mod_format/formatters/smartconfig.formatter.ts +213 -0
  56. package/ts/mod_format/formatters/templates.formatter.ts +55 -43
  57. package/ts/mod_format/formatters/tsconfig.formatter.ts +6 -3
  58. package/ts/mod_format/index.ts +35 -98
  59. package/ts/mod_format/interfaces.format.ts +16 -19
  60. package/ts/mod_format/mod.plugins.ts +4 -12
  61. package/ts/mod_services/classes.globalregistry.ts +2 -2
  62. package/ts/mod_services/classes.servicemanager.ts +20 -20
  63. package/ts/plugins.ts +2 -2
  64. package/dist_ts/mod_format/classes.changecache.d.ts +0 -26
  65. package/dist_ts/mod_format/classes.changecache.js +0 -181
  66. package/dist_ts/mod_format/classes.dependency-analyzer.d.ts +0 -13
  67. package/dist_ts/mod_format/classes.dependency-analyzer.js +0 -93
  68. package/dist_ts/mod_format/classes.rollbackmanager.d.ts +0 -22
  69. package/dist_ts/mod_format/classes.rollbackmanager.js +0 -259
  70. package/dist_ts/mod_format/format.cleanup.d.ts +0 -2
  71. package/dist_ts/mod_format/format.cleanup.js +0 -25
  72. package/dist_ts/mod_format/format.copy.d.ts +0 -24
  73. package/dist_ts/mod_format/format.copy.js +0 -77
  74. package/dist_ts/mod_format/format.gitignore.d.ts +0 -2
  75. package/dist_ts/mod_format/format.gitignore.js +0 -48
  76. package/dist_ts/mod_format/format.license.d.ts +0 -2
  77. package/dist_ts/mod_format/format.license.js +0 -26
  78. package/dist_ts/mod_format/format.npmextra.d.ts +0 -5
  79. package/dist_ts/mod_format/format.npmextra.js +0 -125
  80. package/dist_ts/mod_format/format.packagejson.d.ts +0 -2
  81. package/dist_ts/mod_format/format.packagejson.js +0 -145
  82. package/dist_ts/mod_format/format.prettier.d.ts +0 -2
  83. package/dist_ts/mod_format/format.prettier.js +0 -56
  84. package/dist_ts/mod_format/format.readme.d.ts +0 -1
  85. package/dist_ts/mod_format/format.readme.js +0 -29
  86. package/dist_ts/mod_format/format.templates.d.ts +0 -5
  87. package/dist_ts/mod_format/format.templates.js +0 -68
  88. package/dist_ts/mod_format/format.tsconfig.d.ts +0 -2
  89. package/dist_ts/mod_format/format.tsconfig.js +0 -28
  90. package/dist_ts/mod_format/formatters/npmextra.formatter.js +0 -142
  91. package/ts/mod_format/classes.changecache.ts +0 -235
  92. package/ts/mod_format/classes.dependency-analyzer.ts +0 -117
  93. package/ts/mod_format/classes.rollbackmanager.ts +0 -340
  94. package/ts/mod_format/format.cleanup.ts +0 -26
  95. package/ts/mod_format/format.copy.ts +0 -93
  96. package/ts/mod_format/format.gitignore.ts +0 -54
  97. package/ts/mod_format/format.license.ts +0 -32
  98. package/ts/mod_format/format.npmextra.ts +0 -151
  99. package/ts/mod_format/format.packagejson.ts +0 -196
  100. package/ts/mod_format/format.prettier.ts +0 -66
  101. package/ts/mod_format/format.readme.ts +0 -29
  102. package/ts/mod_format/format.templates.ts +0 -79
  103. package/ts/mod_format/format.tsconfig.ts +0 -31
  104. package/ts/mod_format/formatters/npmextra.formatter.ts +0 -174
  105. /package/{npmextra.json → .smartconfig.json} +0 -0
@@ -1,235 +0,0 @@
1
- import * as plugins from './mod.plugins.js';
2
- import * as paths from '../paths.js';
3
-
4
- export interface IFileCache {
5
- path: string;
6
- checksum: string;
7
- modified: number;
8
- size: number;
9
- }
10
-
11
- export interface ICacheManifest {
12
- version: string;
13
- lastFormat: number;
14
- files: IFileCache[];
15
- }
16
-
17
- export class ChangeCache {
18
- private cacheDir: string;
19
- private manifestPath: string;
20
- private cacheVersion = '1.0.0';
21
-
22
- constructor() {
23
- this.cacheDir = plugins.path.join(paths.cwd, '.nogit', 'gitzone-cache');
24
- this.manifestPath = plugins.path.join(this.cacheDir, 'manifest.json');
25
- }
26
-
27
- async initialize(): Promise<void> {
28
- await plugins.smartfs.directory(this.cacheDir).recursive().create();
29
- }
30
-
31
- async getManifest(): Promise<ICacheManifest> {
32
- const defaultManifest: ICacheManifest = {
33
- version: this.cacheVersion,
34
- lastFormat: 0,
35
- files: [],
36
- };
37
-
38
- const exists = await plugins.smartfs.file(this.manifestPath).exists();
39
- if (!exists) {
40
- return defaultManifest;
41
- }
42
-
43
- try {
44
- const content = (await plugins.smartfs
45
- .file(this.manifestPath)
46
- .encoding('utf8')
47
- .read()) as string;
48
- const manifest = JSON.parse(content);
49
-
50
- // Validate the manifest structure
51
- if (this.isValidManifest(manifest)) {
52
- return manifest;
53
- } else {
54
- console.warn('Invalid manifest structure, returning default manifest');
55
- return defaultManifest;
56
- }
57
- } catch (error) {
58
- console.warn(
59
- `Failed to read cache manifest: ${error.message}, returning default manifest`,
60
- );
61
- // Try to delete the corrupted file
62
- try {
63
- await plugins.smartfs.file(this.manifestPath).delete();
64
- } catch (removeError) {
65
- // Ignore removal errors
66
- }
67
- return defaultManifest;
68
- }
69
- }
70
-
71
- async saveManifest(manifest: ICacheManifest): Promise<void> {
72
- // Validate before saving
73
- if (!this.isValidManifest(manifest)) {
74
- throw new Error('Invalid manifest structure, cannot save');
75
- }
76
-
77
- // Ensure directory exists
78
- await plugins.smartfs.directory(this.cacheDir).recursive().create();
79
-
80
- // Write directly with proper JSON stringification
81
- const jsonContent = JSON.stringify(manifest, null, 2);
82
- await plugins.smartfs
83
- .file(this.manifestPath)
84
- .encoding('utf8')
85
- .write(jsonContent);
86
- }
87
-
88
- async hasFileChanged(filePath: string): Promise<boolean> {
89
- const absolutePath = plugins.path.isAbsolute(filePath)
90
- ? filePath
91
- : plugins.path.join(paths.cwd, filePath);
92
-
93
- // Check if file exists
94
- const exists = await plugins.smartfs.file(absolutePath).exists();
95
- if (!exists) {
96
- return true; // File doesn't exist, so it's "changed" (will be created)
97
- }
98
-
99
- // Get current file stats
100
- const stats = await plugins.smartfs.file(absolutePath).stat();
101
-
102
- // Skip directories
103
- if (stats.isDirectory) {
104
- return false; // Directories are not processed
105
- }
106
-
107
- const content = (await plugins.smartfs
108
- .file(absolutePath)
109
- .encoding('utf8')
110
- .read()) as string;
111
- const currentChecksum = this.calculateChecksum(content);
112
-
113
- // Get cached info
114
- const manifest = await this.getManifest();
115
- const cachedFile = manifest.files.find((f) => f.path === filePath);
116
-
117
- if (!cachedFile) {
118
- return true; // Not in cache, so it's changed
119
- }
120
-
121
- // Compare checksums
122
- return (
123
- cachedFile.checksum !== currentChecksum ||
124
- cachedFile.size !== stats.size ||
125
- cachedFile.modified !== stats.mtime.getTime()
126
- );
127
- }
128
-
129
- async updateFileCache(filePath: string): Promise<void> {
130
- const absolutePath = plugins.path.isAbsolute(filePath)
131
- ? filePath
132
- : plugins.path.join(paths.cwd, filePath);
133
-
134
- // Get current file stats
135
- const stats = await plugins.smartfs.file(absolutePath).stat();
136
-
137
- // Skip directories
138
- if (stats.isDirectory) {
139
- return; // Don't cache directories
140
- }
141
-
142
- const content = (await plugins.smartfs
143
- .file(absolutePath)
144
- .encoding('utf8')
145
- .read()) as string;
146
- const checksum = this.calculateChecksum(content);
147
-
148
- // Update manifest
149
- const manifest = await this.getManifest();
150
- const existingIndex = manifest.files.findIndex((f) => f.path === filePath);
151
-
152
- const cacheEntry: IFileCache = {
153
- path: filePath,
154
- checksum,
155
- modified: stats.mtime.getTime(),
156
- size: stats.size,
157
- };
158
-
159
- if (existingIndex !== -1) {
160
- manifest.files[existingIndex] = cacheEntry;
161
- } else {
162
- manifest.files.push(cacheEntry);
163
- }
164
-
165
- manifest.lastFormat = Date.now();
166
- await this.saveManifest(manifest);
167
- }
168
-
169
- async getChangedFiles(filePaths: string[]): Promise<string[]> {
170
- const changedFiles: string[] = [];
171
-
172
- for (const filePath of filePaths) {
173
- if (await this.hasFileChanged(filePath)) {
174
- changedFiles.push(filePath);
175
- }
176
- }
177
-
178
- return changedFiles;
179
- }
180
-
181
- async clean(): Promise<void> {
182
- const manifest = await this.getManifest();
183
- const validFiles: IFileCache[] = [];
184
-
185
- // Remove entries for files that no longer exist
186
- for (const file of manifest.files) {
187
- const absolutePath = plugins.path.isAbsolute(file.path)
188
- ? file.path
189
- : plugins.path.join(paths.cwd, file.path);
190
-
191
- if (await plugins.smartfs.file(absolutePath).exists()) {
192
- validFiles.push(file);
193
- }
194
- }
195
-
196
- manifest.files = validFiles;
197
- await this.saveManifest(manifest);
198
- }
199
-
200
- private calculateChecksum(content: string | Buffer): string {
201
- return plugins.crypto.createHash('sha256').update(content).digest('hex');
202
- }
203
-
204
- private isValidManifest(manifest: any): manifest is ICacheManifest {
205
- // Check if manifest has the required structure
206
- if (!manifest || typeof manifest !== 'object') {
207
- return false;
208
- }
209
-
210
- // Check required fields
211
- if (
212
- typeof manifest.version !== 'string' ||
213
- typeof manifest.lastFormat !== 'number' ||
214
- !Array.isArray(manifest.files)
215
- ) {
216
- return false;
217
- }
218
-
219
- // Check each file entry
220
- for (const file of manifest.files) {
221
- if (
222
- !file ||
223
- typeof file !== 'object' ||
224
- typeof file.path !== 'string' ||
225
- typeof file.checksum !== 'string' ||
226
- typeof file.modified !== 'number' ||
227
- typeof file.size !== 'number'
228
- ) {
229
- return false;
230
- }
231
- }
232
-
233
- return true;
234
- }
235
- }
@@ -1,117 +0,0 @@
1
- import * as plugins from './mod.plugins.js';
2
- import { BaseFormatter } from './classes.baseformatter.js';
3
-
4
- export interface IModuleDependency {
5
- module: string;
6
- dependencies: Set<string>;
7
- dependents: Set<string>;
8
- }
9
-
10
- export class DependencyAnalyzer {
11
- private moduleDependencies: Map<string, IModuleDependency> = new Map();
12
-
13
- constructor() {
14
- this.initializeDependencies();
15
- }
16
-
17
- private initializeDependencies(): void {
18
- // Define dependencies between format modules
19
- const dependencies = {
20
- cleanup: [], // No dependencies
21
- npmextra: [], // No dependencies
22
- license: ['npmextra'], // Depends on npmextra for config
23
- packagejson: ['npmextra'], // Depends on npmextra for config
24
- templates: ['npmextra', 'packagejson'], // Depends on both
25
- gitignore: ['templates'], // Depends on templates
26
- tsconfig: ['packagejson'], // Depends on package.json
27
- prettier: [
28
- 'cleanup',
29
- 'npmextra',
30
- 'packagejson',
31
- 'templates',
32
- 'gitignore',
33
- 'tsconfig',
34
- ], // Runs after most others
35
- readme: ['npmextra', 'packagejson'], // Depends on project metadata
36
- copy: ['npmextra'], // Depends on config
37
- };
38
-
39
- // Initialize all modules
40
- for (const [module, deps] of Object.entries(dependencies)) {
41
- this.moduleDependencies.set(module, {
42
- module,
43
- dependencies: new Set(deps),
44
- dependents: new Set(),
45
- });
46
- }
47
-
48
- // Build reverse dependencies (dependents)
49
- for (const [module, deps] of Object.entries(dependencies)) {
50
- for (const dep of deps) {
51
- const depModule = this.moduleDependencies.get(dep);
52
- if (depModule) {
53
- depModule.dependents.add(module);
54
- }
55
- }
56
- }
57
- }
58
-
59
- getExecutionGroups(modules: BaseFormatter[]): BaseFormatter[][] {
60
- const modulesMap = new Map(modules.map((m) => [m.name, m]));
61
- const executed = new Set<string>();
62
- const groups: BaseFormatter[][] = [];
63
-
64
- while (executed.size < modules.length) {
65
- const currentGroup: BaseFormatter[] = [];
66
-
67
- for (const module of modules) {
68
- if (executed.has(module.name)) continue;
69
-
70
- const dependency = this.moduleDependencies.get(module.name);
71
- if (!dependency) {
72
- // Unknown module, execute in isolation
73
- currentGroup.push(module);
74
- continue;
75
- }
76
-
77
- // Check if all dependencies have been executed
78
- const allDepsExecuted = Array.from(dependency.dependencies).every(
79
- (dep) => executed.has(dep) || !modulesMap.has(dep),
80
- );
81
-
82
- if (allDepsExecuted) {
83
- currentGroup.push(module);
84
- }
85
- }
86
-
87
- if (currentGroup.length === 0) {
88
- // Circular dependency or error - execute remaining modules
89
- for (const module of modules) {
90
- if (!executed.has(module.name)) {
91
- currentGroup.push(module);
92
- }
93
- }
94
- }
95
-
96
- currentGroup.forEach((m) => executed.add(m.name));
97
- groups.push(currentGroup);
98
- }
99
-
100
- return groups;
101
- }
102
-
103
- canRunInParallel(module1: string, module2: string): boolean {
104
- const dep1 = this.moduleDependencies.get(module1);
105
- const dep2 = this.moduleDependencies.get(module2);
106
-
107
- if (!dep1 || !dep2) return false;
108
-
109
- // Check if module1 depends on module2 or vice versa
110
- return (
111
- !dep1.dependencies.has(module2) &&
112
- !dep2.dependencies.has(module1) &&
113
- !dep1.dependents.has(module2) &&
114
- !dep2.dependents.has(module1)
115
- );
116
- }
117
- }
@@ -1,340 +0,0 @@
1
- import * as plugins from './mod.plugins.js';
2
- import * as paths from '../paths.js';
3
- import type { IFormatOperation } from './interfaces.format.js';
4
-
5
- export class RollbackManager {
6
- private backupDir: string;
7
- private manifestPath: string;
8
-
9
- constructor() {
10
- this.backupDir = plugins.path.join(paths.cwd, '.nogit', 'gitzone-backups');
11
- this.manifestPath = plugins.path.join(this.backupDir, 'manifest.json');
12
- }
13
-
14
- async createOperation(): Promise<IFormatOperation> {
15
- await this.ensureBackupDir();
16
-
17
- const operation: IFormatOperation = {
18
- id: this.generateOperationId(),
19
- timestamp: Date.now(),
20
- files: [],
21
- status: 'pending',
22
- };
23
-
24
- await this.updateManifest(operation);
25
- return operation;
26
- }
27
-
28
- async backupFile(filepath: string, operationId: string): Promise<void> {
29
- const operation = await this.getOperation(operationId);
30
- if (!operation) {
31
- throw new Error(`Operation ${operationId} not found`);
32
- }
33
-
34
- const absolutePath = plugins.path.isAbsolute(filepath)
35
- ? filepath
36
- : plugins.path.join(paths.cwd, filepath);
37
-
38
- // Check if file exists
39
- const exists = await plugins.smartfs.file(absolutePath).exists();
40
- if (!exists) {
41
- // File doesn't exist yet (will be created), so we skip backup
42
- return;
43
- }
44
-
45
- // Read file content and metadata
46
- const content = (await plugins.smartfs
47
- .file(absolutePath)
48
- .encoding('utf8')
49
- .read()) as string;
50
- const stats = await plugins.smartfs.file(absolutePath).stat();
51
- const checksum = this.calculateChecksum(content);
52
-
53
- // Create backup
54
- const backupPath = this.getBackupPath(operationId, filepath);
55
- await plugins.smartfs
56
- .directory(plugins.path.dirname(backupPath))
57
- .recursive()
58
- .create();
59
- await plugins.smartfs.file(backupPath).encoding('utf8').write(content);
60
-
61
- // Update operation
62
- operation.files.push({
63
- path: filepath,
64
- originalContent: content,
65
- checksum,
66
- permissions: stats.mode.toString(8),
67
- });
68
-
69
- await this.updateManifest(operation);
70
- }
71
-
72
- async rollback(operationId: string): Promise<void> {
73
- const operation = await this.getOperation(operationId);
74
- if (!operation) {
75
- // Operation doesn't exist, might have already been rolled back or never created
76
- console.warn(`Operation ${operationId} not found for rollback, skipping`);
77
- return;
78
- }
79
-
80
- if (operation.status === 'rolled-back') {
81
- throw new Error(`Operation ${operationId} has already been rolled back`);
82
- }
83
-
84
- // Restore files in reverse order
85
- for (let i = operation.files.length - 1; i >= 0; i--) {
86
- const file = operation.files[i];
87
- const absolutePath = plugins.path.isAbsolute(file.path)
88
- ? file.path
89
- : plugins.path.join(paths.cwd, file.path);
90
-
91
- // Verify backup integrity
92
- const backupPath = this.getBackupPath(operationId, file.path);
93
- const backupContent = await plugins.smartfs
94
- .file(backupPath)
95
- .encoding('utf8')
96
- .read();
97
- const backupChecksum = this.calculateChecksum(backupContent);
98
-
99
- if (backupChecksum !== file.checksum) {
100
- throw new Error(`Backup integrity check failed for ${file.path}`);
101
- }
102
-
103
- // Restore file
104
- await plugins.smartfs
105
- .file(absolutePath)
106
- .encoding('utf8')
107
- .write(file.originalContent);
108
-
109
- // Restore permissions
110
- const mode = parseInt(file.permissions, 8);
111
- // Note: Permissions restoration may not work on all platforms
112
- }
113
-
114
- // Update operation status
115
- operation.status = 'rolled-back';
116
- await this.updateManifest(operation);
117
- }
118
-
119
- async markComplete(operationId: string): Promise<void> {
120
- const operation = await this.getOperation(operationId);
121
- if (!operation) {
122
- throw new Error(`Operation ${operationId} not found`);
123
- }
124
-
125
- operation.status = 'completed';
126
- await this.updateManifest(operation);
127
- }
128
-
129
- async cleanOldBackups(retentionDays: number): Promise<void> {
130
- const manifest = await this.getManifest();
131
- const cutoffTime = Date.now() - retentionDays * 24 * 60 * 60 * 1000;
132
-
133
- const operationsToDelete = manifest.operations.filter(
134
- (op) => op.timestamp < cutoffTime && op.status === 'completed',
135
- );
136
-
137
- for (const operation of operationsToDelete) {
138
- // Remove backup files
139
- const operationDir = plugins.path.join(
140
- this.backupDir,
141
- 'operations',
142
- operation.id,
143
- );
144
- await plugins.smartfs.directory(operationDir).recursive().delete();
145
-
146
- // Remove from manifest
147
- manifest.operations = manifest.operations.filter(
148
- (op) => op.id !== operation.id,
149
- );
150
- }
151
-
152
- await this.saveManifest(manifest);
153
- }
154
-
155
- async verifyBackup(operationId: string): Promise<boolean> {
156
- const operation = await this.getOperation(operationId);
157
- if (!operation) {
158
- return false;
159
- }
160
-
161
- for (const file of operation.files) {
162
- const backupPath = this.getBackupPath(operationId, file.path);
163
- const exists = await plugins.smartfs.file(backupPath).exists();
164
-
165
- if (!exists) {
166
- return false;
167
- }
168
-
169
- const content = await plugins.smartfs
170
- .file(backupPath)
171
- .encoding('utf8')
172
- .read();
173
- const checksum = this.calculateChecksum(content);
174
-
175
- if (checksum !== file.checksum) {
176
- return false;
177
- }
178
- }
179
-
180
- return true;
181
- }
182
-
183
- async listBackups(): Promise<IFormatOperation[]> {
184
- const manifest = await this.getManifest();
185
- return manifest.operations;
186
- }
187
-
188
- private async ensureBackupDir(): Promise<void> {
189
- await plugins.smartfs.directory(this.backupDir).recursive().create();
190
- await plugins.smartfs
191
- .directory(plugins.path.join(this.backupDir, 'operations'))
192
- .recursive()
193
- .create();
194
- }
195
-
196
- private generateOperationId(): string {
197
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
198
- const random = Math.random().toString(36).substring(2, 8);
199
- return `${timestamp}-${random}`;
200
- }
201
-
202
- private getBackupPath(operationId: string, filepath: string): string {
203
- const filename = plugins.path.basename(filepath);
204
- const dir = plugins.path.dirname(filepath);
205
- const safeDir = dir.replace(/[/\\]/g, '__');
206
- return plugins.path.join(
207
- this.backupDir,
208
- 'operations',
209
- operationId,
210
- 'files',
211
- safeDir,
212
- `${filename}.backup`,
213
- );
214
- }
215
-
216
- private calculateChecksum(content: string | Buffer): string {
217
- return plugins.crypto.createHash('sha256').update(content).digest('hex');
218
- }
219
-
220
- private async getManifest(): Promise<{ operations: IFormatOperation[] }> {
221
- const defaultManifest = { operations: [] };
222
-
223
- const exists = await plugins.smartfs.file(this.manifestPath).exists();
224
- if (!exists) {
225
- return defaultManifest;
226
- }
227
-
228
- try {
229
- const content = (await plugins.smartfs
230
- .file(this.manifestPath)
231
- .encoding('utf8')
232
- .read()) as string;
233
- const manifest = JSON.parse(content);
234
-
235
- // Validate the manifest structure
236
- if (this.isValidManifest(manifest)) {
237
- return manifest;
238
- } else {
239
- console.warn(
240
- 'Invalid rollback manifest structure, returning default manifest',
241
- );
242
- return defaultManifest;
243
- }
244
- } catch (error) {
245
- console.warn(
246
- `Failed to read rollback manifest: ${error.message}, returning default manifest`,
247
- );
248
- // Try to delete the corrupted file
249
- try {
250
- await plugins.smartfs.file(this.manifestPath).delete();
251
- } catch (removeError) {
252
- // Ignore removal errors
253
- }
254
- return defaultManifest;
255
- }
256
- }
257
-
258
- private async saveManifest(manifest: {
259
- operations: IFormatOperation[];
260
- }): Promise<void> {
261
- // Validate before saving
262
- if (!this.isValidManifest(manifest)) {
263
- throw new Error('Invalid rollback manifest structure, cannot save');
264
- }
265
-
266
- // Ensure directory exists
267
- await this.ensureBackupDir();
268
-
269
- // Write directly with proper JSON stringification
270
- const jsonContent = JSON.stringify(manifest, null, 2);
271
- await plugins.smartfs
272
- .file(this.manifestPath)
273
- .encoding('utf8')
274
- .write(jsonContent);
275
- }
276
-
277
- private async getOperation(
278
- operationId: string,
279
- ): Promise<IFormatOperation | null> {
280
- const manifest = await this.getManifest();
281
- return manifest.operations.find((op) => op.id === operationId) || null;
282
- }
283
-
284
- private async updateManifest(operation: IFormatOperation): Promise<void> {
285
- const manifest = await this.getManifest();
286
- const existingIndex = manifest.operations.findIndex(
287
- (op) => op.id === operation.id,
288
- );
289
-
290
- if (existingIndex !== -1) {
291
- manifest.operations[existingIndex] = operation;
292
- } else {
293
- manifest.operations.push(operation);
294
- }
295
-
296
- await this.saveManifest(manifest);
297
- }
298
-
299
- private isValidManifest(
300
- manifest: any,
301
- ): manifest is { operations: IFormatOperation[] } {
302
- // Check if manifest has the required structure
303
- if (!manifest || typeof manifest !== 'object') {
304
- return false;
305
- }
306
-
307
- // Check required fields
308
- if (!Array.isArray(manifest.operations)) {
309
- return false;
310
- }
311
-
312
- // Check each operation entry
313
- for (const operation of manifest.operations) {
314
- if (
315
- !operation ||
316
- typeof operation !== 'object' ||
317
- typeof operation.id !== 'string' ||
318
- typeof operation.timestamp !== 'number' ||
319
- typeof operation.status !== 'string' ||
320
- !Array.isArray(operation.files)
321
- ) {
322
- return false;
323
- }
324
-
325
- // Check each file in the operation
326
- for (const file of operation.files) {
327
- if (
328
- !file ||
329
- typeof file !== 'object' ||
330
- typeof file.path !== 'string' ||
331
- typeof file.checksum !== 'string'
332
- ) {
333
- return false;
334
- }
335
- }
336
- }
337
-
338
- return true;
339
- }
340
- }
@@ -1,26 +0,0 @@
1
- import * as plugins from './mod.plugins.js';
2
- import * as paths from '../paths.js';
3
-
4
- import { logger } from '../gitzone.logging.js';
5
- import { Project } from '../classes.project.js';
6
-
7
- const filesToDelete = [
8
- 'defaults.yml',
9
- 'yarn.lock',
10
- 'package-lock.json',
11
- 'tslint.json',
12
- ];
13
-
14
- export const run = async (projectArg: Project) => {
15
- for (const relativeFilePath of filesToDelete) {
16
- const fileExists = await plugins.smartfs.file(relativeFilePath).exists();
17
- if (fileExists) {
18
- logger.log('info', `Found ${relativeFilePath}! Removing it!`);
19
- await plugins.smartfs
20
- .file(plugins.path.join(paths.cwd, relativeFilePath))
21
- .delete();
22
- } else {
23
- logger.log('info', `Project is free of ${relativeFilePath}`);
24
- }
25
- }
26
- };