@mangos/filepath 0.0.7 → 1.0.0
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/README.md +161 -221
- package/dist/ParsedPath.d.ts +9 -0
- package/dist/ParsedPath.js +17 -0
- package/dist/ParsedPathError.d.ts +9 -0
- package/dist/ParsedPathError.js +20 -0
- package/dist/Token.d.ts +17 -0
- package/dist/Token.js +22 -0
- package/dist/absorbSuccessiveValues.d.ts +4 -0
- package/dist/absorbSuccessiveValues.js +21 -0
- package/dist/absorbers/ddp.d.ts +10 -0
- package/dist/absorbers/ddp.js +46 -0
- package/dist/absorbers/posix.d.ts +2 -0
- package/dist/absorbers/posix.js +33 -0
- package/dist/absorbers/tdp.d.ts +3 -0
- package/dist/absorbers/tdp.js +132 -0
- package/dist/absorbers/unc.d.ts +3 -0
- package/dist/absorbers/unc.js +20 -0
- package/dist/constants.d.ts +11 -0
- package/dist/constants.js +17 -0
- package/dist/getCWD.d.ts +1 -0
- package/dist/getCWD.js +12 -0
- package/dist/getDrive.d.ts +1 -0
- package/dist/getDrive.js +7 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/parser.d.ts +17 -0
- package/dist/parser.js +161 -0
- package/dist/platform.d.ts +1 -0
- package/dist/platform.js +19 -0
- package/dist/togglePathFragment.d.ts +1 -0
- package/dist/togglePathFragment.js +5 -0
- package/dist/types/TokenValueType.d.ts +2 -0
- package/dist/validSep.d.ts +1 -0
- package/dist/validSep.js +6 -0
- package/package.json +61 -49
- package/.eslintrc.js +0 -17
- package/CHANGELOG.md +0 -52
- package/CODE_OF_CONDUCT.md +0 -69
- package/CONTRIBUTING_GUIDELINES.md +0 -9
- package/index.js +0 -23
- package/lib/parser.js +0 -191
- package/lib/tokenizer.js +0 -397
- package/test.js +0 -5
package/lib/tokenizer.js
DELETED
|
@@ -1,397 +0,0 @@
|
|
|
1
|
-
const tokens = {
|
|
2
|
-
SEP: '\x01', // done
|
|
3
|
-
PATHELT: '\x06',
|
|
4
|
-
PARENT: '\x07',
|
|
5
|
-
CURRENT: '\x08'
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
const rootTokens = {
|
|
9
|
-
POSIX_ROOT: '\x02', // done
|
|
10
|
-
TDP_ROOT: '\x03', // traditional dos path
|
|
11
|
-
UNC_ROOT: '\x04', // unc root
|
|
12
|
-
DDP_ROOT: '\x05' // dos device path root
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
function invertKeyValues(obj) {
|
|
16
|
-
return Object.entries(obj).reduce((o, v) => {
|
|
17
|
-
o[v[1]] = v[0];
|
|
18
|
-
return o;
|
|
19
|
-
}, {});
|
|
20
|
-
}
|
|
21
|
-
const rootTokenValues = invertKeyValues(rootTokens);
|
|
22
|
-
|
|
23
|
-
const regexpLD = /(CON|PRN|AUX|NUL|COM[\\d]|LPT[\\d]|PRN)/i;
|
|
24
|
-
|
|
25
|
-
const uncRegExp = /^(\/\/|\\\\)([^\\/\\?\\.]+)(\/|\\)([^\\/]+)(\/|\\)?/;
|
|
26
|
-
|
|
27
|
-
function hasLegacyDeviceName(str = '', start = 0, end = str.length - 1) {
|
|
28
|
-
const checkFrom = str.slice(start, end + 1);
|
|
29
|
-
const match = checkFrom.match(regexpLD);
|
|
30
|
-
if (Array.isArray(match)) {
|
|
31
|
-
return match[0];
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function inferPlatform() {
|
|
36
|
-
return globalThis?.navigator?.platform || globalThis?.process?.platform || 'posix';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const forbiddenRegExp = new RegExp(`[<>:"/\\|?*<\u0000}]`);
|
|
40
|
-
|
|
41
|
-
function isInValidMSDirecotryName(str = '', start = 0, end = str.length - 1) {
|
|
42
|
-
return forbiddenRegExp.test(str.slice(start, end + 1));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function lookSuccessive(str, fn, start, end = str.length - 1) {
|
|
46
|
-
let i = start;
|
|
47
|
-
let len = 0;
|
|
48
|
-
for (; i <= end; i++) {
|
|
49
|
-
if (fn(str[i])) {
|
|
50
|
-
len++;
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
if (len === 0) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
// return range
|
|
59
|
-
return ({
|
|
60
|
-
end: i - 1,
|
|
61
|
-
start,
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function validSep(s) {
|
|
66
|
-
return s === '\\' || s === '/';
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// hard to infer , '\\' tokens are actually legal in linux xfs, etx4, etc
|
|
70
|
-
function* posixAbsorber(str = '', start = 0, end = str.length - 1) {
|
|
71
|
-
|
|
72
|
-
const selectorPosix = [{ // explicit posix
|
|
73
|
-
fn: (str, start, end) => lookSuccessive(str, s => s !== '/', start, end),
|
|
74
|
-
t: tokens.PATHELT
|
|
75
|
-
},
|
|
76
|
-
{ // explicit posix
|
|
77
|
-
fn: (str, start, end) => lookSuccessive(str, s => s === '/', start, end),
|
|
78
|
-
t: tokens.SEP
|
|
79
|
-
}
|
|
80
|
-
];
|
|
81
|
-
|
|
82
|
-
// "/" start with "/" or '\' tokens should be converted to "/"
|
|
83
|
-
let i = start;
|
|
84
|
-
const root = lookSuccessive(str, s => s === '/', start, end);
|
|
85
|
-
if (root) {
|
|
86
|
-
yield {
|
|
87
|
-
token: rootTokens.POSIX_ROOT,
|
|
88
|
-
start: start,
|
|
89
|
-
end: root.end,
|
|
90
|
-
value: str.slice(start, root.end + 1)
|
|
91
|
-
}
|
|
92
|
-
i = root.end + 1;
|
|
93
|
-
}
|
|
94
|
-
let toggle = 0;
|
|
95
|
-
while (i <= end) {
|
|
96
|
-
// find pathpart
|
|
97
|
-
let token;
|
|
98
|
-
const result = selectorPosix[toggle].fn(str, i, end);
|
|
99
|
-
if (result) {
|
|
100
|
-
const value = str.slice(i, result.end + 1);
|
|
101
|
-
token = selectorPosix[toggle].t;
|
|
102
|
-
if (value === '..') {
|
|
103
|
-
token = tokens.PARENT;
|
|
104
|
-
}
|
|
105
|
-
if (value === '.') {
|
|
106
|
-
token = tokens.CURRENT;
|
|
107
|
-
}
|
|
108
|
-
yield {
|
|
109
|
-
token,
|
|
110
|
-
start: result.start,
|
|
111
|
-
end: result.end,
|
|
112
|
-
value
|
|
113
|
-
}
|
|
114
|
-
i = result.end + 1;
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
toggle = (++toggle % 2);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function getCWDDOSRoot() {
|
|
122
|
-
const cwdPath = getCWD(); // cwd can be anything, even unc //server/share , but not //./unc/ or any other
|
|
123
|
-
const ddpTokens = Array.from(ddpAbsorber(cwdPath));
|
|
124
|
-
if (ddpTokens.length) {
|
|
125
|
-
return ddpTokens[0]; // emit the root
|
|
126
|
-
}
|
|
127
|
-
const uncTokens = Array.from(uncAbsorber(cwdPath));
|
|
128
|
-
if (uncTokens.length) {
|
|
129
|
-
return uncTokens[0];
|
|
130
|
-
}
|
|
131
|
-
// guess its normal tdp
|
|
132
|
-
let drive = cwdPath.slice(0, 2).toLowerCase();
|
|
133
|
-
if (drive[0] >= 'a' && drive[0] <= 'z' && drive[1] === ':') {
|
|
134
|
-
return {
|
|
135
|
-
token: rootTokens.TDP_ROOT,
|
|
136
|
-
value: `${drive}`,
|
|
137
|
-
start: 0,
|
|
138
|
-
end: 1
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
return undefined;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function tdpRootNeedsCorrection(str) {
|
|
146
|
-
const match = str.match(/^[/\\]+/);
|
|
147
|
-
if (match) {
|
|
148
|
-
const exclusions = regExpOrderedMapDDP.slice();
|
|
149
|
-
exclusions.push(['unc', uncRegExp]);
|
|
150
|
-
const shouldNotFind = exclusions.find(([, regexp]) => str.match(regexp));
|
|
151
|
-
if (shouldNotFind) {
|
|
152
|
-
return undefined;
|
|
153
|
-
}
|
|
154
|
-
return { start: 0, end: match[0].length - 1 };
|
|
155
|
-
}
|
|
156
|
-
return undefined;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function* tdpBodyAbsorber(str = '', start = 0, end = str.length - 1) {
|
|
160
|
-
const selectorTDP = [{
|
|
161
|
-
fn: (str, start, end) => lookSuccessive(str, s => !validSep(s), start, end),
|
|
162
|
-
t: tokens.PATHELT
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
fn: (str, start, end) => lookSuccessive(str, s => validSep(s), start, end),
|
|
166
|
-
t: tokens.SEP
|
|
167
|
-
}
|
|
168
|
-
];
|
|
169
|
-
|
|
170
|
-
// also a unix path would work if it is winsos system
|
|
171
|
-
let toggle = 0;
|
|
172
|
-
let i = start;
|
|
173
|
-
while (i <= end) {
|
|
174
|
-
let token;
|
|
175
|
-
const result = selectorTDP[toggle].fn(str, i, end);
|
|
176
|
-
if (result) {
|
|
177
|
-
const value = toggle === 0 ? str.slice(i, result.end + 1) : '\\';
|
|
178
|
-
token = selectorTDP[toggle].t;
|
|
179
|
-
|
|
180
|
-
const errors = [];
|
|
181
|
-
if (toggle === 0) {
|
|
182
|
-
switch (value) {
|
|
183
|
-
case '..':
|
|
184
|
-
token = tokens.PARENT;
|
|
185
|
-
break;
|
|
186
|
-
case '.':
|
|
187
|
-
token = tokens.CURRENT;
|
|
188
|
-
break;
|
|
189
|
-
default:
|
|
190
|
-
{
|
|
191
|
-
const ldn = hasLegacyDeviceName(value);
|
|
192
|
-
|
|
193
|
-
if (ldn) {
|
|
194
|
-
errors.push(`contains forbidden DOS legacy device name: ${ldn}`);
|
|
195
|
-
}
|
|
196
|
-
if (isInValidMSDirecotryName(value)) {
|
|
197
|
-
errors.push(`name "${value}" contains invalid characters`);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
const rc = {
|
|
204
|
-
token,
|
|
205
|
-
start: result.start,
|
|
206
|
-
end: result.end,
|
|
207
|
-
value
|
|
208
|
-
}
|
|
209
|
-
if (errors.length) {
|
|
210
|
-
rc.error = errors.join('|');
|
|
211
|
-
}
|
|
212
|
-
yield rc;
|
|
213
|
-
i = result.end + 1;
|
|
214
|
-
}
|
|
215
|
-
toggle = (++toggle % 2);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function* tdpAbsorber(str = '', start = 0, end = str.length - 1) {
|
|
220
|
-
|
|
221
|
-
let i = start;
|
|
222
|
-
// needs correction ?
|
|
223
|
-
const result = tdpRootNeedsCorrection(str.slice(i, end + 1));
|
|
224
|
-
if (result) {
|
|
225
|
-
// it should not match
|
|
226
|
-
const os = inferPlatform();
|
|
227
|
-
if (os === 'win32') { // in this case we need to have to current drive
|
|
228
|
-
/*
|
|
229
|
-
cwd can be anything "tdp", "unc", and "ddp"
|
|
230
|
-
PROOF:
|
|
231
|
-
|
|
232
|
-
> process.chdir('//./unc/pc123/c') // use a valid host and share on your machine
|
|
233
|
-
> process.cwd()
|
|
234
|
-
'\\\\.\\unc\\pc123\\c'
|
|
235
|
-
*/
|
|
236
|
-
const winRoot = getCWDDOSRoot();
|
|
237
|
-
if (winRoot) {
|
|
238
|
-
winRoot.end += start;
|
|
239
|
-
winRoot.start += start;
|
|
240
|
-
yield winRoot; // all roots DONT have '/' token
|
|
241
|
-
if (result.end >= end) { // we dont have rest-data
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
// adjust
|
|
245
|
-
str = str.slice(0, start) + winRoot.value + '\\' + str.slice(start + result.end + 1);
|
|
246
|
-
end = end + (winRoot.value.length) - (result.end + 1) + 1; //
|
|
247
|
-
i = start + winRoot.value.length;
|
|
248
|
-
yield* tdpBodyAbsorber(str, i, end);
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
// illegal char!! as a dos directory name, not good at all
|
|
253
|
-
const value = str.slice(result.start, result.end + 1);
|
|
254
|
-
yield {
|
|
255
|
-
value,
|
|
256
|
-
token: tokens.PATHELT,
|
|
257
|
-
start,
|
|
258
|
-
end: result.end,
|
|
259
|
-
error: `path ${str} contains invalid ${value} as path element`
|
|
260
|
-
};
|
|
261
|
-
i = result.end + 1;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
if (str.slice(i, end).match(uncRegExp)) {
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
let drive = str.slice(i, i + 2).toLowerCase();
|
|
269
|
-
if (drive[0] >= 'a' && drive[0] <= 'z' && drive[1] === ':') {
|
|
270
|
-
yield {
|
|
271
|
-
token: rootTokens.TDP_ROOT,
|
|
272
|
-
value: `${drive}`,
|
|
273
|
-
start: i,
|
|
274
|
-
end: i + 1
|
|
275
|
-
};
|
|
276
|
-
i = start + 2;
|
|
277
|
-
}
|
|
278
|
-
// also a unix path would work if it is win32 system
|
|
279
|
-
yield* tdpBodyAbsorber(str, i, end);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
function* uncAbsorber(str = '', start = 0, end = str.length - 1) {
|
|
283
|
-
// \\system07\C$\ servername: system07 (of fully qualified netbios, IP/FQDN address ipv4/ipv6
|
|
284
|
-
// c$: shared name
|
|
285
|
-
// \\Server2\Share\Test\Foo.txt
|
|
286
|
-
// servername: Server2
|
|
287
|
-
// shared name: Share
|
|
288
|
-
|
|
289
|
-
/* 2 "//" or 2 "\\"" are also ok in MS Windows */
|
|
290
|
-
// regexp this
|
|
291
|
-
|
|
292
|
-
const match = str.match(uncRegExp);
|
|
293
|
-
if (match === null) {
|
|
294
|
-
return; // nothing to do here
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
const server = match[2];
|
|
298
|
-
const share = match[4];
|
|
299
|
-
const value = `\\\\${server}\\${share}`;
|
|
300
|
-
const endUnc = value.length - 1;
|
|
301
|
-
|
|
302
|
-
yield {
|
|
303
|
-
token: rootTokens.UNC_ROOT,
|
|
304
|
-
value, // delimter at the end makes my IDE (vscode) do weird stuff
|
|
305
|
-
start,
|
|
306
|
-
end: endUnc
|
|
307
|
-
};
|
|
308
|
-
// at this point is should be just a normal dos parsing
|
|
309
|
-
yield* tdpBodyAbsorber(str, endUnc + 1, end);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const regExpOrderedMapDDP = [
|
|
313
|
-
// \\?\UNC\Server\Share\
|
|
314
|
-
// \\.\UNC\Server\Share\
|
|
315
|
-
['ddpwithUNC', /^(\/\/|\\\\)(.|\\?)(\/|\\)(unc)(\/|\\)([^/\\]+)(\/|\\)([^/\\]+)(\/|\\)?/i],
|
|
316
|
-
|
|
317
|
-
// example \\.\Volume{b75e2c83-0000-0000-0000-602f00000000}\
|
|
318
|
-
// example \\?\Volume{b75e2c83-0000-0000-0000-602f00000000}\
|
|
319
|
-
['ddpwithVolumeUUID', /^(\/\/|\\\\)(.|\\?)(\/|\\)(Volume{[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}})(\\|\/)?/i],
|
|
320
|
-
|
|
321
|
-
// example \\?\C:\
|
|
322
|
-
// example \\.\C:\
|
|
323
|
-
['ddpwithTDP', /^(\/\/|\\\\)(.|\\?)(\/|\\)([a-z]:)(\/|\\)?/i]
|
|
324
|
-
];
|
|
325
|
-
|
|
326
|
-
const mathMapFns = {
|
|
327
|
-
ddpwithVolumeUUID(match) {
|
|
328
|
-
const value = '\\\\?\\' + match[4];
|
|
329
|
-
return {
|
|
330
|
-
token: rootTokens.DDP_ROOT,
|
|
331
|
-
value,
|
|
332
|
-
start: 0,
|
|
333
|
-
end: value.length - 1
|
|
334
|
-
};
|
|
335
|
-
},
|
|
336
|
-
ddpwithUNC(match) {
|
|
337
|
-
const value = '\\\\?\\UNC\\' + match[6] + '\\' + match[8];
|
|
338
|
-
return {
|
|
339
|
-
token: rootTokens.DDP_ROOT,
|
|
340
|
-
value,
|
|
341
|
-
start: 0,
|
|
342
|
-
end: value.length - 1
|
|
343
|
-
};
|
|
344
|
-
},
|
|
345
|
-
ddpwithTDP(match) {
|
|
346
|
-
const value = '\\\\?\\' + match[4];
|
|
347
|
-
return {
|
|
348
|
-
token: rootTokens.DDP_ROOT,
|
|
349
|
-
value,
|
|
350
|
-
start: 0,
|
|
351
|
-
end: value.length - 1
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
function* ddpAbsorber(str = '', start = 0, end = str.length - 1) {
|
|
357
|
-
for (const [pk, regexp] of regExpOrderedMapDDP) {
|
|
358
|
-
const match = str.match(regexp);
|
|
359
|
-
if (match === null) {
|
|
360
|
-
continue;
|
|
361
|
-
}
|
|
362
|
-
const record = mathMapFns[pk] && mathMapFns[pk](match);
|
|
363
|
-
if (!record) {
|
|
364
|
-
continue;
|
|
365
|
-
}
|
|
366
|
-
record.start += start;
|
|
367
|
-
record.end += start;
|
|
368
|
-
yield record;
|
|
369
|
-
yield* tdpBodyAbsorber(str, record.end + 1, end);
|
|
370
|
-
break;
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
function getCWD() {
|
|
375
|
-
if (typeof global !== 'undefined' && global.process && global.process.cwd && typeof global.process.cwd === 'function') {
|
|
376
|
-
return global.process.cwd();
|
|
377
|
-
}
|
|
378
|
-
if (typeof window !== 'undefined'){
|
|
379
|
-
// eslint-disable-next-line no-undef
|
|
380
|
-
if (window.location && window.location.pathname) {
|
|
381
|
-
// eslint-disable-next-line no-undef
|
|
382
|
-
return window.location.pathname;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
return '/'
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
module.exports = {
|
|
389
|
-
posixAbsorber,
|
|
390
|
-
tdpAbsorber,
|
|
391
|
-
uncAbsorber,
|
|
392
|
-
ddpAbsorber,
|
|
393
|
-
tokens,
|
|
394
|
-
rootTokens,
|
|
395
|
-
rootTokenValues,
|
|
396
|
-
getCWD
|
|
397
|
-
};
|