pagan-artifact 0.2.5 → 0.2.6

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.5)
5
+ * CLI (v0.2.6)
6
6
  */
7
7
 
8
8
  const art = require('../index.js');
@@ -44,7 +44,8 @@ async function run() {
44
44
  lastCommit,
45
45
  staged,
46
46
  modified,
47
- untracked
47
+ untracked,
48
+ ignored
48
49
  } = art.status();
49
50
 
50
51
  console.log(`On branch ${activeBranch}`);
@@ -65,8 +66,13 @@ async function run() {
65
66
  untracked.forEach(f => console.log(`${RED}\t${f}${RESET}`));
66
67
  }
67
68
 
69
+ if (ignored && ignored.length > 0) {
70
+ console.log('\nIgnored files:');
71
+ ignored.forEach(f => console.log(`${GRAY}\t${f}${RESET}`));
72
+ }
73
+
68
74
  if (untracked.length === 0 && modified.length === 0 && staged.length === 0) {
69
- console.log('Nothing to commit.');
75
+ console.log('\nNothing to commit, working tree clean.');
70
76
  }
71
77
 
72
78
  break;
@@ -198,6 +204,7 @@ async function run() {
198
204
 
199
205
  break;
200
206
 
207
+ case 'remove':
201
208
  case 'rm':
202
209
  if (!args[0]) throw new Error('Specify a file path to remove.');
203
210
 
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * art - Modern version control.
3
- * Module: Branching (v0.2.5)
3
+ * Module: Branching (v0.2.6)
4
4
  */
5
5
 
6
6
  const fs = require('fs');
@@ -226,7 +226,7 @@ function merge (targetBranch) {
226
226
  }
227
227
 
228
228
  module.exports = {
229
- __libraryVersion: '0.2.5',
229
+ __libraryVersion: '0.2.6',
230
230
  __libraryAPIName: 'Branching',
231
231
  branch,
232
232
  checkout,
package/caches/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * art - Modern version control.
3
- * Module: Caches (v0.2.5)
3
+ * Module: Caches (v0.2.6)
4
4
  */
5
5
 
6
6
  const fs = require('fs');
@@ -215,7 +215,7 @@ function rm (filePath) {
215
215
  }
216
216
 
217
217
  module.exports = {
218
- __libraryVersion: '0.2.5',
218
+ __libraryVersion: '0.2.6',
219
219
  __libraryAPIName: 'Caches',
220
220
  stash,
221
221
  reset,
package/changes/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * art - Modern version control.
3
- * Module: Changes (v0.2.5)
3
+ * Module: Changes (v0.2.6)
4
4
  */
5
5
 
6
6
  const fs = require('fs');
@@ -102,7 +102,7 @@ function log () {
102
102
  }
103
103
 
104
104
  module.exports = {
105
- __libraryVersion: '0.2.5',
105
+ __libraryVersion: '0.2.6',
106
106
  __libraryAPIName: 'Changes',
107
107
  log,
108
108
  diff
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * art - Modern version control.
3
- * Module: Contributions (v0.2.5)
3
+ * Module: Contributions (v0.2.6)
4
4
  */
5
5
 
6
6
  const fs = require('fs');
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * art - Modern version control.
3
- * Core Library Entry Point (v0.2.5)
3
+ * Core Library Entry Point (v0.2.6)
4
4
  */
5
5
 
6
6
  const Setup = require('./setup');
@@ -50,7 +50,7 @@ const art = {
50
50
 
51
51
  // Metadata
52
52
 
53
- version: '0.2.5',
53
+ version: '0.2.6',
54
54
  modules: [
55
55
  Setup.__libraryAPIName,
56
56
  Workflow.__libraryAPIName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pagan-artifact",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Modern version control.",
5
5
  "main": "index.js",
6
6
  "bin": {
package/setup/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * art - Modern version control.
3
- * Module: Setup (v0.2.5)
3
+ * Module: Setup (v0.2.6)
4
4
  */
5
5
 
6
6
  const fs = require('fs');
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * art - Modern version control.
3
- * Module: Utils (v0.2.5)
3
+ * Module: Utils (v0.2.6)
4
4
  */
5
5
 
6
6
  const fs = require('fs');
@@ -0,0 +1,58 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ let memoizedRules = null;
5
+
6
+ function getRules () {
7
+ if (memoizedRules) {
8
+ return memoizedRules;
9
+ }
10
+
11
+ const root = process.cwd();
12
+ const ignorePath = path.join(root, '.artignore');
13
+ const rules = [];
14
+
15
+ if (fs.existsSync(ignorePath)) {
16
+ const lines = fs.readFileSync(ignorePath, 'utf8').split(/\r?\n/);
17
+
18
+ for (let line of lines) {
19
+ line = line.trim();
20
+
21
+ if (!line || line.startsWith('#')) {
22
+ continue;
23
+ }
24
+
25
+ let regexStr = line
26
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&')
27
+ .replace(/\/\*\*\//g, '(/.+/|/)')
28
+ .replace(/\*/g, '[^/]+')
29
+ .replace(/\/$/, '(/.+)?');
30
+
31
+ if (line.startsWith('/')) {
32
+ regexStr = '^' + regexStr.slice(1);
33
+ } else {
34
+ regexStr = '(^|/)' + regexStr;
35
+ }
36
+
37
+ rules.push(new RegExp(regexStr));
38
+ }
39
+ }
40
+
41
+ memoizedRules = rules;
42
+
43
+ return rules;
44
+ }
45
+
46
+ function shouldIgnore (relPath) {
47
+ const normalizedPath = relPath.split(path.sep).join('/');
48
+
49
+ if (normalizedPath === '.art' || normalizedPath.startsWith('.art/')) {
50
+ return true;
51
+ }
52
+
53
+ const rules = getRules();
54
+
55
+ return rules.some(rule => rule.test(normalizedPath));
56
+ }
57
+
58
+ module.exports = shouldIgnore;
package/workflow/index.js CHANGED
@@ -1,20 +1,25 @@
1
1
  /**
2
2
  * art - Modern version control.
3
- * Module: Workflow (v0.2.5)
3
+ * Module: Workflow (v0.2.6)
4
4
  */
5
5
 
6
6
  const fs = require('fs');
7
7
  const path = require('path');
8
8
  const crypto = require('crypto');
9
9
 
10
+ const getStateByHash = require('../utils/getStateByHash');
11
+ const shouldIgnore = require('../utils/shouldIgnore');
12
+
10
13
  /**
11
14
  * Compares the working directory against the last commit and pending stage.
12
15
  */
13
16
 
14
- function status () {
17
+ function status() {
15
18
  const root = process.cwd();
16
19
  const artPath = path.join(root, '.art');
17
20
  const artJsonPath = path.join(artPath, 'art.json');
21
+ const shouldIgnore = require('../utils/shouldIgnore');
22
+ const getStateByHash = require('../utils/getStateByHash');
18
23
 
19
24
  if (!fs.existsSync(artJsonPath)) {
20
25
  throw new Error('No art repository found.');
@@ -25,24 +30,34 @@ function status () {
25
30
  const stagePath = path.join(artPath, 'stage.json');
26
31
 
27
32
  let stagedFiles = {};
28
-
29
33
  if (fs.existsSync(stagePath)) {
30
34
  stagedFiles = JSON.parse(fs.readFileSync(stagePath, 'utf8')).changes;
31
35
  }
32
36
 
33
- const getStateByHash = require('../utils/getStateByHash');
34
37
  const activeState = getStateByHash(activeBranch, artJson.active.parent) || {};
35
38
 
36
- const allWorkDirFiles = fs.readdirSync(root, { recursive: true })
37
- .filter(f => !f.startsWith('.art') && !fs.statSync(path.join(root, f)).isDirectory());
39
+ const allFiles = fs.readdirSync(root, { recursive: true })
40
+ .filter(f => !fs.statSync(path.join(root, f)).isDirectory());
38
41
 
39
42
  const untracked = [];
40
43
  const modified = [];
44
+ const ignored = [];
41
45
 
42
- for (const file of allWorkDirFiles) {
46
+ for (const file of allFiles) {
43
47
  const isStaged = !!stagedFiles[file];
44
48
  const isActive = !!activeState[file];
45
49
 
50
+ if (file === '.art' || file.startsWith(`.art${path.sep}`)) {
51
+ continue;
52
+ }
53
+
54
+ const isIgnored = shouldIgnore(file);
55
+
56
+ if (isIgnored && !isActive && !isStaged) {
57
+ ignored.push(file);
58
+ continue;
59
+ }
60
+
46
61
  if (!isStaged && !isActive) {
47
62
  untracked.push(file);
48
63
  } else if (!isStaged && isActive) {
@@ -59,7 +74,8 @@ function status () {
59
74
  lastCommit: artJson.active.parent,
60
75
  staged: Object.keys(stagedFiles),
61
76
  modified,
62
- untracked
77
+ untracked,
78
+ ignored
63
79
  };
64
80
  }
65
81
 
@@ -68,103 +84,115 @@ function status () {
68
84
  * Implements character-precise position tracking.
69
85
  */
70
86
 
71
- function add (targetPath) {
72
- const root = process.cwd();
73
- const artPath = path.join(root, '.art');
74
- const stagePath = path.join(artPath, 'stage.json');
75
- const artJsonPath = path.join(artPath, 'art.json');
76
- const fullPath = path.resolve(root, targetPath);
77
-
78
- if (!fs.existsSync(fullPath)) {
79
- throw new Error(`Path does not exist: ${targetPath}`);
80
- }
81
-
82
- let stage = { changes: {} };
83
-
84
- if (fs.existsSync(stagePath)) {
85
- stage = JSON.parse(fs.readFileSync(stagePath, 'utf8'));
86
- }
87
-
88
- const artJson = JSON.parse(fs.readFileSync(artJsonPath, 'utf8'));
89
- const getStateByHash = require('../utils/getStateByHash');
90
- const activeState = getStateByHash(artJson.active.branch, artJson.active.parent) || {};
91
-
92
- const stats = fs.statSync(fullPath);
93
-
94
- let filesToProcess = [];
95
-
96
- if (stats.isDirectory()) {
97
- filesToProcess = fs.readdirSync(fullPath, { recursive: true })
98
- .filter(f => {
99
- const absoluteF = path.join(fullPath, f);
100
-
101
- return !fs.statSync(absoluteF).isDirectory() && !absoluteF.includes('.art');
102
- })
103
- .map(f => path.relative(root, path.join(fullPath, f)));
104
- } else {
105
- filesToProcess = [path.relative(root, fullPath)];
106
- }
107
-
108
- for (const relPath of filesToProcess) {
109
- const currentContent = fs.readFileSync(path.join(root, relPath), 'utf8');
110
- const previousContent = activeState[relPath];
111
-
112
- if (previousContent === undefined) {
113
- stage.changes[relPath] = {
114
- type: 'createFile',
115
- content: currentContent
116
- };
117
-
118
- continue;
119
- }
120
-
121
- if (currentContent !== previousContent) {
122
- const operations = [];
123
-
124
- let start = 0;
125
-
126
- while (start < previousContent.length && start < currentContent.length && previousContent[start] === currentContent[start]) {
127
- start++;
128
- }
129
-
130
- let oldEnd = previousContent.length - 1;
131
- let newEnd = currentContent.length - 1;
132
-
133
- while (oldEnd >= start && newEnd >= start && previousContent[oldEnd] === currentContent[newEnd]) {
134
- oldEnd--;
135
- newEnd--;
136
- }
137
-
138
- const deletionLength = oldEnd - start + 1;
139
-
140
- if (deletionLength > 0) {
141
- operations.push({
142
- type: 'delete',
143
- position: start,
144
- length: deletionLength
145
- });
146
- }
147
-
148
- const insertionContent = currentContent.slice(start, newEnd + 1);
149
-
150
- if (insertionContent.length > 0) {
151
- operations.push({
152
- type: 'insert',
153
- position: start,
154
- content: insertionContent
155
- });
156
- }
157
-
158
- if (operations.length > 0) {
159
- stage.changes[relPath] = operations;
160
- }
161
- }
162
- }
163
-
164
- fs.writeFileSync(stagePath, JSON.stringify(stage, null, 2));
165
-
166
- return `Added ${filesToProcess.length} file(s) to stage.`;
167
- }
87
+ function add (targetPath) {
88
+ const root = process.cwd();
89
+ const artPath = path.join(root, '.art');
90
+ const stagePath = path.join(artPath, 'stage.json');
91
+ const artJsonPath = path.join(artPath, 'art.json');
92
+ const fullPath = path.resolve(root, targetPath);
93
+
94
+ if (!fs.existsSync(fullPath)) {
95
+ throw new Error(`Path does not exist: ${targetPath}`);
96
+ }
97
+
98
+ const artJson = JSON.parse(fs.readFileSync(artJsonPath, 'utf8'));
99
+ const activeState = getStateByHash(artJson.active.branch, artJson.active.parent) || {};
100
+
101
+ const stats = fs.statSync(fullPath);
102
+ const relativeTarget = path.relative(root, fullPath);
103
+
104
+ if (!stats.isDirectory() && shouldIgnore(relativeTarget) && !activeState[relativeTarget]) {
105
+ return `${relativeTarget} is being ignored. Edit your .artignore file to remove it.`;
106
+ }
107
+
108
+ let stage = { changes: {} };
109
+ if (fs.existsSync(stagePath)) {
110
+ stage = JSON.parse(fs.readFileSync(stagePath, 'utf8'));
111
+ }
112
+
113
+ let filesToProcess = [];
114
+
115
+ if (stats.isDirectory()) {
116
+ filesToProcess = fs.readdirSync(fullPath, { recursive: true })
117
+ .filter(f => {
118
+ const absoluteF = path.join(fullPath, f);
119
+ const relF = path.relative(root, absoluteF);
120
+ const isDir = fs.statSync(absoluteF).isDirectory();
121
+
122
+ if (relF.startsWith('.art') || relF.includes(`${path.sep}.art`)) return false;
123
+
124
+ const isTracked = !!activeState[relF];
125
+ const isIgnored = shouldIgnore(relF);
126
+
127
+ return !isDir && (!isIgnored || isTracked);
128
+ })
129
+ .map(f => path.relative(root, path.join(fullPath, f)));
130
+ } else {
131
+ filesToProcess = [relativeTarget];
132
+ }
133
+
134
+ if (filesToProcess.length === 0) {
135
+ return "No changes to add.";
136
+ }
137
+
138
+ for (const relPath of filesToProcess) {
139
+ const currentContent = fs.readFileSync(path.join(root, relPath), 'utf8');
140
+ const previousContent = activeState[relPath];
141
+
142
+ if (previousContent === undefined) {
143
+ stage.changes[relPath] = {
144
+ type: 'createFile',
145
+ content: currentContent
146
+ };
147
+
148
+ continue;
149
+ }
150
+
151
+ if (currentContent !== previousContent) {
152
+ const operations = [];
153
+ let start = 0;
154
+
155
+ while (start < previousContent.length && start < currentContent.length && previousContent[start] === currentContent[start]) {
156
+ start++;
157
+ }
158
+
159
+ let oldEnd = previousContent.length - 1;
160
+ let newEnd = currentContent.length - 1;
161
+
162
+ while (oldEnd >= start && newEnd >= start && previousContent[oldEnd] === currentContent[newEnd]) {
163
+ oldEnd--;
164
+ newEnd--;
165
+ }
166
+
167
+ const deletionLength = oldEnd - start + 1;
168
+
169
+ if (deletionLength > 0) {
170
+ operations.push({
171
+ type: 'delete',
172
+ position: start,
173
+ length: deletionLength
174
+ });
175
+ }
176
+
177
+ const insertionContent = currentContent.slice(start, newEnd + 1);
178
+ if (insertionContent.length > 0) {
179
+ operations.push({
180
+ type: 'insert',
181
+ position: start,
182
+ content: insertionContent
183
+ });
184
+ }
185
+
186
+ if (operations.length > 0) {
187
+ stage.changes[relPath] = operations;
188
+ }
189
+ }
190
+ }
191
+
192
+ fs.writeFileSync(stagePath, JSON.stringify(stage, null, 2));
193
+
194
+ return `Added ${filesToProcess.length} file(s) to stage.`;
195
+ }
168
196
 
169
197
  /**
170
198
  * Finalizes the stage into a commit file.
@@ -220,7 +248,7 @@ function commit (message) {
220
248
  }
221
249
 
222
250
  module.exports = {
223
- __libraryVersion: '0.2.5',
251
+ __libraryVersion: '0.2.6',
224
252
  __libraryAPIName: 'Workflow',
225
253
  status,
226
254
  add,