@himamshus06/git-auto 1.3.4 → 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 +128 -124
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@himamshus06/git-auto",
3
- "version": "1.3.4",
3
+ "version": "1.3.5",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/tree.js CHANGED
@@ -12,7 +12,17 @@ class TreeParseError extends Error {
12
12
  }
13
13
 
14
14
  /**
15
- * Parse a visual directory tree into structured items.
15
+ * Parse a visual directory tree.
16
+ *
17
+ * Supported format:
18
+ *
19
+ * my-project/
20
+ * ├── src/
21
+ * │ ├── index.js
22
+ * │ └── utils.js
23
+ * ├── public/
24
+ * │ └── index.html
25
+ * └── package.json
16
26
  */
17
27
  function parseTree(text) {
18
28
  if (!text || text.trim() === '') {
@@ -30,46 +40,111 @@ function parseTree(text) {
30
40
  const line = lines[i];
31
41
  const lineNum = i + 1;
32
42
 
33
- const parsed = parseLine(line);
43
+ let name;
44
+ let depth;
34
45
 
35
- if (!parsed) {
36
- throw new TreeParseError(
37
- `Unable to parse tree line: "${line}"`,
38
- lineNum
39
- );
46
+ // --------------------------------------------------
47
+ // ROOT
48
+ // --------------------------------------------------
49
+
50
+ if (i === 0) {
51
+ name = line.trim();
52
+ depth = 0;
40
53
  }
41
54
 
42
- const { name, depth } = parsed;
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
+ }
82
+
83
+ const indentation = match[1];
84
+ name = match[2].trim();
85
+
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
+ */
43
94
 
44
- // Root must be depth 0
45
- if (i === 0 && depth !== 0) {
95
+ depth = indentation.length / 4 + 1;
96
+ }
97
+
98
+ if (!name) {
46
99
  throw new TreeParseError(
47
- 'Root item must have depth 0',
100
+ 'Empty file/directory name',
48
101
  lineNum
49
102
  );
50
103
  }
51
104
 
52
- // Prevent impossible jumps
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
+
122
+ while (stack.length > depth) {
123
+ stack.pop();
124
+ }
125
+
126
+ /*
127
+ * Make sure we aren't jumping over a level.
128
+ */
53
129
  if (depth > stack.length) {
54
130
  throw new TreeParseError(
55
- `Nesting depth jump detected`,
131
+ `Invalid nesting at depth ${depth}`,
56
132
  lineNum
57
133
  );
58
134
  }
59
135
 
60
- // Remove anything deeper than the current item
61
- while (stack.length > depth) {
62
- stack.pop();
63
- }
136
+ // --------------------------------------------------
137
+ // FILE / DIRECTORY
138
+ // --------------------------------------------------
64
139
 
65
- // Detect directory/file
66
- const isDirectory = detectDirectory(name);
140
+ const isDirectory = name.endsWith('/');
67
141
 
68
- const cleanName = isDirectory
69
- ? name.replace(/\/$/, '')
70
- : name;
142
+ const cleanName = name.replace(/\/$/, '');
143
+
144
+ // --------------------------------------------------
145
+ // PATH
146
+ // --------------------------------------------------
71
147
 
72
- // Add current item to stack
73
148
  stack.push(cleanName);
74
149
 
75
150
  const fullPath = path.join(...stack);
@@ -86,117 +161,46 @@ function parseTree(text) {
86
161
  }
87
162
 
88
163
  /**
89
- * Parse one line of a tree.
90
- */
91
- function parseLine(line) {
92
- // Root:
93
- // project/
94
- if (!/^[│|├└+`]/.test(line)) {
95
- return {
96
- name: line.trim(),
97
- depth: 0
98
- };
99
- }
100
-
101
- /*
102
- * Match tree indentation.
103
- *
104
- * Examples:
105
- *
106
- * ├── src/
107
- * └── package.json
108
- *
109
- * │ ├── components/
110
- * │ └── App.jsx
111
- *
112
- * │ │ └── Button.jsx
113
- */
114
-
115
- const match = line.match(/^((?:│ | )*)(?:├── |└── |\+-- |`-- )(.*)$/);
116
-
117
- if (!match) {
118
- return null;
119
- }
120
-
121
- const indentation = match[1];
122
- const name = match[2].trim();
123
-
124
- // Every 4-character indentation block = one level.
125
- const depth = indentation.length / 4 + 1;
126
-
127
- return {
128
- name,
129
- depth
130
- };
131
- }
132
-
133
- /**
134
- * Determine whether an item is a directory.
135
- *
136
- * Best case: directories end with /.
137
- *
138
- * For trees that don't include /, this falls back to
139
- * extension-based detection.
140
- */
141
- function detectDirectory(name) {
142
- // Explicit directory marker
143
- if (name.endsWith('/')) {
144
- return true;
145
- }
146
-
147
- // Hidden files like .gitignore are files
148
- if (name.startsWith('.')) {
149
- return false;
150
- }
151
-
152
- // Files with extensions are files
153
- if (path.extname(name) !== '') {
154
- return false;
155
- }
156
-
157
- // Otherwise assume directory
158
- return true;
159
- }
160
-
161
- /**
162
- * Parse tree and create files/directories.
164
+ * Create files and directories from parsed tree.
163
165
  */
164
166
  async function parseAndCreateTree(text) {
165
167
  const created = [];
166
168
  const errors = [];
167
169
 
170
+ let treeStructure;
171
+
168
172
  try {
169
- const treeStructure = parseTree(text);
170
-
171
- for (const item of treeStructure) {
172
- try {
173
- if (item.isDirectory) {
174
- fs.mkdirSync(item.fullPath, {
175
- recursive: true
176
- });
177
- } else {
178
- const parentDir = path.dirname(item.fullPath);
179
-
180
- fs.mkdirSync(parentDir, {
181
- recursive: true
182
- });
183
-
184
- fs.writeFileSync(item.fullPath, '');
185
- }
186
-
187
- created.push(item.fullPath);
188
- } catch (err) {
189
- errors.push(
190
- `Failed to create ${item.fullPath}: ${err.message}`
191
- );
192
- }
193
- }
173
+ treeStructure = parseTree(text);
194
174
  } catch (err) {
195
175
  if (err instanceof TreeParseError) {
196
176
  throw err;
197
177
  }
198
178
 
199
- throw new Error(`Unexpected error: ${err.message}`);
179
+ throw new Error(`Unexpected parsing error: ${err.message}`);
180
+ }
181
+
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
+ }
200
204
  }
201
205
 
202
206
  return {
@@ -206,7 +210,7 @@ async function parseAndCreateTree(text) {
206
210
  }
207
211
 
208
212
  module.exports = {
209
- parseAndCreateTree,
210
213
  parseTree,
214
+ parseAndCreateTree,
211
215
  TreeParseError
212
216
  };