@heyputer/puter.js 2.1.4 → 2.1.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 (57) hide show
  1. package/dist/puter.cjs +2 -2
  2. package/index.d.ts +41 -15
  3. package/package.json +1 -1
  4. package/src/index.js +116 -79
  5. package/src/lib/APICallLogger.js +20 -21
  6. package/src/lib/EventListener.js +10 -10
  7. package/src/lib/filesystem/APIFS.js +11 -19
  8. package/src/lib/filesystem/CacheFS.js +25 -25
  9. package/src/lib/filesystem/PostMessageFS.js +11 -11
  10. package/src/lib/filesystem/definitions.js +11 -10
  11. package/src/lib/path.js +505 -446
  12. package/src/lib/polyfills/fileReaderPoly.js +40 -0
  13. package/src/lib/polyfills/localStorage.js +30 -33
  14. package/src/lib/polyfills/xhrshim.js +206 -207
  15. package/src/lib/utils.js +160 -151
  16. package/src/lib/xdrpc.js +9 -9
  17. package/src/modules/AI.js +473 -292
  18. package/src/modules/Apps.js +56 -56
  19. package/src/modules/Auth.js +17 -17
  20. package/src/modules/Debug.js +1 -1
  21. package/src/modules/Drivers.js +41 -41
  22. package/src/modules/FSItem.js +64 -62
  23. package/src/modules/FileSystem/index.js +22 -23
  24. package/src/modules/FileSystem/operations/copy.js +7 -7
  25. package/src/modules/FileSystem/operations/deleteFSEntry.js +14 -12
  26. package/src/modules/FileSystem/operations/getReadUrl.js +16 -14
  27. package/src/modules/FileSystem/operations/mkdir.js +11 -11
  28. package/src/modules/FileSystem/operations/move.js +12 -12
  29. package/src/modules/FileSystem/operations/read.js +10 -10
  30. package/src/modules/FileSystem/operations/readdir.js +28 -28
  31. package/src/modules/FileSystem/operations/rename.js +11 -11
  32. package/src/modules/FileSystem/operations/sign.js +33 -30
  33. package/src/modules/FileSystem/operations/space.js +7 -7
  34. package/src/modules/FileSystem/operations/stat.js +25 -25
  35. package/src/modules/FileSystem/operations/symlink.js +15 -17
  36. package/src/modules/FileSystem/operations/upload.js +151 -122
  37. package/src/modules/FileSystem/operations/write.js +16 -12
  38. package/src/modules/FileSystem/utils/getAbsolutePathForApp.js +10 -6
  39. package/src/modules/Hosting.js +29 -29
  40. package/src/modules/KV.js +23 -23
  41. package/src/modules/OS.js +15 -15
  42. package/src/modules/Perms.js +19 -21
  43. package/src/modules/PuterDialog.js +46 -48
  44. package/src/modules/Threads.js +17 -20
  45. package/src/modules/UI.js +156 -156
  46. package/src/modules/Util.js +3 -3
  47. package/src/modules/Workers.js +52 -49
  48. package/src/modules/networking/PSocket.js +38 -38
  49. package/src/modules/networking/PTLS.js +54 -47
  50. package/src/modules/networking/PWispHandler.js +49 -47
  51. package/src/modules/networking/parsers.js +110 -108
  52. package/src/modules/networking/requests.js +67 -78
  53. package/src/services/APIAccess.js +9 -9
  54. package/src/services/FSRelay.js +6 -6
  55. package/src/services/Filesystem.js +8 -8
  56. package/src/services/NoPuterYet.js +2 -2
  57. package/src/services/XDIncoming.js +1 -1
package/src/lib/path.js CHANGED
@@ -24,486 +24,545 @@ let cwd;
24
24
  //'use strict';
25
25
 
26
26
  const
27
- CHAR_UPPERCASE_A = 65,
28
- CHAR_LOWERCASE_A = 97,
29
- CHAR_UPPERCASE_Z = 90,
30
- CHAR_LOWERCASE_Z = 122,
31
- CHAR_DOT = 46,
32
- CHAR_FORWARD_SLASH = 47,
33
- CHAR_BACKWARD_SLASH = 92,
34
- CHAR_COLON = 58,
35
- CHAR_QUESTION_MARK = 63;
36
-
37
- function isPathSeparator(code) {
38
- return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
27
+ CHAR_UPPERCASE_A = 65,
28
+ CHAR_LOWERCASE_A = 97,
29
+ CHAR_UPPERCASE_Z = 90,
30
+ CHAR_LOWERCASE_Z = 122,
31
+ CHAR_DOT = 46,
32
+ CHAR_FORWARD_SLASH = 47,
33
+ CHAR_BACKWARD_SLASH = 92,
34
+ CHAR_COLON = 58,
35
+ CHAR_QUESTION_MARK = 63;
36
+
37
+ function isPathSeparator (code) {
38
+ return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
39
39
  }
40
40
 
41
- function isPosixPathSeparator(code) {
42
- return code === CHAR_FORWARD_SLASH;
41
+ function isPosixPathSeparator (code) {
42
+ return code === CHAR_FORWARD_SLASH;
43
43
  }
44
44
 
45
45
  // Resolves . and .. elements in a path with directory names
46
- function normalizeString(path, allowAboveRoot, separator, isPathSeparator) {
47
- let res = '';
48
- let lastSegmentLength = 0;
49
- let lastSlash = -1;
50
- let dots = 0;
51
- let code = 0;
52
- for (let i = 0; i <= path.length; ++i) {
53
- if (i < path.length)
54
- code = path.charCodeAt(i);
55
- else if (isPathSeparator(code))
56
- break;
57
- else
58
- code = CHAR_FORWARD_SLASH;
59
-
60
- if (isPathSeparator(code)) {
61
- if (lastSlash === i - 1 || dots === 1) {
62
- // NOOP
63
- } else if (dots === 2) {
64
- if (res.length < 2 || lastSegmentLength !== 2 ||
65
- res.charCodeAt( res.length - 1) !== CHAR_DOT ||
66
- res.charCodeAt(res.length - 2) !== CHAR_DOT) {
67
- if (res.length > 2) {
68
- const lastSlashIndex = res.lastIndexOf(separator);
69
- if (lastSlashIndex === -1) {
70
- res = '';
71
- lastSegmentLength = 0;
72
- } else {
73
- res = res.slice(0, lastSlashIndex);
74
- lastSegmentLength =
75
- res.length - 1 - res.lastIndexOf(res, separator);
76
- }
77
- lastSlash = i;
78
- dots = 0;
79
- continue;
80
- } else if (res.length !== 0) {
81
- res = '';
82
- lastSegmentLength = 0;
83
- lastSlash = i;
84
- dots = 0;
85
- continue;
86
- }
87
- }
88
- if (allowAboveRoot) {
89
- res += res.length > 0 ? `${separator}..` : '..';
90
- lastSegmentLength = 2;
91
- }
92
- } else {
93
- if (res.length > 0)
94
- res += `${separator}${path.slice(lastSlash + 1, i)}`;
95
- else
96
- res = path.slice(lastSlash + 1, i);
97
- lastSegmentLength = i - lastSlash - 1;
98
- }
99
- lastSlash = i;
100
- dots = 0;
101
- } else if (code === CHAR_DOT && dots !== -1) {
102
- ++dots;
103
- } else {
104
- dots = -1;
105
- }
106
- }
107
- return res;
46
+ function normalizeString (path, allowAboveRoot, separator, isPathSeparator) {
47
+ let res = '';
48
+ let lastSegmentLength = 0;
49
+ let lastSlash = -1;
50
+ let dots = 0;
51
+ let code = 0;
52
+ for ( let i = 0; i <= path.length; ++i ) {
53
+ if ( i < path.length )
54
+ {
55
+ code = path.charCodeAt(i);
56
+ }
57
+ else if ( isPathSeparator(code) )
58
+ {
59
+ break;
60
+ }
61
+ else
62
+ {
63
+ code = CHAR_FORWARD_SLASH;
64
+ }
65
+
66
+ if ( isPathSeparator(code) ) {
67
+ if ( lastSlash === i - 1 || dots === 1 ) {
68
+ // NOOP
69
+ } else if ( dots === 2 ) {
70
+ if ( res.length < 2 || lastSegmentLength !== 2 ||
71
+ res.charCodeAt(res.length - 1) !== CHAR_DOT ||
72
+ res.charCodeAt(res.length - 2) !== CHAR_DOT ) {
73
+ if ( res.length > 2 ) {
74
+ const lastSlashIndex = res.lastIndexOf(separator);
75
+ if ( lastSlashIndex === -1 ) {
76
+ res = '';
77
+ lastSegmentLength = 0;
78
+ } else {
79
+ res = res.slice(0, lastSlashIndex);
80
+ lastSegmentLength =
81
+ res.length - 1 - res.lastIndexOf(res, separator);
82
+ }
83
+ lastSlash = i;
84
+ dots = 0;
85
+ continue;
86
+ } else if ( res.length !== 0 ) {
87
+ res = '';
88
+ lastSegmentLength = 0;
89
+ lastSlash = i;
90
+ dots = 0;
91
+ continue;
92
+ }
93
+ }
94
+ if ( allowAboveRoot ) {
95
+ res += res.length > 0 ? `${separator}..` : '..';
96
+ lastSegmentLength = 2;
97
+ }
98
+ } else {
99
+ if ( res.length > 0 )
100
+ {
101
+ res += `${separator}${path.slice(lastSlash + 1, i)}`;
102
+ }
103
+ else
104
+ {
105
+ res = path.slice(lastSlash + 1, i);
106
+ }
107
+ lastSegmentLength = i - lastSlash - 1;
108
+ }
109
+ lastSlash = i;
110
+ dots = 0;
111
+ } else if ( code === CHAR_DOT && dots !== -1 ) {
112
+ ++dots;
113
+ } else {
114
+ dots = -1;
115
+ }
116
+ }
117
+ return res;
108
118
  }
109
119
 
110
120
  const path = {
111
121
  // path.resolve([from ...], to)
112
- resolve(...args) {
113
- let resolvedPath = '';
114
- let resolvedAbsolute = false;
115
-
116
- for (let i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) {
122
+ resolve (...args) {
123
+ let resolvedPath = '';
124
+ let resolvedAbsolute = false;
125
+
126
+ for ( let i = args.length - 1; i >= -1 && !resolvedAbsolute; i-- ) {
117
127
  // orig const path = i >= 0 ? args[i] : posixCwd();
118
- const path = i >= 0 ? args[i] : (cwd !== undefined ? cwd : '/');
119
- // const path = i >= 0 ? args[i] : '/';
120
-
121
- // Skip empty entries
122
- if (path.length === 0) {
123
- continue;
124
- }
125
-
126
- resolvedPath = `${path}/${resolvedPath}`;
127
- resolvedAbsolute =
128
- path.charCodeAt(0) === CHAR_FORWARD_SLASH;
129
- }
130
-
131
- // At this point the path should be resolved to a full absolute path, but
132
- // handle relative paths to be safe (might happen when process.cwd() fails)
133
-
134
- // Normalize the path
135
- resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/',
136
- isPosixPathSeparator);
137
-
138
- if (resolvedAbsolute) {
139
- return `/${resolvedPath}`;
140
- }
141
- return resolvedPath.length > 0 ? resolvedPath : '.';
142
- },
143
-
144
- normalize(path) {
145
- if (path.length === 0)
146
- return '.';
147
-
148
- const isAbsolute =
149
- path.charCodeAt(0) === CHAR_FORWARD_SLASH;
150
- const trailingSeparator =
151
- path.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH;
152
-
153
- // Normalize the path
154
- path = normalizeString(path, !isAbsolute, '/', isPosixPathSeparator);
155
-
156
- if (path.length === 0) {
157
- if (isAbsolute)
158
- return '/';
159
- return trailingSeparator ? './' : '.';
160
- }
161
- if (trailingSeparator)
162
- path += '/';
163
-
164
- return isAbsolute ? `/${path}` : path;
128
+ const path = i >= 0 ? args[i] : (cwd !== undefined ? cwd : '/');
129
+ // const path = i >= 0 ? args[i] : '/';
130
+
131
+ // Skip empty entries
132
+ if ( path.length === 0 ) {
133
+ continue;
134
+ }
135
+
136
+ resolvedPath = `${path}/${resolvedPath}`;
137
+ resolvedAbsolute =
138
+ path.charCodeAt(0) === CHAR_FORWARD_SLASH;
139
+ }
140
+
141
+ // At this point the path should be resolved to a full absolute path, but
142
+ // handle relative paths to be safe (might happen when process.cwd() fails)
143
+
144
+ // Normalize the path
145
+ resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/', isPosixPathSeparator);
146
+
147
+ if ( resolvedAbsolute ) {
148
+ return `/${resolvedPath}`;
149
+ }
150
+ return resolvedPath.length > 0 ? resolvedPath : '.';
165
151
  },
166
-
167
- isAbsolute(path) {
168
- return path.length > 0 &&
169
- path.charCodeAt(0) === CHAR_FORWARD_SLASH;
152
+
153
+ normalize (path) {
154
+ if ( path.length === 0 )
155
+ {
156
+ return '.';
157
+ }
158
+
159
+ const isAbsolute =
160
+ path.charCodeAt(0) === CHAR_FORWARD_SLASH;
161
+ const trailingSeparator =
162
+ path.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH;
163
+
164
+ // Normalize the path
165
+ path = normalizeString(path, !isAbsolute, '/', isPosixPathSeparator);
166
+
167
+ if ( path.length === 0 ) {
168
+ if ( isAbsolute )
169
+ {
170
+ return '/';
171
+ }
172
+ return trailingSeparator ? './' : '.';
173
+ }
174
+ if ( trailingSeparator )
175
+ {
176
+ path += '/';
177
+ }
178
+
179
+ return isAbsolute ? `/${path}` : path;
170
180
  },
171
-
172
- join(...args) {
173
- if (args.length === 0)
174
- return '.';
175
- let joined;
176
- for (let i = 0; i < args.length; ++i) {
177
- const arg = args[i];
178
- if (arg.length > 0) {
179
- if (joined === undefined)
180
- joined = arg;
181
- else
182
- joined += `/${arg}`;
183
- }
184
- }
185
- if (joined === undefined)
186
- return '.';
187
- return path.normalize(joined);
181
+
182
+ isAbsolute (path) {
183
+ return path.length > 0 &&
184
+ path.charCodeAt(0) === CHAR_FORWARD_SLASH;
188
185
  },
189
-
190
- relative(from, to) {
191
- if (from === to)
192
- return '';
193
-
194
- // Trim leading forward slashes.
195
- from = path.resolve(from);
196
- to = path.resolve(to);
197
-
198
- if (from === to)
199
- return '';
200
-
201
- const fromStart = 1;
202
- const fromEnd = from.length;
203
- const fromLen = fromEnd - fromStart;
204
- const toStart = 1;
205
- const toLen = to.length - toStart;
206
-
207
- // Compare paths to find the longest common path from root
208
- const length = (fromLen < toLen ? fromLen : toLen);
209
- let lastCommonSep = -1;
210
- let i = 0;
211
- for (; i < length; i++) {
212
- const fromCode = from.charCodeAt(fromStart + i);
213
- if (fromCode !== to.charCodeAt(toStart + i))
214
- break;
215
- else if (fromCode === CHAR_FORWARD_SLASH)
216
- lastCommonSep = i;
217
- }
218
- if (i === length) {
219
- if (toLen > length) {
220
- if (to.charCodeAt(toStart + i) === CHAR_FORWARD_SLASH) {
221
- // We get here if `from` is the exact base path for `to`.
222
- // For example: from='/foo/bar'; to='/foo/bar/baz'
223
- return to.slice(toStart + i + 1);
224
- }
225
- if (i === 0) {
226
- // We get here if `from` is the root
227
- // For example: from='/'; to='/foo'
228
- return to.slice(toStart + i);
229
- }
230
- } else if (fromLen > length) {
231
- if (from.charCodeAt(fromStart + i) ===
232
- CHAR_FORWARD_SLASH) {
233
- // We get here if `to` is the exact base path for `from`.
234
- // For example: from='/foo/bar/baz'; to='/foo/bar'
235
- lastCommonSep = i;
236
- } else if (i === 0) {
237
- // We get here if `to` is the root.
238
- // For example: from='/foo/bar'; to='/'
239
- lastCommonSep = 0;
240
- }
241
- }
242
- }
243
-
244
- let out = '';
245
- // Generate the relative path based on the path difference between `to`
246
- // and `from`.
247
- for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {
248
- if (i === fromEnd ||
249
- from.charCodeAt(i) === CHAR_FORWARD_SLASH) {
250
- out += out.length === 0 ? '..' : '/..';
251
- }
252
- }
253
-
254
- // Lastly, append the rest of the destination (`to`) path that comes after
255
- // the common path parts.
256
- return `${out}${to.slice(toStart + lastCommonSep)}`;
186
+
187
+ join (...args) {
188
+ if ( args.length === 0 )
189
+ {
190
+ return '.';
191
+ }
192
+ let joined;
193
+ for ( let i = 0; i < args.length; ++i ) {
194
+ const arg = args[i];
195
+ if ( arg.length > 0 ) {
196
+ if ( joined === undefined )
197
+ {
198
+ joined = arg;
199
+ }
200
+ else
201
+ {
202
+ joined += `/${arg}`;
203
+ }
204
+ }
205
+ }
206
+ if ( joined === undefined )
207
+ {
208
+ return '.';
209
+ }
210
+ return path.normalize(joined);
257
211
  },
258
-
259
- toNamespacedPath(path) {
260
- // Non-op on posix systems
261
- return path;
212
+
213
+ relative (from, to) {
214
+ if ( from === to )
215
+ {
216
+ return '';
217
+ }
218
+
219
+ // Trim leading forward slashes.
220
+ from = path.resolve(from);
221
+ to = path.resolve(to);
222
+
223
+ if ( from === to )
224
+ {
225
+ return '';
226
+ }
227
+
228
+ const fromStart = 1;
229
+ const fromEnd = from.length;
230
+ const fromLen = fromEnd - fromStart;
231
+ const toStart = 1;
232
+ const toLen = to.length - toStart;
233
+
234
+ // Compare paths to find the longest common path from root
235
+ const length = (fromLen < toLen ? fromLen : toLen);
236
+ let lastCommonSep = -1;
237
+ let i = 0;
238
+ for ( ; i < length; i++ ) {
239
+ const fromCode = from.charCodeAt(fromStart + i);
240
+ if ( fromCode !== to.charCodeAt(toStart + i) )
241
+ {
242
+ break;
243
+ }
244
+ else if ( fromCode === CHAR_FORWARD_SLASH )
245
+ {
246
+ lastCommonSep = i;
247
+ }
248
+ }
249
+ if ( i === length ) {
250
+ if ( toLen > length ) {
251
+ if ( to.charCodeAt(toStart + i) === CHAR_FORWARD_SLASH ) {
252
+ // We get here if `from` is the exact base path for `to`.
253
+ // For example: from='/foo/bar'; to='/foo/bar/baz'
254
+ return to.slice(toStart + i + 1);
255
+ }
256
+ if ( i === 0 ) {
257
+ // We get here if `from` is the root
258
+ // For example: from='/'; to='/foo'
259
+ return to.slice(toStart + i);
260
+ }
261
+ } else if ( fromLen > length ) {
262
+ if ( from.charCodeAt(fromStart + i) ===
263
+ CHAR_FORWARD_SLASH ) {
264
+ // We get here if `to` is the exact base path for `from`.
265
+ // For example: from='/foo/bar/baz'; to='/foo/bar'
266
+ lastCommonSep = i;
267
+ } else if ( i === 0 ) {
268
+ // We get here if `to` is the root.
269
+ // For example: from='/foo/bar'; to='/'
270
+ lastCommonSep = 0;
271
+ }
272
+ }
273
+ }
274
+
275
+ let out = '';
276
+ // Generate the relative path based on the path difference between `to`
277
+ // and `from`.
278
+ for ( i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i ) {
279
+ if ( i === fromEnd ||
280
+ from.charCodeAt(i) === CHAR_FORWARD_SLASH ) {
281
+ out += out.length === 0 ? '..' : '/..';
282
+ }
283
+ }
284
+
285
+ // Lastly, append the rest of the destination (`to`) path that comes after
286
+ // the common path parts.
287
+ return `${out}${to.slice(toStart + lastCommonSep)}`;
262
288
  },
263
-
264
- dirname(path) {
265
- if (path.length === 0)
266
- return '.';
267
- const hasRoot = path.charCodeAt(0) === CHAR_FORWARD_SLASH;
268
- let end = -1;
269
- let matchedSlash = true;
270
- for (let i = path.length - 1; i >= 1; --i) {
271
- if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) {
272
- if (!matchedSlash) {
273
- end = i;
274
- break;
275
- }
276
- } else {
277
- // We saw the first non-path separator
278
- matchedSlash = false;
279
- }
280
- }
281
-
282
- if (end === -1)
283
- return hasRoot ? '/' : '.';
284
- if (hasRoot && end === 1)
285
- return '//';
286
- return path.slice(0, end);
289
+
290
+ toNamespacedPath (path) {
291
+ // Non-op on posix systems
292
+ return path;
287
293
  },
288
-
289
- basename(path, ext) {
290
- let start = 0;
291
- let end = -1;
292
- let matchedSlash = true;
293
-
294
- if (ext !== undefined && ext.length > 0 && ext.length <= path.length) {
295
- if (ext === path)
296
- return '';
297
- let extIdx = ext.length - 1;
298
- let firstNonSlashEnd = -1;
299
- for (let i = path.length - 1; i >= 0; --i) {
300
- const code = path.charCodeAt(i);
301
- if (code === CHAR_FORWARD_SLASH) {
302
- // If we reached a path separator that was not part of a set of path
303
- // separators at the end of the string, stop now
304
- if (!matchedSlash) {
305
- start = i + 1;
306
- break;
294
+
295
+ dirname (path) {
296
+ if ( path.length === 0 )
297
+ {
298
+ return '.';
299
+ }
300
+ const hasRoot = path.charCodeAt(0) === CHAR_FORWARD_SLASH;
301
+ let end = -1;
302
+ let matchedSlash = true;
303
+ for ( let i = path.length - 1; i >= 1; --i ) {
304
+ if ( path.charCodeAt(i) === CHAR_FORWARD_SLASH ) {
305
+ if ( ! matchedSlash ) {
306
+ end = i;
307
+ break;
308
+ }
309
+ } else {
310
+ // We saw the first non-path separator
311
+ matchedSlash = false;
307
312
  }
308
- } else {
309
- if (firstNonSlashEnd === -1) {
310
- // We saw the first non-path separator, remember this index in case
311
- // we need it if the extension ends up not matching
312
- matchedSlash = false;
313
- firstNonSlashEnd = i + 1;
313
+ }
314
+
315
+ if ( end === -1 )
316
+ {
317
+ return hasRoot ? '/' : '.';
318
+ }
319
+ if ( hasRoot && end === 1 )
320
+ {
321
+ return '//';
322
+ }
323
+ return path.slice(0, end);
324
+ },
325
+
326
+ basename (path, ext) {
327
+ let start = 0;
328
+ let end = -1;
329
+ let matchedSlash = true;
330
+
331
+ if ( ext !== undefined && ext.length > 0 && ext.length <= path.length ) {
332
+ if ( ext === path )
333
+ {
334
+ return '';
314
335
  }
315
- if (extIdx >= 0) {
316
- // Try to match the explicit extension
317
- if (code === ext.charCodeAt(extIdx)) {
318
- if (--extIdx === -1) {
319
- // We matched the extension, so mark this as the end of our path
320
- // component
321
- end = i;
336
+ let extIdx = ext.length - 1;
337
+ let firstNonSlashEnd = -1;
338
+ for ( let i = path.length - 1; i >= 0; --i ) {
339
+ const code = path.charCodeAt(i);
340
+ if ( code === CHAR_FORWARD_SLASH ) {
341
+ // If we reached a path separator that was not part of a set of path
342
+ // separators at the end of the string, stop now
343
+ if ( ! matchedSlash ) {
344
+ start = i + 1;
345
+ break;
346
+ }
347
+ } else {
348
+ if ( firstNonSlashEnd === -1 ) {
349
+ // We saw the first non-path separator, remember this index in case
350
+ // we need it if the extension ends up not matching
351
+ matchedSlash = false;
352
+ firstNonSlashEnd = i + 1;
353
+ }
354
+ if ( extIdx >= 0 ) {
355
+ // Try to match the explicit extension
356
+ if ( code === ext.charCodeAt(extIdx) ) {
357
+ if ( --extIdx === -1 ) {
358
+ // We matched the extension, so mark this as the end of our path
359
+ // component
360
+ end = i;
361
+ }
362
+ } else {
363
+ // Extension does not match, so our result is the entire path
364
+ // component
365
+ extIdx = -1;
366
+ end = firstNonSlashEnd;
367
+ }
368
+ }
322
369
  }
323
- } else {
324
- // Extension does not match, so our result is the entire path
325
- // component
326
- extIdx = -1;
370
+ }
371
+
372
+ if ( start === end )
373
+ {
327
374
  end = firstNonSlashEnd;
328
- }
329
375
  }
330
- }
376
+ else if ( end === -1 )
377
+ {
378
+ end = path.length;
379
+ }
380
+ return path.slice(start, end);
381
+ }
382
+ for ( let i = path.length - 1; i >= 0; --i ) {
383
+ if ( path.charCodeAt(i) === CHAR_FORWARD_SLASH ) {
384
+ // If we reached a path separator that was not part of a set of path
385
+ // separators at the end of the string, stop now
386
+ if ( ! matchedSlash ) {
387
+ start = i + 1;
388
+ break;
389
+ }
390
+ } else if ( end === -1 ) {
391
+ // We saw the first non-path separator, mark this as the end of our
392
+ // path component
393
+ matchedSlash = false;
394
+ end = i + 1;
395
+ }
396
+ }
397
+
398
+ if ( end === -1 )
399
+ {
400
+ return '';
331
401
  }
332
-
333
- if (start === end)
334
- end = firstNonSlashEnd;
335
- else if (end === -1)
336
- end = path.length;
337
402
  return path.slice(start, end);
338
- }
339
- for (let i = path.length - 1; i >= 0; --i) {
340
- if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) {
341
- // If we reached a path separator that was not part of a set of path
342
- // separators at the end of the string, stop now
343
- if (!matchedSlash) {
344
- start = i + 1;
345
- break;
346
- }
347
- } else if (end === -1) {
348
- // We saw the first non-path separator, mark this as the end of our
349
- // path component
350
- matchedSlash = false;
351
- end = i + 1;
352
- }
353
- }
354
-
355
- if (end === -1)
356
- return '';
357
- return path.slice(start, end);
358
- },
359
-
360
- extname(path) {
361
- let startDot = -1;
362
- let startPart = 0;
363
- let end = -1;
364
- let matchedSlash = true;
365
- // Track the state of characters (if any) we see before our first dot and
366
- // after any path separator we find
367
- let preDotState = 0;
368
- for (let i = path.length - 1; i >= 0; --i) {
369
- const code = path.charCodeAt(i);
370
- if (code === CHAR_FORWARD_SLASH) {
371
- // If we reached a path separator that was not part of a set of path
372
- // separators at the end of the string, stop now
373
- if (!matchedSlash) {
374
- startPart = i + 1;
375
- break;
376
- }
377
- continue;
378
- }
379
- if (end === -1) {
380
- // We saw the first non-path separator, mark this as the end of our
381
- // extension
382
- matchedSlash = false;
383
- end = i + 1;
384
- }
385
- if (code === CHAR_DOT) {
386
- // If this is our first dot, mark it as the start of our extension
387
- if (startDot === -1)
388
- startDot = i;
389
- else if (preDotState !== 1)
390
- preDotState = 1;
391
- } else if (startDot !== -1) {
392
- // We saw a non-dot and non-path separator before our dot, so we should
393
- // have a good chance at having a non-empty extension
394
- preDotState = -1;
395
- }
396
- }
397
-
398
- if (startDot === -1 ||
399
- end === -1 ||
400
- // We saw a non-dot character immediately before the dot
401
- preDotState === 0 ||
402
- // The (right-most) trimmed path component is exactly '..'
403
- (preDotState === 1 &&
404
- startDot === end - 1 &&
405
- startDot === startPart + 1)) {
406
- return '';
407
- }
408
- return path.slice(startDot, end);
409
403
  },
410
-
411
- format: _format.bind( null, '/'),
412
-
413
- parse(path) {
414
- const ret = { root: '', dir: '', base: '', ext: '', name: '' };
415
- if (path.length === 0)
416
- return ret;
417
- const isAbsolute =
418
- path.charCodeAt(0) === CHAR_FORWARD_SLASH;
419
- let start;
420
- if (isAbsolute) {
421
- ret.root = '/';
422
- start = 1;
423
- } else {
424
- start = 0;
425
- }
426
- let startDot = -1;
427
- let startPart = 0;
428
- let end = -1;
429
- let matchedSlash = true;
430
- let i = path.length - 1;
431
-
432
- // Track the state of characters (if any) we see before our first dot and
433
- // after any path separator we find
434
- let preDotState = 0;
435
-
436
- // Get non-dir info
437
- for (; i >= start; --i) {
438
- const code = path.charCodeAt(i);
439
- if (code === CHAR_FORWARD_SLASH) {
440
- // If we reached a path separator that was not part of a set of path
441
- // separators at the end of the string, stop now
442
- if (!matchedSlash) {
443
- startPart = i + 1;
444
- break;
445
- }
446
- continue;
447
- }
448
- if (end === -1) {
449
- // We saw the first non-path separator, mark this as the end of our
450
- // extension
451
- matchedSlash = false;
452
- end = i + 1;
453
- }
454
- if (code === CHAR_DOT) {
455
- // If this is our first dot, mark it as the start of our extension
456
- if (startDot === -1)
457
- startDot = i;
458
- else if (preDotState !== 1)
459
- preDotState = 1;
460
- } else if (startDot !== -1) {
461
- // We saw a non-dot and non-path separator before our dot, so we should
462
- // have a good chance at having a non-empty extension
463
- preDotState = -1;
464
- }
465
- }
466
-
467
- if (end !== -1) {
468
- const start = startPart === 0 && isAbsolute ? 1 : startPart;
469
- if (startDot === -1 ||
470
- // We saw a non-dot character immediately before the dot
404
+
405
+ extname (path) {
406
+ let startDot = -1;
407
+ let startPart = 0;
408
+ let end = -1;
409
+ let matchedSlash = true;
410
+ // Track the state of characters (if any) we see before our first dot and
411
+ // after any path separator we find
412
+ let preDotState = 0;
413
+ for ( let i = path.length - 1; i >= 0; --i ) {
414
+ const code = path.charCodeAt(i);
415
+ if ( code === CHAR_FORWARD_SLASH ) {
416
+ // If we reached a path separator that was not part of a set of path
417
+ // separators at the end of the string, stop now
418
+ if ( ! matchedSlash ) {
419
+ startPart = i + 1;
420
+ break;
421
+ }
422
+ continue;
423
+ }
424
+ if ( end === -1 ) {
425
+ // We saw the first non-path separator, mark this as the end of our
426
+ // extension
427
+ matchedSlash = false;
428
+ end = i + 1;
429
+ }
430
+ if ( code === CHAR_DOT ) {
431
+ // If this is our first dot, mark it as the start of our extension
432
+ if ( startDot === -1 )
433
+ {
434
+ startDot = i;
435
+ }
436
+ else if ( preDotState !== 1 )
437
+ {
438
+ preDotState = 1;
439
+ }
440
+ } else if ( startDot !== -1 ) {
441
+ // We saw a non-dot and non-path separator before our dot, so we should
442
+ // have a good chance at having a non-empty extension
443
+ preDotState = -1;
444
+ }
445
+ }
446
+
447
+ if ( startDot === -1 ||
448
+ end === -1 ||
449
+ // We saw a non-dot character immediately before the dot
471
450
  preDotState === 0 ||
472
- // The (right-most) trimmed path component is exactly '..'
451
+ // The (right-most) trimmed path component is exactly '..'
473
452
  (preDotState === 1 &&
474
- startDot === end - 1 &&
475
- startDot === startPart + 1)) {
476
- ret.base = ret.name = path.slice(start, end);
453
+ startDot === end - 1 &&
454
+ startDot === startPart + 1) ) {
455
+ return '';
456
+ }
457
+ return path.slice(startDot, end);
458
+ },
459
+
460
+ format: _format.bind(null, '/'),
461
+
462
+ parse (path) {
463
+ const ret = { root: '', dir: '', base: '', ext: '', name: '' };
464
+ if ( path.length === 0 )
465
+ {
466
+ return ret;
467
+ }
468
+ const isAbsolute =
469
+ path.charCodeAt(0) === CHAR_FORWARD_SLASH;
470
+ let start;
471
+ if ( isAbsolute ) {
472
+ ret.root = '/';
473
+ start = 1;
477
474
  } else {
478
- ret.name = path.slice(start, startDot);
479
- ret.base = path.slice(start, end);
480
- ret.ext = path.slice(startDot, end);
481
- }
482
- }
483
-
484
- if (startPart > 0)
485
- ret.dir = path.slice(0, startPart - 1);
486
- else if (isAbsolute)
487
- ret.dir = '/';
488
-
489
- return ret;
475
+ start = 0;
476
+ }
477
+ let startDot = -1;
478
+ let startPart = 0;
479
+ let end = -1;
480
+ let matchedSlash = true;
481
+ let i = path.length - 1;
482
+
483
+ // Track the state of characters (if any) we see before our first dot and
484
+ // after any path separator we find
485
+ let preDotState = 0;
486
+
487
+ // Get non-dir info
488
+ for ( ; i >= start; --i ) {
489
+ const code = path.charCodeAt(i);
490
+ if ( code === CHAR_FORWARD_SLASH ) {
491
+ // If we reached a path separator that was not part of a set of path
492
+ // separators at the end of the string, stop now
493
+ if ( ! matchedSlash ) {
494
+ startPart = i + 1;
495
+ break;
496
+ }
497
+ continue;
498
+ }
499
+ if ( end === -1 ) {
500
+ // We saw the first non-path separator, mark this as the end of our
501
+ // extension
502
+ matchedSlash = false;
503
+ end = i + 1;
504
+ }
505
+ if ( code === CHAR_DOT ) {
506
+ // If this is our first dot, mark it as the start of our extension
507
+ if ( startDot === -1 )
508
+ {
509
+ startDot = i;
510
+ }
511
+ else if ( preDotState !== 1 )
512
+ {
513
+ preDotState = 1;
514
+ }
515
+ } else if ( startDot !== -1 ) {
516
+ // We saw a non-dot and non-path separator before our dot, so we should
517
+ // have a good chance at having a non-empty extension
518
+ preDotState = -1;
519
+ }
520
+ }
521
+
522
+ if ( end !== -1 ) {
523
+ const start = startPart === 0 && isAbsolute ? 1 : startPart;
524
+ if ( startDot === -1 ||
525
+ // We saw a non-dot character immediately before the dot
526
+ preDotState === 0 ||
527
+ // The (right-most) trimmed path component is exactly '..'
528
+ (preDotState === 1 &&
529
+ startDot === end - 1 &&
530
+ startDot === startPart + 1) ) {
531
+ ret.base = ret.name = path.slice(start, end);
532
+ } else {
533
+ ret.name = path.slice(start, startDot);
534
+ ret.base = path.slice(start, end);
535
+ ret.ext = path.slice(startDot, end);
536
+ }
537
+ }
538
+
539
+ if ( startPart > 0 )
540
+ {
541
+ ret.dir = path.slice(0, startPart - 1);
542
+ }
543
+ else if ( isAbsolute )
544
+ {
545
+ ret.dir = '/';
546
+ }
547
+
548
+ return ret;
490
549
  },
491
-
550
+
492
551
  sep: '/',
493
552
  delimiter: ':',
494
553
  win32: null,
495
- posix: null
496
- };
554
+ posix: null,
555
+ };
497
556
 
498
- function _format(sep, pathObject) {
557
+ function _format (sep, pathObject) {
499
558
  validateObject(pathObject, 'pathObject');
500
559
  const dir = pathObject.dir || pathObject.root;
501
560
  const base = pathObject.base ||
502
- `${pathObject.name || ''}${pathObject.ext || ''}`;
503
- if (!dir) {
504
- return base;
561
+ `${pathObject.name || ''}${pathObject.ext || ''}`;
562
+ if ( ! dir ) {
563
+ return base;
505
564
  }
506
565
  return dir === pathObject.root ? `${dir}${base}` : `${dir}${sep}${base}`;
507
- }
508
-
509
- export default path
566
+ }
567
+
568
+ export default path;