@himamshus06/git-auto 1.3.3 → 1.3.5

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/tree.js +147 -108
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@himamshus06/git-auto",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/tree.js CHANGED
@@ -12,73 +12,141 @@ class TreeParseError extends Error {
12
12
  }
13
13
 
14
14
  /**
15
- * Symbols used to define tree structures
16
- */
17
- const SYMBOLS = {
18
- unicode: {
19
- vertical: '│',
20
- branch: '├',
21
- leaf: '└',
22
- space: ' '
23
- },
24
- ascii: {
25
- vertical: '|',
26
- branch: '+',
27
- leaf: '`',
28
- space: ' '
29
- }
30
- };
31
-
32
- /**
33
- * Parses a visual tree string into a structured array of items.
15
+ * Parse a visual directory tree.
16
+ *
17
+ * Supported format:
34
18
  *
35
- * @param {string} text - The visual directory tree string.
36
- * @returns {Array<{name: string, depth: number, isDirectory: boolean, fullPath: string}>}
37
- * @throws {TreeParseError}
19
+ * my-project/
20
+ * ├── src/
21
+ * │ ├── index.js
22
+ * │ └── utils.js
23
+ * ├── public/
24
+ * │ └── index.html
25
+ * └── package.json
38
26
  */
39
27
  function parseTree(text) {
40
28
  if (!text || text.trim() === '') {
41
29
  throw new TreeParseError('No tree provided');
42
30
  }
43
31
 
44
- const lines = text.split('\n').filter(line => line.trim() !== '');
45
- const stack = [];
32
+ const lines = text
33
+ .split(/\r?\n/)
34
+ .filter(line => line.trim() !== '');
35
+
46
36
  const result = [];
47
- let currentDepth = -1;
37
+ const stack = [];
48
38
 
49
39
  for (let i = 0; i < lines.length; i++) {
50
40
  const line = lines[i];
51
41
  const lineNum = i + 1;
52
42
 
53
- // Regex to split prefix symbols/spaces from the actual name
54
- const match = line.match(/^([│\s├└| \+`-]*) (.*)$/) || line.match(/^([│\s├└| \+`-]*)(.*)$/);
55
- if (!match) continue;
43
+ let name;
44
+ let depth;
45
+
46
+ // --------------------------------------------------
47
+ // ROOT
48
+ // --------------------------------------------------
49
+
50
+ if (i === 0) {
51
+ name = line.trim();
52
+ depth = 0;
53
+ }
54
+
55
+ // --------------------------------------------------
56
+ // CHILD
57
+ // --------------------------------------------------
58
+
59
+ else {
60
+ /*
61
+ * Match:
62
+ *
63
+ * ├── src/
64
+ * └── package.json
65
+ *
66
+ * │ ├── index.js
67
+ * │ └── utils.js
68
+ *
69
+ * │ │ └── Button.jsx
70
+ */
71
+
72
+ const match = line.match(
73
+ /^((?:│ | )*)(?:├── |└── |\+-- |`-- )(.*)$/
74
+ );
75
+
76
+ if (!match) {
77
+ throw new TreeParseError(
78
+ `Could not parse line: "${line}"`,
79
+ lineNum
80
+ );
81
+ }
56
82
 
57
- const prefix = match[1];
58
- let name = match[2].trim();
83
+ const indentation = match[1];
84
+ name = match[2].trim();
59
85
 
60
- if (!name) continue;
86
+ /*
87
+ * Every 4 characters of indentation
88
+ * represents one level.
89
+ *
90
+ * ├── src/ depth 1
91
+ * │ ├── index.js depth 2
92
+ * │ │ └── x.js depth 3
93
+ */
61
94
 
62
- // Calculate depth based on "indentation units"
63
- // A unit is typically 4 characters (symbol + 3 spaces) or similar.
64
- // We count how many vertical bars or space blocks exist before the branch symbol.
65
- const depth = calculateDepth(prefix);
95
+ depth = indentation.length / 4 + 1;
96
+ }
66
97
 
67
- // Logical Validation: Continuity Check
68
- if (depth > currentDepth + 1) {
69
- throw new TreeParseError(`Nesting depth jump detected (from ${currentDepth + 1} to ${depth})`, lineNum);
98
+ if (!name) {
99
+ throw new TreeParseError(
100
+ 'Empty file/directory name',
101
+ lineNum
102
+ );
70
103
  }
71
104
 
72
- // Adjust stack to current depth
105
+ // --------------------------------------------------
106
+ // STACK
107
+ // --------------------------------------------------
108
+
109
+ /*
110
+ * If we're moving back up the tree,
111
+ * remove deeper entries.
112
+ *
113
+ * Example:
114
+ *
115
+ * │ ├── index.js
116
+ * │ └── utils.js
117
+ *
118
+ * When utils.js is processed, index.js
119
+ * must be removed from the stack.
120
+ */
121
+
73
122
  while (stack.length > depth) {
74
123
  stack.pop();
75
124
  }
76
125
 
77
- // Reliable Type Detection
78
- const isDirectory = name.endsWith('/') || (!name.includes('.') && !name.startsWith('.'));
79
- const cleanName = isDirectory ? name.replace(/\/$/, '') : name;
126
+ /*
127
+ * Make sure we aren't jumping over a level.
128
+ */
129
+ if (depth > stack.length) {
130
+ throw new TreeParseError(
131
+ `Invalid nesting at depth ${depth}`,
132
+ lineNum
133
+ );
134
+ }
135
+
136
+ // --------------------------------------------------
137
+ // FILE / DIRECTORY
138
+ // --------------------------------------------------
139
+
140
+ const isDirectory = name.endsWith('/');
141
+
142
+ const cleanName = name.replace(/\/$/, '');
143
+
144
+ // --------------------------------------------------
145
+ // PATH
146
+ // --------------------------------------------------
80
147
 
81
148
  stack.push(cleanName);
149
+
82
150
  const fullPath = path.join(...stack);
83
151
 
84
152
  result.push({
@@ -87,91 +155,62 @@ function parseTree(text) {
87
155
  isDirectory,
88
156
  fullPath
89
157
  });
90
-
91
- currentDepth = depth;
92
158
  }
93
159
 
94
160
  return result;
95
161
  }
96
162
 
97
163
  /**
98
- * Determines the depth of a line based on its prefix.
99
- * Supports both Unicode and ASCII styles.
100
- *
101
- * @param {string} prefix
102
- * @returns {number}
103
- */
104
- function calculateDepth(prefix) {
105
- if (!prefix) return 0;
106
-
107
- // Standard visual trees use blocks of 4 characters per level (e.g., "│ " or " ")
108
- // We count these blocks.
109
- let depth = 0;
110
- let i = 0;
111
- while (i < prefix.length) {
112
- // Check if we've reached the terminal branch symbol (├ or └ or + or `)
113
- if (prefix[i] === SYMBOLS.unicode.branch || prefix[i] === SYMBOLS.unicode.leaf ||
114
- prefix[i] === SYMBOLS.ascii.branch || prefix[i] === SYMBOLS.ascii.leaf) {
115
- break;
116
- }
117
-
118
- // Increment depth for every "unit" of indentation
119
- // We assume a unit is 4 characters wide in most common formats
120
- depth++;
121
- i += 4;
122
- }
123
-
124
- // Because we increment depth for every 4-char block,
125
- // we need to handle cases where the prefix is shorter than a full block.
126
- // A more robust way is to count actual vertical markers.
127
- const markers = (prefix.match(/[│|]/g) || []).length;
128
-
129
- // Heuristic: If we have markers, that's our depth.
130
- // Otherwise, we use the space-based block count.
131
- if (markers > 0) return markers;
132
-
133
- return Math.floor(prefix.length / 4);
134
- }
135
-
136
- /**
137
- * Parses a visual directory tree and creates the corresponding directories/files.
138
- *
139
- * @param {string} text - The visual directory tree string.
140
- * @returns {Promise<{created: string[], errors: string[]}>}
164
+ * Create files and directories from parsed tree.
141
165
  */
142
166
  async function parseAndCreateTree(text) {
143
167
  const created = [];
144
168
  const errors = [];
145
169
 
170
+ let treeStructure;
171
+
146
172
  try {
147
- const treeStructure = parseTree(text);
148
-
149
- for (const item of treeStructure) {
150
- try {
151
- if (item.isDirectory) {
152
- fs.mkdirSync(item.fullPath, { recursive: true });
153
- } else {
154
- const parentDir = path.dirname(item.fullPath);
155
- fs.mkdirSync(parentDir, { recursive: true });
156
- fs.writeFileSync(item.fullPath, '');
157
- }
158
- created.push(item.fullPath);
159
- } catch (err) {
160
- errors.push(`Failed to create ${item.fullPath}: ${err.message}`);
161
- }
162
- }
173
+ treeStructure = parseTree(text);
163
174
  } catch (err) {
164
175
  if (err instanceof TreeParseError) {
165
- throw err; // Rethrow parsing errors for the CLI to handle
176
+ throw err;
166
177
  }
167
- throw new Error(`Unexpected error: ${err.message}`);
178
+
179
+ throw new Error(`Unexpected parsing error: ${err.message}`);
168
180
  }
169
181
 
170
- return { created, errors };
182
+ for (const item of treeStructure) {
183
+ try {
184
+ if (item.isDirectory) {
185
+ fs.mkdirSync(item.fullPath, {
186
+ recursive: true
187
+ });
188
+ } else {
189
+ const parentDir = path.dirname(item.fullPath);
190
+
191
+ fs.mkdirSync(parentDir, {
192
+ recursive: true
193
+ });
194
+
195
+ fs.writeFileSync(item.fullPath, '');
196
+ }
197
+
198
+ created.push(item.fullPath);
199
+ } catch (err) {
200
+ errors.push(
201
+ `Failed to create ${item.fullPath}: ${err.message}`
202
+ );
203
+ }
204
+ }
205
+
206
+ return {
207
+ created,
208
+ errors
209
+ };
171
210
  }
172
211
 
173
212
  module.exports = {
174
- parseAndCreateTree,
175
213
  parseTree,
214
+ parseAndCreateTree,
176
215
  TreeParseError
177
- };
216
+ };