pagan-artifact 0.2.7 → 0.2.9

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/bin/art.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * art - Modern version control.
5
- * CLI (v0.2.7)
5
+ * CLI (v0.2.9)
6
6
  */
7
7
 
8
8
  const art = require('../index.js');
@@ -12,6 +12,7 @@ const [,, command, ...args] = process.argv;
12
12
  const RED = '\x1b[31m';
13
13
  const GREEN = '\x1b[32m';
14
14
  const RESET = '\x1b[0m';
15
+ const GRAY = '\x1b[90m';
15
16
 
16
17
  async function run() {
17
18
  try {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * art - Modern version control.
3
- * Module: Branching (v0.2.7)
3
+ * Module: Branching (v0.2.9)
4
4
  */
5
5
 
6
6
  const fs = require('fs');
@@ -8,6 +8,8 @@ const path = require('path');
8
8
 
9
9
  const getStateByHash = require('../utils/getStateByHash');
10
10
 
11
+ const MAX_PART_SIZE = 32000000;
12
+
11
13
  /**
12
14
  * Lists, creates, or deletes branches.
13
15
  */
@@ -20,8 +22,8 @@ function branch ({ name, isDelete = false } = {}) {
20
22
 
21
23
  if (!name) {
22
24
  return fs.readdirSync(localHistoryPath).filter(f => {
23
- return f !== '.DS_Store' && f !== 'desktop.ini' && f !== 'thumbs.db';
24
- });
25
+ return f !== '.DS_Store' && f !== 'desktop.ini' && f !== 'thumbs.db';
26
+ });
25
27
  }
26
28
 
27
29
  const illegalRegExp = /[\/\\]/g;
@@ -60,7 +62,8 @@ function branch ({ name, isDelete = false } = {}) {
60
62
  }
61
63
 
62
64
  const artJson = JSON.parse(fs.readFileSync(artJsonPath, 'utf8'));
63
- const currentBranchManifest = path.join(localHistoryPath, artJson.active.branch, 'manifest.json');
65
+ const sourceBranchName = artJson.active.branch;
66
+ const currentBranchManifest = path.join(localHistoryPath, sourceBranchName, 'manifest.json');
64
67
 
65
68
  let initialCommits = [];
66
69
 
@@ -85,14 +88,28 @@ function branch ({ name, isDelete = false } = {}) {
85
88
  }
86
89
 
87
90
  if (initialCommits.length > 0) {
88
- const sourceBranchPath = path.join(localHistoryPath, artJson.active.branch);
91
+ const sourceBranchPath = path.join(localHistoryPath, sourceBranchName);
89
92
 
90
93
  for (const hash of initialCommits) {
91
- const srcFile = path.join(sourceBranchPath, `${hash}.json`);
92
- const destFile = path.join(branchLocalPath, `${hash}.json`);
94
+ const masterFile = path.join(sourceBranchPath, `${hash}.json`);
95
+
96
+ if (fs.existsSync(masterFile)) {
97
+ // Copy the Master File
98
+ fs.copyFileSync(masterFile, path.join(branchLocalPath, `${hash}.json`));
99
+
100
+ // Detect and copy all Parts
101
+ const commitMaster = JSON.parse(fs.readFileSync(masterFile, 'utf8'));
102
+
103
+ if (commitMaster.parts && Array.isArray(commitMaster.parts)) {
104
+ for (const partName of commitMaster.parts) {
105
+ const srcPart = path.join(sourceBranchPath, partName);
106
+ const destPart = path.join(branchLocalPath, partName);
93
107
 
94
- if (fs.existsSync(srcFile)) {
95
- fs.copyFileSync(srcFile, destFile);
108
+ if (fs.existsSync(srcPart)) {
109
+ fs.copyFileSync(srcPart, destPart);
110
+ }
111
+ }
112
+ }
96
113
  }
97
114
  }
98
115
  }
@@ -122,10 +139,13 @@ function checkout (branchName, { force = false } = {}) {
122
139
  .filter(f => !f.startsWith('.art') && !fs.statSync(path.join(root, f)).isDirectory());
123
140
 
124
141
  let isDirty = false;
142
+
125
143
  for (const file of allWorkDirFiles) {
126
144
  const currentContent = fs.readFileSync(path.join(root, file), 'utf8');
145
+
127
146
  if (currentContent !== currentState[file]) {
128
147
  isDirty = true;
148
+
129
149
  break;
130
150
  }
131
151
  }
@@ -134,6 +154,7 @@ function checkout (branchName, { force = false } = {}) {
134
154
  for (const file in currentState) {
135
155
  if (!fs.existsSync(path.join(root, file))) {
136
156
  isDirty = true;
157
+
137
158
  break;
138
159
  }
139
160
  }
@@ -155,12 +176,16 @@ function checkout (branchName, { force = false } = {}) {
155
176
  for (const filePath of Object.keys(currentState)) {
156
177
  if (!targetState[filePath]) {
157
178
  const fullPath = path.join(root, filePath);
158
- if (fs.existsSync(fullPath)) fs.rmSync(fullPath, { recursive: true, force: true });
179
+
180
+ if (fs.existsSync(fullPath)) {
181
+ fs.rmSync(fullPath, { recursive: true, force: true });
182
+ }
159
183
  }
160
184
  }
161
185
 
162
186
  for (const [filePath, content] of Object.entries(targetState)) {
163
187
  const fullPath = path.join(root, filePath);
188
+
164
189
  fs.mkdirSync(path.dirname(fullPath), { recursive: true });
165
190
  fs.writeFileSync(fullPath, content);
166
191
  }
@@ -176,57 +201,97 @@ function checkout (branchName, { force = false } = {}) {
176
201
  * Performs a three-way merge. Overwrites working directory with conflicts.
177
202
  */
178
203
 
179
- function merge (targetBranch) {
180
- const root = process.cwd();
181
- const artPath = path.join(root, '.art');
182
- const artJson = JSON.parse(fs.readFileSync(path.join(artPath, 'art.json'), 'utf8'));
183
- const activeBranch = artJson.active.branch;
204
+ function merge (targetBranch) {
205
+ const root = process.cwd();
206
+ const artPath = path.join(root, '.art');
207
+ const stageDir = path.join(artPath, 'stage');
208
+ const artJson = JSON.parse(fs.readFileSync(path.join(artPath, 'art.json'), 'utf8'));
209
+ const activeBranch = artJson.active.branch;
184
210
 
185
- const activeManifest = JSON.parse(fs.readFileSync(path.join(artPath, `history/local/${activeBranch}/manifest.json`), 'utf8'));
186
- const targetManifest = JSON.parse(fs.readFileSync(path.join(artPath, `history/local/${targetBranch}/manifest.json`), 'utf8'));
211
+ if (fs.existsSync(stageDir)) {
212
+ fs.rmSync(stageDir, { recursive: true, force: true });
213
+ }
187
214
 
188
- const commonAncestorHash = [...activeManifest.commits].reverse().find(h => targetManifest.commits.includes(h)) || null;
215
+ fs.mkdirSync(stageDir, { recursive: true });
189
216
 
190
- const baseState = commonAncestorHash ? getStateByHash(activeBranch, commonAncestorHash) : {};
191
- const activeState = getStateByHash(activeBranch, artJson.active.parent);
192
- const lastTargetHash = targetManifest.commits[targetManifest.commits.length - 1];
193
- const targetState = getStateByHash(targetBranch, lastTargetHash);
217
+ const activeManifest = JSON.parse(fs.readFileSync(path.join(artPath, `history/local/${activeBranch}/manifest.json`), 'utf8'));
218
+ const targetManifest = JSON.parse(fs.readFileSync(path.join(artPath, `history/local/${targetBranch}/manifest.json`), 'utf8'));
194
219
 
195
- const mergedChanges = {};
196
- const allFiles = new Set([...Object.keys(activeState), ...Object.keys(targetState)]);
220
+ const commonAncestorHash = [...activeManifest.commits].reverse().find(h => targetManifest.commits.includes(h)) || null;
197
221
 
198
- for (const filePath of allFiles) {
199
- const base = baseState[filePath];
200
- const active = activeState[filePath];
201
- const target = targetState[filePath];
202
- const fullPath = path.join(root, filePath);
222
+ const baseState = commonAncestorHash ? getStateByHash(activeBranch, commonAncestorHash) : {};
223
+ const activeState = getStateByHash(activeBranch, artJson.active.parent);
224
+ const lastTargetHash = targetManifest.commits[targetManifest.commits.length - 1];
225
+ const targetState = getStateByHash(targetBranch, lastTargetHash);
203
226
 
204
- if (active === target) continue;
227
+ const allFiles = new Set([...Object.keys(activeState), ...Object.keys(targetState)]);
205
228
 
206
- if (base === active && base !== target) {
207
- fs.mkdirSync(path.dirname(fullPath), { recursive: true });
208
- fs.writeFileSync(fullPath, target || '');
229
+ let currentPartChanges = {};
230
+ let currentPartSize = 0;
231
+ let partCount = 0;
209
232
 
210
- mergedChanges[filePath] = { type: 'createFile', content: target };
211
- } else if (base !== active && base !== target && active !== target) {
212
- const conflictContent = `<<<<<<< active\n${active || ''}\n=======\n${target || ''}\n>>>>>>> ${targetBranch}`;
233
+ const saveStagePart = () => {
234
+ if (Object.keys(currentPartChanges).length === 0) return;
213
235
 
214
- fs.mkdirSync(path.dirname(fullPath), { recursive: true });
215
- fs.writeFileSync(fullPath, conflictContent);
236
+ const partPath = path.join(stageDir, `part.${partCount}.json`);
216
237
 
217
- mergedChanges[filePath] = { type: 'createFile', content: conflictContent };
218
- }
219
- }
238
+ fs.writeFileSync(partPath, JSON.stringify({ changes: currentPartChanges }, null, 2));
239
+ currentPartChanges = {};
240
+ currentPartSize = 0;
241
+ partCount++;
242
+ };
220
243
 
221
- const stage = { changes: mergedChanges };
244
+ for (const filePath of allFiles) {
245
+ const base = baseState[filePath];
246
+ const active = activeState[filePath];
247
+ const target = targetState[filePath];
248
+ const fullPath = path.join(root, filePath);
222
249
 
223
- fs.writeFileSync(path.join(artPath, 'stage.json'), JSON.stringify(stage, null, 2));
250
+ if (active === target) continue;
224
251
 
225
- return `Merged ${targetBranch}. Conflicts written to the stage and working directory to be resolved.`;
226
- }
252
+ let change = null;
253
+
254
+ if (base === active && base !== target) {
255
+ if (target === undefined) {
256
+ if (fs.existsSync(fullPath)) fs.unlinkSync(fullPath);
257
+ change = { type: 'deleteFile' };
258
+ } else {
259
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
260
+ fs.writeFileSync(fullPath, target);
261
+ change = { type: 'createFile', content: target };
262
+ }
263
+ } else if (base !== active && base !== target && active !== target) {
264
+ const conflictContent = `<<<<<<< active\n${active || ''}\n=======\n${target || ''}\n>>>>>>> ${targetBranch}`;
265
+
266
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
267
+ fs.writeFileSync(fullPath, conflictContent);
268
+ change = { type: 'createFile', content: conflictContent };
269
+ }
270
+
271
+ if (change) {
272
+ const changeSize = JSON.stringify(change).length;
273
+
274
+ if (currentPartSize + changeSize > MAX_PART_SIZE) {
275
+ saveStagePart();
276
+ }
277
+
278
+ currentPartChanges[filePath] = change;
279
+ currentPartSize += changeSize;
280
+ }
281
+ }
282
+
283
+ saveStagePart();
284
+
285
+ fs.writeFileSync(
286
+ path.join(stageDir, 'manifest.json'),
287
+ JSON.stringify({ parts: Array.from({ length: partCount }, (_, i) => `part.${i}.json`) }, null, 2)
288
+ );
289
+
290
+ return `Merged ${targetBranch}. ${partCount} stage parts created. Resolve conflicts and art commit.`;
291
+ }
227
292
 
228
293
  module.exports = {
229
- __libraryVersion: '0.2.7',
294
+ __libraryVersion: '0.2.9',
230
295
  __libraryAPIName: 'Branching',
231
296
  branch,
232
297
  checkout,
package/caches/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * art - Modern version control.
3
- * Module: Caches (v0.2.7)
3
+ * Module: Caches (v0.2.9)
4
4
  */
5
5
 
6
6
  const fs = require('fs');
@@ -9,6 +9,80 @@ const path = require('path');
9
9
  const { checkout } = require('../branching/index.js');
10
10
  const getStateByHash = require('../utils/getStateByHash');
11
11
 
12
+ /**
13
+ * Helper to load all changes from a paginated stage directory.
14
+ */
15
+
16
+ function getStagedChanges(artPath) {
17
+ const stageDir = path.join(artPath, 'stage');
18
+ const manifestPath = path.join(stageDir, 'manifest.json');
19
+
20
+ if (!fs.existsSync(stageDir) || !fs.existsSync(manifestPath)) {
21
+ return {};
22
+ }
23
+
24
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
25
+
26
+ let allChanges = {};
27
+
28
+ for (const partName of manifest.parts) {
29
+ const partPath = path.join(stageDir, partName);
30
+
31
+ if (fs.existsSync(partPath)) {
32
+ const partData = JSON.parse(fs.readFileSync(partPath, 'utf8'));
33
+
34
+ Object.assign(allChanges, partData.changes);
35
+ }
36
+ }
37
+
38
+ return allChanges;
39
+ }
40
+
41
+ /**
42
+ * Helper to write changes to a paginated stage directory.
43
+ */
44
+
45
+ function saveStagedChanges(artPath, changes) {
46
+ const MAX_PART_SIZE = 32000000;
47
+ const stageDir = path.join(artPath, 'stage');
48
+
49
+ if (fs.existsSync(stageDir)) {
50
+ fs.rmSync(stageDir, { recursive: true, force: true });
51
+ }
52
+
53
+ fs.mkdirSync(stageDir, { recursive: true });
54
+
55
+ const stageParts = [];
56
+
57
+ let currentPartChanges = {};
58
+ let currentSize = 0;
59
+
60
+ const savePart = () => {
61
+ const partName = `part.${stageParts.length}.json`;
62
+
63
+ fs.writeFileSync(path.join(stageDir, partName), JSON.stringify({ changes: currentPartChanges }, null, 2));
64
+ stageParts.push(partName);
65
+
66
+ currentPartChanges = {};
67
+ currentSize = 0;
68
+ };
69
+
70
+ for (const [file, changeSet] of Object.entries(changes)) {
71
+ const size = JSON.stringify(changeSet).length;
72
+
73
+ if (currentSize + size > MAX_PART_SIZE && Object.keys(currentPartChanges).length > 0) {
74
+ savePart();
75
+ }
76
+
77
+ currentPartChanges[file] = changeSet;
78
+ currentSize += size;
79
+ }
80
+
81
+ savePart();
82
+
83
+ fs.writeFileSync(path.join(stageDir, 'manifest.json'), JSON.stringify({ parts: stageParts }, null, 2));
84
+ }
85
+
12
86
  /**
13
87
  * Moves changes to a cache folder, or restores the most recent stash.
14
88
  */
@@ -16,12 +90,13 @@ const getStateByHash = require('../utils/getStateByHash');
16
90
  function stash ({ pop = false, list = false } = {}) {
17
91
  const root = process.cwd();
18
92
  const artPath = path.join(root, '.art');
19
- const stagePath = path.join(artPath, 'stage.json');
93
+ const stageDir = path.join(artPath, 'stage');
20
94
  const cachePath = path.join(artPath, 'cache');
21
95
  const artJsonPath = path.join(artPath, 'art.json');
22
96
 
23
97
  if (list) {
24
98
  if (!fs.existsSync(cachePath)) return [];
99
+
25
100
  const stashFiles = fs.readdirSync(cachePath)
26
101
  .filter(f => f.startsWith('stash_') && f.endsWith('.json'))
27
102
  .sort();
@@ -134,8 +209,8 @@ function stash ({ pop = false, list = false } = {}) {
134
209
 
135
210
  fs.writeFileSync(path.join(cachePath, `stash_${timestamp}.json`), JSON.stringify({ changes: stashChanges }, null, 2));
136
211
 
137
- if (fs.existsSync(stagePath)) {
138
- fs.unlinkSync(stagePath);
212
+ if (fs.existsSync(stageDir)) {
213
+ fs.rmSync(stageDir, { recursive: true, force: true });
139
214
  }
140
215
 
141
216
  checkout(artJson.active.branch, { force: true });
@@ -149,11 +224,11 @@ function stash ({ pop = false, list = false } = {}) {
149
224
 
150
225
  function reset (hash) {
151
226
  const artPath = path.join(process.cwd(), '.art');
152
- const stagePath = path.join(artPath, 'stage.json');
227
+ const stageDir = path.join(artPath, 'stage');
153
228
  const artJsonPath = path.join(artPath, 'art.json');
154
229
 
155
- if (fs.existsSync(stagePath)) {
156
- fs.unlinkSync(stagePath);
230
+ if (fs.existsSync(stageDir)) {
231
+ fs.rmSync(stageDir, { recursive: true, force: true });
157
232
  }
158
233
 
159
234
  if (!hash) {
@@ -192,20 +267,15 @@ function reset (hash) {
192
267
 
193
268
  function rm (filePath) {
194
269
  const artPath = path.join(process.cwd(), '.art');
195
- const stagePath = path.join(artPath, 'stage.json');
196
270
  const fullPath = path.join(process.cwd(), filePath);
197
271
 
198
- let stage = { changes: {} };
199
-
200
- if (fs.existsSync(stagePath)) {
201
- stage = JSON.parse(fs.readFileSync(stagePath, 'utf8'));
202
- }
272
+ const stage = getStagedChanges(artPath);
203
273
 
204
- stage.changes[filePath] = {
274
+ stage[filePath] = {
205
275
  type: 'deleteFile'
206
276
  };
207
277
 
208
- fs.writeFileSync(stagePath, JSON.stringify(stage, null, 2));
278
+ saveStagedChanges(artPath, stage);
209
279
 
210
280
  if (fs.existsSync(fullPath)) {
211
281
  fs.unlinkSync(fullPath);
@@ -215,7 +285,7 @@ function rm (filePath) {
215
285
  }
216
286
 
217
287
  module.exports = {
218
- __libraryVersion: '0.2.7',
288
+ __libraryVersion: '0.2.9',
219
289
  __libraryAPIName: 'Caches',
220
290
  stash,
221
291
  reset,
package/changes/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * art - Modern version control.
3
- * Module: Changes (v0.2.7)
3
+ * Module: Changes (v0.2.9)
4
4
  */
5
5
 
6
6
  const fs = require('fs');
@@ -38,11 +38,15 @@ function log () {
38
38
 
39
39
  for (let i = manifest.commits.length - 1; i >= 0; i--) {
40
40
  const hash = manifest.commits[i];
41
- const commitData = JSON.parse(fs.readFileSync(path.join(branchPath, `${hash}.json`), 'utf8'));
41
+ const commitMasterPath = path.join(branchPath, `${hash}.json`);
42
42
 
43
- output += `commit ${commitData.hash}\n`;
44
- output += `Date: ${new Date(commitData.timestamp).toLocaleString()}\n`;
45
- output += `\n ${commitData.message}\n\n`;
43
+ if (fs.existsSync(commitMasterPath)) {
44
+ const commitData = JSON.parse(fs.readFileSync(commitMasterPath, 'utf8'));
45
+
46
+ output += `commit ${commitData.hash}\n`;
47
+ output += `Date: ${new Date(commitData.timestamp).toLocaleString()}\n`;
48
+ output += `\n ${commitData.message}\n\n`;
49
+ }
46
50
  }
47
51
 
48
52
  return output;
@@ -50,14 +54,19 @@ function log () {
50
54
 
51
55
  /**
52
56
  * Displays line-by-line differences between working directory and the last commit/stage.
53
- * @returns {string} Formatted diff output.
57
+ * @returns {object} Formatted diff output and staged file list.
54
58
  */
55
59
 
56
60
  function diff () {
57
61
  const root = process.cwd();
58
62
  const artPath = path.join(root, '.art');
59
- const artJson = JSON.parse(fs.readFileSync(path.join(artPath, 'art.json'), 'utf8'));
63
+ const artJsonPath = path.join(artPath, 'art.json');
64
+
65
+ if (!fs.existsSync(artJsonPath)) {
66
+ throw new Error('No art repository found.');
67
+ }
60
68
 
69
+ const artJson = JSON.parse(fs.readFileSync(artJsonPath, 'utf8'));
61
70
  const activeBranch = artJson.active.branch;
62
71
  const lastCommitHash = artJson.active.parent;
63
72
  const lastCommitState = lastCommitHash ? getStateByHash(activeBranch, lastCommitHash) : {};
@@ -95,14 +104,30 @@ function log () {
95
104
  }
96
105
  }
97
106
 
98
- const stagePath = path.join(artPath, 'stage.json');
99
- const staged = fs.existsSync(stagePath) ? Object.keys(JSON.parse(fs.readFileSync(stagePath, 'utf8')).changes) : [];
107
+ const stageDir = path.join(artPath, 'stage');
108
+ const stageManifestPath = path.join(stageDir, 'manifest.json');
109
+
110
+ let staged = [];
111
+
112
+ if (fs.existsSync(stageManifestPath)) {
113
+ const manifest = JSON.parse(fs.readFileSync(stageManifestPath, 'utf8'));
114
+ const stagedFilesSet = new Set();
115
+
116
+ for (const partName of manifest.parts) {
117
+ const partPath = path.join(stageDir, partName);
118
+ if (fs.existsSync(partPath)) {
119
+ const partData = JSON.parse(fs.readFileSync(partPath, 'utf8'));
120
+ Object.keys(partData.changes).forEach(file => stagedFilesSet.add(file));
121
+ }
122
+ }
123
+ staged = Array.from(stagedFilesSet);
124
+ }
100
125
 
101
126
  return { fileDiffs, staged };
102
127
  }
103
128
 
104
129
  module.exports = {
105
- __libraryVersion: '0.2.7',
130
+ __libraryVersion: '0.2.9',
106
131
  __libraryAPIName: 'Changes',
107
132
  log,
108
133
  diff