@himamshus06/git-auto 1.3.5 → 1.3.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/tree.js +38 -161
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@himamshus06/git-auto",
3
- "version": "1.3.5",
3
+ "version": "1.3.6",
4
4
  "description": "",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/tree.js CHANGED
@@ -1,9 +1,6 @@
1
1
  const fs = require('node:fs');
2
2
  const path = require('node:path');
3
3
 
4
- /**
5
- * Custom error for tree parsing failures
6
- */
7
4
  class TreeParseError extends Error {
8
5
  constructor(message, line) {
9
6
  super(line ? `Line ${line}: ${message}` : message);
@@ -11,206 +8,86 @@ class TreeParseError extends Error {
11
8
  }
12
9
  }
13
10
 
14
- /**
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
26
- */
11
+ // Every character that can appear in a branch-drawing prefix, unicode or ascii style.
12
+ // Note the U+2500 box-drawing horizontal (─) — NOT an ascii hyphen (-). Real tree
13
+ // output (and most pasted trees) uses U+2500, which is why the old regex silently
14
+ // failed to strip prefixes correctly.
15
+ const PREFIX_CHARS = /[│├└|+`\-─\s]/;
16
+ const CONNECTOR_CHARS = new Set(['├', '└', '+', '`']);
17
+
27
18
  function parseTree(text) {
28
19
  if (!text || text.trim() === '') {
29
20
  throw new TreeParseError('No tree provided');
30
21
  }
31
-
32
- const lines = text
33
- .split(/\r?\n/)
34
- .filter(line => line.trim() !== '');
35
-
36
- const result = [];
22
+ const lines = text.split('\n').filter(line => line.trim() !== '');
37
23
  const stack = [];
24
+ const result = [];
38
25
 
39
26
  for (let i = 0; i < lines.length; i++) {
40
27
  const line = lines[i];
41
28
  const lineNum = i + 1;
42
29
 
43
- let name;
44
- let depth;
45
-
46
- // --------------------------------------------------
47
- // ROOT
48
- // --------------------------------------------------
49
-
50
- if (i === 0) {
51
- name = line.trim();
52
- depth = 0;
30
+ // Find the connector character (├ / └ / ascii + / `), if any.
31
+ let connectorIdx = -1;
32
+ for (let c = 0; c < line.length; c++) {
33
+ if (CONNECTOR_CHARS.has(line[c])) { connectorIdx = c; break; }
53
34
  }
54
35
 
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
- */
94
-
95
- depth = indentation.length / 4 + 1;
96
- }
97
-
98
- if (!name) {
99
- throw new TreeParseError(
100
- 'Empty file/directory name',
101
- lineNum
102
- );
36
+ let depth, rest;
37
+ if (connectorIdx === -1) {
38
+ // No connector at all -> this is the root line itself.
39
+ depth = 0;
40
+ rest = line.trim();
41
+ } else {
42
+ const prefix = line.slice(0, connectorIdx);
43
+ // Each ancestor level draws a fixed 4-char block ("│ " or " ").
44
+ // +1 because having a connector at all means "at least one level below root".
45
+ depth = Math.round(prefix.length / 4) + 1;
46
+ rest = line.slice(connectorIdx);
103
47
  }
104
48
 
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
- }
49
+ // Strip any remaining connector/line-drawing/space characters to get the name.
50
+ const name = rest.replace(new RegExp(`^${PREFIX_CHARS.source}+`), '').trim();
51
+ if (!name) continue;
125
52
 
126
- /*
127
- * Make sure we aren't jumping over a level.
128
- */
129
53
  if (depth > stack.length) {
130
54
  throw new TreeParseError(
131
- `Invalid nesting at depth ${depth}`,
132
- lineNum
55
+ `Nesting depth jump detected (from ${stack.length} to ${depth})`, lineNum
133
56
  );
134
57
  }
135
58
 
136
- // --------------------------------------------------
137
- // FILE / DIRECTORY
138
- // --------------------------------------------------
59
+ while (stack.length > depth) stack.pop();
139
60
 
140
- const isDirectory = name.endsWith('/');
141
-
142
- const cleanName = name.replace(/\/$/, '');
143
-
144
- // --------------------------------------------------
145
- // PATH
146
- // --------------------------------------------------
61
+ const isDirectory = name.endsWith('/') || (!name.includes('.') && !name.startsWith('.'));
62
+ const cleanName = isDirectory ? name.replace(/\/$/, '') : name;
147
63
 
148
64
  stack.push(cleanName);
149
-
150
65
  const fullPath = path.join(...stack);
151
66
 
152
- result.push({
153
- name: cleanName,
154
- depth,
155
- isDirectory,
156
- fullPath
157
- });
67
+ result.push({ name: cleanName, depth, isDirectory, fullPath });
158
68
  }
159
-
160
69
  return result;
161
70
  }
162
71
 
163
- /**
164
- * Create files and directories from parsed tree.
165
- */
166
72
  async function parseAndCreateTree(text) {
167
73
  const created = [];
168
74
  const errors = [];
169
-
170
- let treeStructure;
171
-
172
- try {
173
- treeStructure = parseTree(text);
174
- } catch (err) {
175
- if (err instanceof TreeParseError) {
176
- throw err;
177
- }
178
-
179
- throw new Error(`Unexpected parsing error: ${err.message}`);
180
- }
75
+ const treeStructure = parseTree(text); // let TreeParseError propagate to caller
181
76
 
182
77
  for (const item of treeStructure) {
183
78
  try {
184
79
  if (item.isDirectory) {
185
- fs.mkdirSync(item.fullPath, {
186
- recursive: true
187
- });
80
+ fs.mkdirSync(item.fullPath, { recursive: true });
188
81
  } else {
189
- const parentDir = path.dirname(item.fullPath);
190
-
191
- fs.mkdirSync(parentDir, {
192
- recursive: true
193
- });
194
-
82
+ fs.mkdirSync(path.dirname(item.fullPath), { recursive: true });
195
83
  fs.writeFileSync(item.fullPath, '');
196
84
  }
197
-
198
85
  created.push(item.fullPath);
199
86
  } catch (err) {
200
- errors.push(
201
- `Failed to create ${item.fullPath}: ${err.message}`
202
- );
87
+ errors.push(`Failed to create ${item.fullPath}: ${err.message}`);
203
88
  }
204
89
  }
205
-
206
- return {
207
- created,
208
- errors
209
- };
90
+ return { created, errors };
210
91
  }
211
92
 
212
- module.exports = {
213
- parseTree,
214
- parseAndCreateTree,
215
- TreeParseError
216
- };
93
+ module.exports = { parseAndCreateTree, parseTree, TreeParseError };