@himamshus06/git-auto 1.3.5 → 1.3.7

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 +40 -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.7",
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,88 @@ 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
+ let name = rest.replace(new RegExp(`^${PREFIX_CHARS.source}+`), '').trim();
51
+ // Strip a trailing inline comment (" # explanation"), if present.
52
+ name = name.replace(/\s+#.*$/, '').trim();
53
+ if (!name) continue;
125
54
 
126
- /*
127
- * Make sure we aren't jumping over a level.
128
- */
129
55
  if (depth > stack.length) {
130
56
  throw new TreeParseError(
131
- `Invalid nesting at depth ${depth}`,
132
- lineNum
57
+ `Nesting depth jump detected (from ${stack.length} to ${depth})`, lineNum
133
58
  );
134
59
  }
135
60
 
136
- // --------------------------------------------------
137
- // FILE / DIRECTORY
138
- // --------------------------------------------------
61
+ while (stack.length > depth) stack.pop();
139
62
 
140
- const isDirectory = name.endsWith('/');
141
-
142
- const cleanName = name.replace(/\/$/, '');
143
-
144
- // --------------------------------------------------
145
- // PATH
146
- // --------------------------------------------------
63
+ const isDirectory = name.endsWith('/') || (!name.includes('.') && !name.startsWith('.'));
64
+ const cleanName = isDirectory ? name.replace(/\/$/, '') : name;
147
65
 
148
66
  stack.push(cleanName);
149
-
150
67
  const fullPath = path.join(...stack);
151
68
 
152
- result.push({
153
- name: cleanName,
154
- depth,
155
- isDirectory,
156
- fullPath
157
- });
69
+ result.push({ name: cleanName, depth, isDirectory, fullPath });
158
70
  }
159
-
160
71
  return result;
161
72
  }
162
73
 
163
- /**
164
- * Create files and directories from parsed tree.
165
- */
166
74
  async function parseAndCreateTree(text) {
167
75
  const created = [];
168
76
  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
- }
77
+ const treeStructure = parseTree(text); // let TreeParseError propagate to caller
181
78
 
182
79
  for (const item of treeStructure) {
183
80
  try {
184
81
  if (item.isDirectory) {
185
- fs.mkdirSync(item.fullPath, {
186
- recursive: true
187
- });
82
+ fs.mkdirSync(item.fullPath, { recursive: true });
188
83
  } else {
189
- const parentDir = path.dirname(item.fullPath);
190
-
191
- fs.mkdirSync(parentDir, {
192
- recursive: true
193
- });
194
-
84
+ fs.mkdirSync(path.dirname(item.fullPath), { recursive: true });
195
85
  fs.writeFileSync(item.fullPath, '');
196
86
  }
197
-
198
87
  created.push(item.fullPath);
199
88
  } catch (err) {
200
- errors.push(
201
- `Failed to create ${item.fullPath}: ${err.message}`
202
- );
89
+ errors.push(`Failed to create ${item.fullPath}: ${err.message}`);
203
90
  }
204
91
  }
205
-
206
- return {
207
- created,
208
- errors
209
- };
92
+ return { created, errors };
210
93
  }
211
94
 
212
- module.exports = {
213
- parseTree,
214
- parseAndCreateTree,
215
- TreeParseError
216
- };
95
+ module.exports = { parseAndCreateTree, parseTree, TreeParseError };