@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.
- package/package.json +1 -1
- package/src/tree.js +38 -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,86 @@ 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
|
+
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
|
-
`
|
|
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
|
-
|
|
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 };
|