@himamshus06/git-auto 1.3.3 → 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.
- package/package.json +1 -1
- package/src/tree.js +147 -108
package/package.json
CHANGED
package/src/tree.js
CHANGED
|
@@ -12,73 +12,141 @@ class TreeParseError extends Error {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
unicode: {
|
|
19
|
-
vertical: '│',
|
|
20
|
-
branch: '├',
|
|
21
|
-
leaf: '└',
|
|
22
|
-
space: ' '
|
|
23
|
-
},
|
|
24
|
-
ascii: {
|
|
25
|
-
vertical: '|',
|
|
26
|
-
branch: '+',
|
|
27
|
-
leaf: '`',
|
|
28
|
-
space: ' '
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Parses a visual tree string into a structured array of items.
|
|
15
|
+
* Parse a visual directory tree.
|
|
16
|
+
*
|
|
17
|
+
* Supported format:
|
|
34
18
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
19
|
+
* my-project/
|
|
20
|
+
* ├── src/
|
|
21
|
+
* │ ├── index.js
|
|
22
|
+
* │ └── utils.js
|
|
23
|
+
* ├── public/
|
|
24
|
+
* │ └── index.html
|
|
25
|
+
* └── package.json
|
|
38
26
|
*/
|
|
39
27
|
function parseTree(text) {
|
|
40
28
|
if (!text || text.trim() === '') {
|
|
41
29
|
throw new TreeParseError('No tree provided');
|
|
42
30
|
}
|
|
43
31
|
|
|
44
|
-
const lines = text
|
|
45
|
-
|
|
32
|
+
const lines = text
|
|
33
|
+
.split(/\r?\n/)
|
|
34
|
+
.filter(line => line.trim() !== '');
|
|
35
|
+
|
|
46
36
|
const result = [];
|
|
47
|
-
|
|
37
|
+
const stack = [];
|
|
48
38
|
|
|
49
39
|
for (let i = 0; i < lines.length; i++) {
|
|
50
40
|
const line = lines[i];
|
|
51
41
|
const lineNum = i + 1;
|
|
52
42
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
43
|
+
let name;
|
|
44
|
+
let depth;
|
|
45
|
+
|
|
46
|
+
// --------------------------------------------------
|
|
47
|
+
// ROOT
|
|
48
|
+
// --------------------------------------------------
|
|
49
|
+
|
|
50
|
+
if (i === 0) {
|
|
51
|
+
name = line.trim();
|
|
52
|
+
depth = 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
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
|
+
}
|
|
56
82
|
|
|
57
|
-
|
|
58
|
-
|
|
83
|
+
const indentation = match[1];
|
|
84
|
+
name = match[2].trim();
|
|
59
85
|
|
|
60
|
-
|
|
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
|
+
*/
|
|
61
94
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// We count how many vertical bars or space blocks exist before the branch symbol.
|
|
65
|
-
const depth = calculateDepth(prefix);
|
|
95
|
+
depth = indentation.length / 4 + 1;
|
|
96
|
+
}
|
|
66
97
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
98
|
+
if (!name) {
|
|
99
|
+
throw new TreeParseError(
|
|
100
|
+
'Empty file/directory name',
|
|
101
|
+
lineNum
|
|
102
|
+
);
|
|
70
103
|
}
|
|
71
104
|
|
|
72
|
-
//
|
|
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
|
+
|
|
73
122
|
while (stack.length > depth) {
|
|
74
123
|
stack.pop();
|
|
75
124
|
}
|
|
76
125
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
126
|
+
/*
|
|
127
|
+
* Make sure we aren't jumping over a level.
|
|
128
|
+
*/
|
|
129
|
+
if (depth > stack.length) {
|
|
130
|
+
throw new TreeParseError(
|
|
131
|
+
`Invalid nesting at depth ${depth}`,
|
|
132
|
+
lineNum
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// --------------------------------------------------
|
|
137
|
+
// FILE / DIRECTORY
|
|
138
|
+
// --------------------------------------------------
|
|
139
|
+
|
|
140
|
+
const isDirectory = name.endsWith('/');
|
|
141
|
+
|
|
142
|
+
const cleanName = name.replace(/\/$/, '');
|
|
143
|
+
|
|
144
|
+
// --------------------------------------------------
|
|
145
|
+
// PATH
|
|
146
|
+
// --------------------------------------------------
|
|
80
147
|
|
|
81
148
|
stack.push(cleanName);
|
|
149
|
+
|
|
82
150
|
const fullPath = path.join(...stack);
|
|
83
151
|
|
|
84
152
|
result.push({
|
|
@@ -87,91 +155,62 @@ function parseTree(text) {
|
|
|
87
155
|
isDirectory,
|
|
88
156
|
fullPath
|
|
89
157
|
});
|
|
90
|
-
|
|
91
|
-
currentDepth = depth;
|
|
92
158
|
}
|
|
93
159
|
|
|
94
160
|
return result;
|
|
95
161
|
}
|
|
96
162
|
|
|
97
163
|
/**
|
|
98
|
-
*
|
|
99
|
-
* Supports both Unicode and ASCII styles.
|
|
100
|
-
*
|
|
101
|
-
* @param {string} prefix
|
|
102
|
-
* @returns {number}
|
|
103
|
-
*/
|
|
104
|
-
function calculateDepth(prefix) {
|
|
105
|
-
if (!prefix) return 0;
|
|
106
|
-
|
|
107
|
-
// Standard visual trees use blocks of 4 characters per level (e.g., "│ " or " ")
|
|
108
|
-
// We count these blocks.
|
|
109
|
-
let depth = 0;
|
|
110
|
-
let i = 0;
|
|
111
|
-
while (i < prefix.length) {
|
|
112
|
-
// Check if we've reached the terminal branch symbol (├ or └ or + or `)
|
|
113
|
-
if (prefix[i] === SYMBOLS.unicode.branch || prefix[i] === SYMBOLS.unicode.leaf ||
|
|
114
|
-
prefix[i] === SYMBOLS.ascii.branch || prefix[i] === SYMBOLS.ascii.leaf) {
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Increment depth for every "unit" of indentation
|
|
119
|
-
// We assume a unit is 4 characters wide in most common formats
|
|
120
|
-
depth++;
|
|
121
|
-
i += 4;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Because we increment depth for every 4-char block,
|
|
125
|
-
// we need to handle cases where the prefix is shorter than a full block.
|
|
126
|
-
// A more robust way is to count actual vertical markers.
|
|
127
|
-
const markers = (prefix.match(/[│|]/g) || []).length;
|
|
128
|
-
|
|
129
|
-
// Heuristic: If we have markers, that's our depth.
|
|
130
|
-
// Otherwise, we use the space-based block count.
|
|
131
|
-
if (markers > 0) return markers;
|
|
132
|
-
|
|
133
|
-
return Math.floor(prefix.length / 4);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Parses a visual directory tree and creates the corresponding directories/files.
|
|
138
|
-
*
|
|
139
|
-
* @param {string} text - The visual directory tree string.
|
|
140
|
-
* @returns {Promise<{created: string[], errors: string[]}>}
|
|
164
|
+
* Create files and directories from parsed tree.
|
|
141
165
|
*/
|
|
142
166
|
async function parseAndCreateTree(text) {
|
|
143
167
|
const created = [];
|
|
144
168
|
const errors = [];
|
|
145
169
|
|
|
170
|
+
let treeStructure;
|
|
171
|
+
|
|
146
172
|
try {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
for (const item of treeStructure) {
|
|
150
|
-
try {
|
|
151
|
-
if (item.isDirectory) {
|
|
152
|
-
fs.mkdirSync(item.fullPath, { recursive: true });
|
|
153
|
-
} else {
|
|
154
|
-
const parentDir = path.dirname(item.fullPath);
|
|
155
|
-
fs.mkdirSync(parentDir, { recursive: true });
|
|
156
|
-
fs.writeFileSync(item.fullPath, '');
|
|
157
|
-
}
|
|
158
|
-
created.push(item.fullPath);
|
|
159
|
-
} catch (err) {
|
|
160
|
-
errors.push(`Failed to create ${item.fullPath}: ${err.message}`);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
173
|
+
treeStructure = parseTree(text);
|
|
163
174
|
} catch (err) {
|
|
164
175
|
if (err instanceof TreeParseError) {
|
|
165
|
-
throw err;
|
|
176
|
+
throw err;
|
|
166
177
|
}
|
|
167
|
-
|
|
178
|
+
|
|
179
|
+
throw new Error(`Unexpected parsing error: ${err.message}`);
|
|
168
180
|
}
|
|
169
181
|
|
|
170
|
-
|
|
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
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
created,
|
|
208
|
+
errors
|
|
209
|
+
};
|
|
171
210
|
}
|
|
172
211
|
|
|
173
212
|
module.exports = {
|
|
174
|
-
parseAndCreateTree,
|
|
175
213
|
parseTree,
|
|
214
|
+
parseAndCreateTree,
|
|
176
215
|
TreeParseError
|
|
177
|
-
};
|
|
216
|
+
};
|