@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.
- package/package.json +1 -1
- package/src/tree.js +40 -161
package/package.json
CHANGED
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
44
|
-
let
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
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
|
-
`
|
|
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
|
-
|
|
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 };
|