@grain/stdlib 0.5.13 → 0.6.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/CHANGELOG.md +193 -0
- package/LICENSE +1 -1
- package/README.md +25 -2
- package/array.gr +1512 -199
- package/array.md +2032 -94
- package/bigint.gr +239 -140
- package/bigint.md +450 -106
- package/buffer.gr +595 -102
- package/buffer.md +903 -145
- package/bytes.gr +401 -110
- package/bytes.md +551 -63
- package/char.gr +228 -49
- package/char.md +373 -7
- package/exception.gr +26 -12
- package/exception.md +29 -5
- package/float32.gr +130 -109
- package/float32.md +185 -57
- package/float64.gr +112 -99
- package/float64.md +185 -57
- package/hash.gr +47 -37
- package/hash.md +21 -3
- package/int16.gr +430 -0
- package/int16.md +618 -0
- package/int32.gr +200 -269
- package/int32.md +254 -289
- package/int64.gr +142 -225
- package/int64.md +254 -289
- package/int8.gr +511 -0
- package/int8.md +786 -0
- package/json.gr +2084 -0
- package/json.md +608 -0
- package/list.gr +120 -68
- package/list.md +125 -80
- package/map.gr +560 -57
- package/map.md +672 -56
- package/marshal.gr +239 -227
- package/marshal.md +36 -4
- package/number.gr +626 -676
- package/number.md +738 -153
- package/option.gr +33 -35
- package/option.md +58 -42
- package/package.json +2 -2
- package/path.gr +148 -187
- package/path.md +47 -96
- package/pervasives.gr +75 -416
- package/pervasives.md +85 -180
- package/priorityqueue.gr +433 -74
- package/priorityqueue.md +422 -54
- package/queue.gr +362 -80
- package/queue.md +433 -38
- package/random.gr +67 -75
- package/random.md +68 -40
- package/range.gr +135 -63
- package/range.md +198 -43
- package/rational.gr +284 -0
- package/rational.md +545 -0
- package/regex.gr +933 -1066
- package/regex.md +59 -60
- package/result.gr +23 -25
- package/result.md +54 -39
- package/runtime/atof/common.gr +78 -82
- package/runtime/atof/common.md +22 -10
- package/runtime/atof/decimal.gr +102 -127
- package/runtime/atof/decimal.md +28 -7
- package/runtime/atof/lemire.gr +56 -71
- package/runtime/atof/lemire.md +9 -1
- package/runtime/atof/parse.gr +83 -110
- package/runtime/atof/parse.md +12 -2
- package/runtime/atof/slow.gr +28 -35
- package/runtime/atof/slow.md +9 -1
- package/runtime/atof/table.gr +19 -18
- package/runtime/atof/table.md +10 -2
- package/runtime/atoi/parse.gr +153 -136
- package/runtime/atoi/parse.md +50 -1
- package/runtime/bigint.gr +410 -517
- package/runtime/bigint.md +71 -57
- package/runtime/compare.gr +176 -85
- package/runtime/compare.md +31 -1
- package/runtime/dataStructures.gr +144 -32
- package/runtime/dataStructures.md +267 -31
- package/runtime/debugPrint.gr +34 -15
- package/runtime/debugPrint.md +37 -5
- package/runtime/equal.gr +53 -52
- package/runtime/equal.md +30 -1
- package/runtime/exception.gr +38 -47
- package/runtime/exception.md +10 -8
- package/runtime/gc.gr +23 -152
- package/runtime/gc.md +13 -17
- package/runtime/malloc.gr +31 -31
- package/runtime/malloc.md +11 -3
- package/runtime/numberUtils.gr +191 -172
- package/runtime/numberUtils.md +17 -9
- package/runtime/numbers.gr +1695 -1021
- package/runtime/numbers.md +1098 -134
- package/runtime/string.gr +540 -242
- package/runtime/string.md +76 -6
- package/runtime/unsafe/constants.gr +30 -13
- package/runtime/unsafe/constants.md +80 -0
- package/runtime/unsafe/conv.gr +55 -28
- package/runtime/unsafe/conv.md +41 -9
- package/runtime/unsafe/memory.gr +10 -30
- package/runtime/unsafe/memory.md +15 -19
- package/runtime/unsafe/tags.gr +37 -21
- package/runtime/unsafe/tags.md +88 -8
- package/runtime/unsafe/wasmf32.gr +30 -36
- package/runtime/unsafe/wasmf32.md +64 -56
- package/runtime/unsafe/wasmf64.gr +30 -36
- package/runtime/unsafe/wasmf64.md +64 -56
- package/runtime/unsafe/wasmi32.gr +49 -66
- package/runtime/unsafe/wasmi32.md +102 -94
- package/runtime/unsafe/wasmi64.gr +52 -79
- package/runtime/unsafe/wasmi64.md +108 -100
- package/runtime/utils/printing.gr +13 -15
- package/runtime/utils/printing.md +11 -3
- package/runtime/wasi.gr +294 -295
- package/runtime/wasi.md +62 -42
- package/set.gr +574 -64
- package/set.md +634 -54
- package/stack.gr +181 -64
- package/stack.md +271 -42
- package/string.gr +453 -533
- package/string.md +241 -151
- package/uint16.gr +369 -0
- package/uint16.md +585 -0
- package/uint32.gr +470 -0
- package/uint32.md +737 -0
- package/uint64.gr +471 -0
- package/uint64.md +737 -0
- package/uint8.gr +369 -0
- package/uint8.md +585 -0
- package/uri.gr +1093 -0
- package/uri.md +477 -0
- package/{sys → wasi}/file.gr +914 -500
- package/{sys → wasi}/file.md +454 -50
- package/wasi/process.gr +292 -0
- package/{sys → wasi}/process.md +164 -6
- package/wasi/random.gr +77 -0
- package/wasi/random.md +80 -0
- package/{sys → wasi}/time.gr +15 -22
- package/{sys → wasi}/time.md +5 -5
- package/immutablearray.gr +0 -929
- package/immutablearray.md +0 -1038
- package/immutablemap.gr +0 -493
- package/immutablemap.md +0 -479
- package/immutablepriorityqueue.gr +0 -360
- package/immutablepriorityqueue.md +0 -291
- package/immutableset.gr +0 -498
- package/immutableset.md +0 -449
- package/runtime/debug.gr +0 -2
- package/runtime/debug.md +0 -6
- package/runtime/unsafe/errors.gr +0 -36
- package/runtime/unsafe/errors.md +0 -204
- package/sys/process.gr +0 -254
- package/sys/random.gr +0 -79
- package/sys/random.md +0 -66
package/path.gr
CHANGED
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Utilities for working with system paths.
|
|
3
|
+
*
|
|
4
4
|
* This module treats paths purely as a data representation and does not
|
|
5
5
|
* provide functionality for interacting with the file system.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* This module explicitly encodes whether a path is absolute or relative, and
|
|
8
8
|
* whether it refers to a file or a directory, as part of the `Path` type.
|
|
9
9
|
*
|
|
10
10
|
* Paths in this module abide by a special POSIX-like representation/grammar
|
|
11
11
|
* rather than one defined by a specific operating system. The rules are as
|
|
12
12
|
* follows:
|
|
13
|
-
*
|
|
13
|
+
*
|
|
14
14
|
* - Path separators are denoted by `/` for POSIX-like paths
|
|
15
15
|
* - Absolute paths may be rooted either at the POSIX-like root `/` or at Windows-like drive roots like `C:/`
|
|
16
16
|
* - Paths referencing files must not include trailing forward slashes, but paths referencing directories may
|
|
17
17
|
* - The path segment `.` indicates the relative "current" directory of a path, and `..` indicates the parent directory of a path
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
*
|
|
18
|
+
*
|
|
19
|
+
* @example from "path" include Path
|
|
20
|
+
*
|
|
21
21
|
* @since v0.5.5
|
|
22
22
|
*/
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
module Path
|
|
24
|
+
|
|
25
|
+
from "string" include String
|
|
26
|
+
from "list" include List
|
|
27
|
+
from "option" include Option
|
|
28
|
+
from "result" include Result
|
|
29
|
+
from "char" include Char
|
|
28
30
|
|
|
29
31
|
// this module is influenced by https://github.com/reasonml/reason-native/blob/a0ddab6ab25237961e32d8732b0a222ec2372d4a/src/fp/Fp.re
|
|
30
32
|
// with some modifications; reason-native license:
|
|
@@ -76,22 +78,18 @@ record TFileType<a> {
|
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
// Rel(Number) represents the number of directories up from the base point
|
|
79
|
-
enum Base {
|
|
81
|
+
enum rec Base {
|
|
80
82
|
Rel(Number),
|
|
81
83
|
Abs(AbsoluteRoot),
|
|
82
|
-
}
|
|
83
|
-
type PathInfo = (Base, FileType, List<String>)
|
|
84
|
-
record TBase<a> {
|
|
84
|
+
}
|
|
85
|
+
and type PathInfo = (Base, FileType, List<String>)
|
|
86
|
+
and record TBase<a> {
|
|
85
87
|
base: Base,
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* @section Types: Type declarations included in the Path module.
|
|
89
|
-
*/
|
|
90
|
-
|
|
88
|
+
}
|
|
91
89
|
/**
|
|
92
90
|
* Represents an absolute path's anchor point.
|
|
93
91
|
*/
|
|
94
|
-
|
|
92
|
+
and provide enum AbsoluteRoot {
|
|
95
93
|
Root,
|
|
96
94
|
Drive(Char),
|
|
97
95
|
}
|
|
@@ -101,28 +99,28 @@ export enum AbsoluteRoot {
|
|
|
101
99
|
/**
|
|
102
100
|
* Represents a relative path.
|
|
103
101
|
*/
|
|
104
|
-
record Relative {
|
|
102
|
+
abstract record Relative {
|
|
105
103
|
_rel: Void,
|
|
106
104
|
}
|
|
107
105
|
|
|
108
106
|
/**
|
|
109
107
|
* Represents an absolute path.
|
|
110
108
|
*/
|
|
111
|
-
record Absolute {
|
|
109
|
+
abstract record Absolute {
|
|
112
110
|
_abs: Void,
|
|
113
111
|
}
|
|
114
112
|
|
|
115
113
|
/**
|
|
116
114
|
* Represents a path referencing a file.
|
|
117
115
|
*/
|
|
118
|
-
record File {
|
|
116
|
+
abstract record File {
|
|
119
117
|
_file: Void,
|
|
120
118
|
}
|
|
121
119
|
|
|
122
120
|
/**
|
|
123
121
|
* Represents a path referencing a directory.
|
|
124
122
|
*/
|
|
125
|
-
record Directory {
|
|
123
|
+
abstract record Directory {
|
|
126
124
|
_directory: Void,
|
|
127
125
|
}
|
|
128
126
|
|
|
@@ -130,11 +128,11 @@ record Directory {
|
|
|
130
128
|
* Represents a path typed on (`Absolute` or `Relative`) and (`File` or
|
|
131
129
|
* `Directory`)
|
|
132
130
|
*/
|
|
133
|
-
type TypedPath<a, b> = (TBase<a>, TFileType<b>, List<String>)
|
|
131
|
+
abstract type rec TypedPath<a, b> = (TBase<a>, TFileType<b>, List<String>)
|
|
134
132
|
/**
|
|
135
133
|
* Represents a system path.
|
|
136
134
|
*/
|
|
137
|
-
|
|
135
|
+
and provide enum Path {
|
|
138
136
|
AbsoluteFile(TypedPath<Absolute, File>),
|
|
139
137
|
AbsoluteDir(TypedPath<Absolute, Directory>),
|
|
140
138
|
RelativeFile(TypedPath<Relative, File>),
|
|
@@ -144,7 +142,7 @@ export enum Path {
|
|
|
144
142
|
/**
|
|
145
143
|
* Represents a platform-specific path encoding scheme.
|
|
146
144
|
*/
|
|
147
|
-
|
|
145
|
+
provide enum Platform {
|
|
148
146
|
Windows,
|
|
149
147
|
Posix,
|
|
150
148
|
}
|
|
@@ -152,14 +150,14 @@ export enum Platform {
|
|
|
152
150
|
/**
|
|
153
151
|
* Represents an error that can occur when finding a property of a path.
|
|
154
152
|
*/
|
|
155
|
-
|
|
153
|
+
provide enum PathOperationError {
|
|
156
154
|
IncompatiblePathType,
|
|
157
155
|
}
|
|
158
156
|
|
|
159
157
|
/**
|
|
160
158
|
* Represents an error that can occur when appending paths.
|
|
161
159
|
*/
|
|
162
|
-
|
|
160
|
+
provide enum AppendError {
|
|
163
161
|
AppendToFile,
|
|
164
162
|
AppendAbsolute,
|
|
165
163
|
}
|
|
@@ -167,7 +165,7 @@ export enum AppendError {
|
|
|
167
165
|
/**
|
|
168
166
|
* Represents the status of an ancestry check between two paths.
|
|
169
167
|
*/
|
|
170
|
-
|
|
168
|
+
provide enum AncestryStatus {
|
|
171
169
|
Descendant,
|
|
172
170
|
Ancestor,
|
|
173
171
|
Self,
|
|
@@ -178,7 +176,7 @@ export enum AncestryStatus {
|
|
|
178
176
|
* Represents an error that can occur when the types of paths are incompatible
|
|
179
177
|
* for an operation.
|
|
180
178
|
*/
|
|
181
|
-
|
|
179
|
+
provide enum IncompatibilityError {
|
|
182
180
|
DifferentRoots,
|
|
183
181
|
DifferentBases,
|
|
184
182
|
}
|
|
@@ -186,15 +184,11 @@ export enum IncompatibilityError {
|
|
|
186
184
|
/**
|
|
187
185
|
* Represents possible errors for the `relativeTo` operation.
|
|
188
186
|
*/
|
|
189
|
-
|
|
187
|
+
provide enum RelativizationError {
|
|
190
188
|
Incompatible(IncompatibilityError),
|
|
191
189
|
ImpossibleRelativization,
|
|
192
190
|
}
|
|
193
191
|
|
|
194
|
-
/**
|
|
195
|
-
* @section Values: Functions for working with Paths.
|
|
196
|
-
*/
|
|
197
|
-
|
|
198
192
|
let makeToken = str => {
|
|
199
193
|
match (str) {
|
|
200
194
|
"." => Dot,
|
|
@@ -232,7 +226,7 @@ let lexPath = (pathStr, platform) => {
|
|
|
232
226
|
for (let mut i = 0; i < len; i += 1) {
|
|
233
227
|
if (isSeparator(String.charAt(i, pathStr))) {
|
|
234
228
|
if (segBeginI != i) {
|
|
235
|
-
let tok = makeToken(String.slice(segBeginI, i, pathStr))
|
|
229
|
+
let tok = makeToken(String.slice(segBeginI, end=i, pathStr))
|
|
236
230
|
revTokens = [tok, ...revTokens]
|
|
237
231
|
}
|
|
238
232
|
revTokens = [Slash, ...revTokens]
|
|
@@ -240,7 +234,7 @@ let lexPath = (pathStr, platform) => {
|
|
|
240
234
|
}
|
|
241
235
|
}
|
|
242
236
|
if (segBeginI < len) {
|
|
243
|
-
let lastPart = String.slice(segBeginI, len, pathStr)
|
|
237
|
+
let lastPart = String.slice(segBeginI, end=len, pathStr)
|
|
244
238
|
revTokens = [makeToken(lastPart), ...revTokens]
|
|
245
239
|
}
|
|
246
240
|
List.reverse(revTokens)
|
|
@@ -304,7 +298,7 @@ let parseAbs = (tokens, fileType) => {
|
|
|
304
298
|
}
|
|
305
299
|
}
|
|
306
300
|
|
|
307
|
-
// TODO(#1496):
|
|
301
|
+
// TODO(#1496): provide these functions once module system added
|
|
308
302
|
|
|
309
303
|
let absoluteFile = tokens => {
|
|
310
304
|
let pathOpt = parseAbs(tokens, File)
|
|
@@ -359,53 +353,37 @@ let fromStringHelper = (pathStr, platform) => {
|
|
|
359
353
|
}
|
|
360
354
|
let isDir = !isFilePath(tokens)
|
|
361
355
|
|
|
362
|
-
let path = (
|
|
363
|
-
|
|
364
|
-
Option.expect("Impossible: failed parse of " ++ pathType, mkPath(tokens))
|
|
365
|
-
)
|
|
356
|
+
let path = (mkPath, pathType) => {
|
|
357
|
+
Option.expect("Impossible: failed parse of " ++ pathType, mkPath(tokens))
|
|
366
358
|
}
|
|
367
359
|
|
|
368
360
|
match ((isAbs, isDir)) {
|
|
369
|
-
(true, true) => path(
|
|
370
|
-
(true, false) => path(
|
|
371
|
-
(false, true) => path(
|
|
372
|
-
(false, false) => path(
|
|
361
|
+
(true, true) => AbsoluteDir(path(absoluteDir, "absolute dir")),
|
|
362
|
+
(true, false) => AbsoluteFile(path(absoluteFile, "absolute file")),
|
|
363
|
+
(false, true) => RelativeDir(path(relativeDir, "relative dir")),
|
|
364
|
+
(false, false) => RelativeFile(path(relativeFile, "relative file")),
|
|
373
365
|
}
|
|
374
366
|
}
|
|
375
367
|
|
|
376
|
-
/**
|
|
377
|
-
* Parses a path string into a `Path`. Paths will be parsed as file paths
|
|
378
|
-
* rather than directory paths if there is ambiguity.
|
|
379
|
-
*
|
|
380
|
-
* @param pathStr: The string to parse as a path
|
|
381
|
-
* @returns The path wrapped with details encoded within the type
|
|
382
|
-
*
|
|
383
|
-
* @example fromString("/bin/") // an absolute Path referencing the directory /bin/
|
|
384
|
-
* @example fromString("file.txt") // a relative Path referencing the file ./file.txt
|
|
385
|
-
* @example fromString(".") // a relative Path referencing the current directory
|
|
386
|
-
*
|
|
387
|
-
* @since v0.5.5
|
|
388
|
-
*/
|
|
389
|
-
export let fromString = pathStr => {
|
|
390
|
-
fromStringHelper(pathStr, Posix)
|
|
391
|
-
}
|
|
392
|
-
|
|
393
368
|
/**
|
|
394
369
|
* Parses a path string into a `Path` using the path separators appropriate to
|
|
395
370
|
* the given platform (`/` for `Posix` and either `/` or `\` for `Windows`).
|
|
396
371
|
* Paths will be parsed as file paths rather than directory paths if there is
|
|
397
372
|
* ambiguity.
|
|
398
|
-
*
|
|
373
|
+
*
|
|
399
374
|
* @param pathStr: The string to parse as a path
|
|
400
375
|
* @param platform: The platform whose path separators should be used for parsing
|
|
401
376
|
* @returns The path wrapped with details encoded within the type
|
|
402
|
-
*
|
|
403
|
-
* @example
|
|
404
|
-
* @example
|
|
405
|
-
*
|
|
377
|
+
*
|
|
378
|
+
* @example fromString("file.txt") // a relative Path referencing the file ./file.txt
|
|
379
|
+
* @example fromString(".") // a relative Path referencing the current directory
|
|
380
|
+
* @example fromString("/bin/", Posix) // an absolute Path referencing the directory /bin/
|
|
381
|
+
* @example fromString("C:\\file.txt", Windows) // a relative Path referencing the file C:\file.txt
|
|
382
|
+
*
|
|
406
383
|
* @since v0.5.5
|
|
384
|
+
* @history v0.6.0: Merged with `fromPlatformString`; modified signature to accept platform
|
|
407
385
|
*/
|
|
408
|
-
|
|
386
|
+
provide let fromString = (pathStr, platform=Posix) => {
|
|
409
387
|
fromStringHelper(pathStr, platform)
|
|
410
388
|
}
|
|
411
389
|
|
|
@@ -436,66 +414,52 @@ let toStringHelper = (path, platform) => {
|
|
|
436
414
|
List.join(sep, segs)
|
|
437
415
|
}
|
|
438
416
|
|
|
439
|
-
/**
|
|
440
|
-
* Converts the given `Path` into a string, using the `/` path separator.
|
|
441
|
-
* A trailing slash is added to directory paths.
|
|
442
|
-
*
|
|
443
|
-
* @param path: The path to convert to a string
|
|
444
|
-
* @returns A string representing the given path
|
|
445
|
-
*
|
|
446
|
-
* @example toString(fromString("/file.txt")) == "/file.txt"
|
|
447
|
-
* @example toString(fromString("dir/")) == "./dir/"
|
|
448
|
-
*
|
|
449
|
-
* @since v0.5.5
|
|
450
|
-
*/
|
|
451
|
-
export let toString = path => {
|
|
452
|
-
toStringHelper(pathInfo(path), Posix)
|
|
453
|
-
}
|
|
454
|
-
|
|
455
417
|
/**
|
|
456
418
|
* Converts the given `Path` into a string, using the canonical path separator
|
|
457
419
|
* appropriate to the given platform (`/` for `Posix` and `\` for `Windows`).
|
|
458
420
|
* A trailing slash is added to directory paths.
|
|
459
|
-
*
|
|
421
|
+
*
|
|
460
422
|
* @param path: The path to convert to a string
|
|
461
423
|
* @param platform: The `Platform` to use to represent the path as a string
|
|
462
424
|
* @returns A string representing the given path
|
|
463
|
-
*
|
|
464
|
-
* @example
|
|
465
|
-
* @example
|
|
466
|
-
*
|
|
425
|
+
*
|
|
426
|
+
* @example toString(fromString("/file.txt")) == "/file.txt"
|
|
427
|
+
* @example toString(fromString("dir/"), Posix) == "./dir/"
|
|
428
|
+
* @example toString(fromString("C:/file.txt"), Windows) == "C:\\file.txt"
|
|
429
|
+
*
|
|
467
430
|
* @since v0.5.5
|
|
431
|
+
* @history v0.6.0: Merged with `toPlatformString`; modified signature to accept platform
|
|
468
432
|
*/
|
|
469
|
-
|
|
433
|
+
provide let toString = (path, platform=Posix) => {
|
|
470
434
|
toStringHelper(pathInfo(path), platform)
|
|
471
435
|
}
|
|
472
436
|
|
|
473
437
|
/**
|
|
474
438
|
* Determines whether the path is a directory path.
|
|
475
|
-
*
|
|
439
|
+
*
|
|
476
440
|
* @param path: The path to inspect
|
|
477
441
|
* @returns `true` if the path is a directory path or `false` otherwise
|
|
478
|
-
*
|
|
442
|
+
*
|
|
479
443
|
* @example isDirectory(fromString("file.txt")) == false
|
|
480
444
|
* @example isDirectory(fromString("/bin/")) == true
|
|
481
|
-
*
|
|
445
|
+
*
|
|
482
446
|
* @since v0.5.5
|
|
483
447
|
*/
|
|
484
|
-
|
|
448
|
+
provide let isDirectory = path => {
|
|
485
449
|
let (_, fileType, _) = pathInfo(path)
|
|
486
450
|
fileType == Dir
|
|
487
451
|
}
|
|
488
452
|
|
|
489
453
|
/**
|
|
490
454
|
* Determines whether the path is an absolute path.
|
|
491
|
-
*
|
|
455
|
+
*
|
|
492
456
|
* @param path: The path to inspect
|
|
493
457
|
* @returns `true` if the path is absolute or `false` otherwise
|
|
494
|
-
*
|
|
458
|
+
*
|
|
495
459
|
* @example isAbsolute(fromString("/Users/me")) == true
|
|
496
460
|
* @example isAbsolute(fromString("./file.txt")) == false
|
|
497
461
|
*/
|
|
498
|
-
|
|
462
|
+
provide let isAbsolute = path => {
|
|
499
463
|
let (base, _, _) = pathInfo(path)
|
|
500
464
|
match (base) {
|
|
501
465
|
Abs(_) => true,
|
|
@@ -506,32 +470,33 @@ export let isAbsolute = path => {
|
|
|
506
470
|
// should only be used on relative path appended to directory path
|
|
507
471
|
let rec appendHelper = (path: PathInfo, toAppend: PathInfo) =>
|
|
508
472
|
match (toAppend) {
|
|
509
|
-
(Rel(up2), ft, s2) =>
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
(
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
473
|
+
(Rel(up2), ft, s2) => match (path) {
|
|
474
|
+
(Rel(up1), _, []) => (Rel(up1 + up2), ft, s2),
|
|
475
|
+
(Abs(_) as d, _, []) => (d, ft, s2),
|
|
476
|
+
(d, pft, [_, ...rest] as s1) => {
|
|
477
|
+
if (up2 > 0)
|
|
478
|
+
appendHelper((d, pft, rest), (Rel(up2 - 1), ft, s2))
|
|
479
|
+
else
|
|
480
|
+
(d, ft, List.append(s2, s1))
|
|
517
481
|
},
|
|
482
|
+
},
|
|
518
483
|
(Abs(_), _, _) => fail "Impossible: relative path encoded as absolute path",
|
|
519
484
|
}: PathInfo
|
|
520
485
|
|
|
521
486
|
/**
|
|
522
487
|
* Creates a new path by appending a relative path segment to a directory path.
|
|
523
|
-
*
|
|
488
|
+
*
|
|
524
489
|
* @param path: The base path
|
|
525
490
|
* @param toAppend: The relative path to append
|
|
526
491
|
* @returns `Ok(path)` combining the base and appended paths or `Err(err)` if the paths are incompatible
|
|
527
|
-
*
|
|
492
|
+
*
|
|
528
493
|
* @example append(fromString("./dir/"), fromString("file.txt")) == Ok(fromString("./dir/file.txt"))
|
|
529
494
|
* @example append(fromString("a.txt"), fromString("b.sh")) == Err(AppendToFile) // cannot append to file path
|
|
530
495
|
* @example append(fromString("./dir/"), fromString("/dir2")) == Err(AppendAbsolute) // cannot append an absolute path
|
|
531
|
-
*
|
|
496
|
+
*
|
|
532
497
|
* @since v0.5.5
|
|
533
498
|
*/
|
|
534
|
-
|
|
499
|
+
provide let append = (path: Path, toAppend: Path) => {
|
|
535
500
|
match ((pathInfo(path), pathInfo(toAppend))) {
|
|
536
501
|
((_, File, _), _) => Err(AppendToFile),
|
|
537
502
|
(_, (Abs(_), _, _)) => Err(AppendAbsolute),
|
|
@@ -561,8 +526,10 @@ let relativeToHelper = (source: PathInfo, dest: PathInfo) => {
|
|
|
561
526
|
let result = match ((source, dest)) {
|
|
562
527
|
((_, File, [name, ..._]), _) when source == dest => Ok((1, [name])),
|
|
563
528
|
((Abs(r1), _, s1), (Abs(r2), _, s2)) =>
|
|
564
|
-
if (r1 != r2)
|
|
565
|
-
|
|
529
|
+
if (r1 != r2)
|
|
530
|
+
Err(Incompatible(DifferentRoots))
|
|
531
|
+
else
|
|
532
|
+
relativizeDepth((0, List.reverse(s1)), (0, List.reverse(s2))),
|
|
566
533
|
((Rel(up1), _, s1), (Rel(up2), _, s2)) =>
|
|
567
534
|
relativizeDepth((up1, List.reverse(s1)), (up2, List.reverse(s2))),
|
|
568
535
|
_ => fail "Impossible: paths should have both been absolute or relative",
|
|
@@ -578,45 +545,44 @@ let relativeToHelper = (source: PathInfo, dest: PathInfo) => {
|
|
|
578
545
|
/**
|
|
579
546
|
* Attempts to construct a new relative path which will lead to the destination
|
|
580
547
|
* path from the source path.
|
|
581
|
-
*
|
|
548
|
+
*
|
|
582
549
|
* If the source and destination are incompatible in their bases, the result
|
|
583
550
|
* will be `Err(IncompatibilityError)`.
|
|
584
551
|
*
|
|
585
552
|
* If the route to the destination cannot be concretely determined from the
|
|
586
553
|
* source, the result will be `Err(ImpossibleRelativization)`.
|
|
587
|
-
*
|
|
554
|
+
*
|
|
588
555
|
* @param source: The source path
|
|
589
556
|
* @param dest: The destination path to resolve
|
|
590
557
|
* @returns `Ok(path)` containing the relative path if successfully resolved or `Err(err)` otherwise
|
|
591
|
-
*
|
|
558
|
+
*
|
|
592
559
|
* @example relativeTo(fromString("/usr"), fromString("/usr/bin")) == Ok(fromString("./bin"))
|
|
593
560
|
* @example relativeTo(fromString("/home/me"), fromString("/home/me")) == Ok(fromString("."))
|
|
594
561
|
* @example relativeTo(fromString("/file.txt"), fromString("/etc/")) == Ok(fromString("../etc/"))
|
|
595
562
|
* @example relativeTo(fromString(".."), fromString("../../thing")) Ok(fromString("../thing"))
|
|
596
563
|
* @example relativeTo(fromString("/usr/bin"), fromString("C:/Users")) == Err(Incompatible(DifferentRoots))
|
|
597
564
|
* @example relativeTo(fromString("../here"), fromString("./there")) == Err(ImpossibleRelativization)
|
|
598
|
-
*
|
|
565
|
+
*
|
|
599
566
|
* @since v0.5.5
|
|
600
567
|
*/
|
|
601
|
-
|
|
568
|
+
provide let relativeTo = (source, dest) => {
|
|
602
569
|
let pathInfo1 = pathInfo(source)
|
|
603
570
|
let (base1, _, _) = pathInfo1
|
|
604
571
|
let pathInfo2 = pathInfo(dest)
|
|
605
572
|
let (base2, _, _) = pathInfo2
|
|
606
573
|
match ((base1, base2)) {
|
|
607
|
-
(Abs(_), Rel(_)) | (
|
|
574
|
+
(Abs(_), Rel(_)) | (Rel(_), Abs(_)) => Err(Incompatible(DifferentBases)),
|
|
608
575
|
_ => Result.map(toPath, relativeToHelper(pathInfo1, pathInfo2)),
|
|
609
576
|
}
|
|
610
577
|
}
|
|
611
578
|
|
|
612
|
-
let rec segsAncestry = (baseSegs, pathSegs) =>
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
}
|
|
579
|
+
let rec segsAncestry = (baseSegs, pathSegs) => match ((baseSegs, pathSegs)) {
|
|
580
|
+
([], []) => Self,
|
|
581
|
+
([], _) => Descendant,
|
|
582
|
+
(_, []) => Ancestor,
|
|
583
|
+
([first1, ..._], [first2, ..._]) when first1 != first2 => NoLineage,
|
|
584
|
+
([_, ...rest1], [_, ...rest2]) => segsAncestry(rest1, rest2),
|
|
585
|
+
}
|
|
620
586
|
|
|
621
587
|
// should be used on paths with same absolute/relativeness
|
|
622
588
|
let ancestryHelper = (base: PathInfo, path: PathInfo) => {
|
|
@@ -630,22 +596,22 @@ let ancestryHelper = (base: PathInfo, path: PathInfo) => {
|
|
|
630
596
|
|
|
631
597
|
/**
|
|
632
598
|
* Determines the relative ancestry betwen two paths.
|
|
633
|
-
*
|
|
599
|
+
*
|
|
634
600
|
* @param base: The first path to consider
|
|
635
601
|
* @param path: The second path to consider
|
|
636
602
|
* @returns `Ok(ancestryStatus)` with the relative ancestry between the paths if they are compatible or `Err(err)` if they are incompatible
|
|
637
|
-
*
|
|
603
|
+
*
|
|
638
604
|
* @example ancestry(fromString("/usr"), fromString("/usr/bin/bash")) == Ok(Ancestor)
|
|
639
605
|
* @example ancestry(fromString("/Users/me"), fromString("/Users")) == Ok(Descendant)
|
|
640
606
|
* @example ancestry(fromString("/usr"), fromString("/etc")) == Ok(Neither)
|
|
641
607
|
* @example ancestry(fromString("C:/dir1"), fromString("/dir2")) == Err(DifferentRoots)
|
|
642
|
-
*
|
|
608
|
+
*
|
|
643
609
|
* @since v0.5.5
|
|
644
610
|
*/
|
|
645
|
-
|
|
646
|
-
let pathInfo1 = pathInfo(
|
|
611
|
+
provide let ancestry = (base: Path, path: Path) => {
|
|
612
|
+
let pathInfo1 = pathInfo(base)
|
|
647
613
|
let (base1, _, _) = pathInfo1
|
|
648
|
-
let pathInfo2 = pathInfo(
|
|
614
|
+
let pathInfo2 = pathInfo(path)
|
|
649
615
|
let (base2, _, _) = pathInfo2
|
|
650
616
|
match ((base1, base2)) {
|
|
651
617
|
(Rel(_), Abs(_)) | (Abs(_), Rel(_)) => Err(DifferentBases),
|
|
@@ -653,81 +619,77 @@ export let ancestry = (path1: Path, path2: Path) => {
|
|
|
653
619
|
}
|
|
654
620
|
}
|
|
655
621
|
|
|
656
|
-
let parentHelper = (path: PathInfo) =>
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}: PathInfo
|
|
622
|
+
let parentHelper = (path: PathInfo) => match (path) {
|
|
623
|
+
(base, _, [_, ...rest]) => (base, Dir, rest),
|
|
624
|
+
(Rel(upDirs), _, []) => (Rel(upDirs + 1), Dir, []),
|
|
625
|
+
(Abs(_) as base, _, []) => (base, Dir, []),
|
|
626
|
+
}: PathInfo
|
|
662
627
|
|
|
663
628
|
/**
|
|
664
629
|
* Retrieves the path corresponding to the parent directory of the given path.
|
|
665
|
-
*
|
|
630
|
+
*
|
|
666
631
|
* @param path: The path to inspect
|
|
667
632
|
* @returns A path corresponding to the parent directory of the given path
|
|
668
|
-
*
|
|
633
|
+
*
|
|
669
634
|
* @example parent(fromString("./dir/inner")) == fromString("./dir/")
|
|
670
635
|
* @example parent(fromString("/")) == fromString("/")
|
|
671
|
-
*
|
|
636
|
+
*
|
|
672
637
|
* @since v0.5.5
|
|
673
638
|
*/
|
|
674
|
-
|
|
639
|
+
provide let parent = (path: Path) => {
|
|
675
640
|
toPath(parentHelper(pathInfo(path)))
|
|
676
641
|
}
|
|
677
642
|
|
|
678
|
-
let basenameHelper = (path: PathInfo) =>
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
}
|
|
643
|
+
let basenameHelper = (path: PathInfo) => match (path) {
|
|
644
|
+
(_, _, [name, ..._]) => Some(name),
|
|
645
|
+
_ => None,
|
|
646
|
+
}
|
|
683
647
|
|
|
684
648
|
/**
|
|
685
649
|
* Retrieves the basename (named final segment) of a path.
|
|
686
|
-
*
|
|
650
|
+
*
|
|
687
651
|
* @param path: The path to inspect
|
|
688
652
|
* @returns `Some(path)` containing the basename of the path or `None` if the path does not have one
|
|
689
|
-
*
|
|
653
|
+
*
|
|
690
654
|
* @example basename(fromString("./dir/file.txt")) == Some("file.txt")
|
|
691
655
|
* @example basename(fromString(".."))) == None
|
|
692
|
-
*
|
|
656
|
+
*
|
|
693
657
|
* @since v0.5.5
|
|
694
658
|
*/
|
|
695
|
-
|
|
659
|
+
provide let basename = (path: Path) => {
|
|
696
660
|
basenameHelper(pathInfo(path))
|
|
697
661
|
}
|
|
698
662
|
|
|
699
663
|
// should only be used on file paths
|
|
700
|
-
let stemExtHelper = (path: PathInfo) =>
|
|
701
|
-
|
|
702
|
-
(
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
_ => ("", ""),
|
|
715
|
-
}
|
|
664
|
+
let stemExtHelper = (path: PathInfo) => match (path) {
|
|
665
|
+
(_, _, [name, ..._]) => {
|
|
666
|
+
// trim first character (which is possibly a .) off as trick for
|
|
667
|
+
// splitting .a.b.c into .a, .b.c
|
|
668
|
+
match (String.indexOf(".", String.slice(1, name))) {
|
|
669
|
+
Some(dotI) => {
|
|
670
|
+
let dotI = dotI + 1
|
|
671
|
+
(String.slice(0, end=dotI, name), String.slice(dotI, name))
|
|
672
|
+
},
|
|
673
|
+
None => (name, ""),
|
|
674
|
+
}
|
|
675
|
+
},
|
|
676
|
+
_ => ("", ""),
|
|
677
|
+
}
|
|
716
678
|
|
|
717
679
|
/**
|
|
718
680
|
* Retrieves the basename of a file path without the extension.
|
|
719
|
-
*
|
|
681
|
+
*
|
|
720
682
|
* @param path: The path to inspect
|
|
721
683
|
* @returns `Ok(path)` containing the stem of the file path or `Err(err)` if the path is a directory path
|
|
722
|
-
*
|
|
684
|
+
*
|
|
723
685
|
* @example stem(fromString("file.txt")) == Ok("file")
|
|
724
686
|
* @example stem(fromString(".gitignore")) == Ok(".gitignore")
|
|
725
687
|
* @example stem(fromString(".a.tar.gz")) == Ok(".a")
|
|
726
688
|
* @example stem(fromString("/dir/")) == Err(IncompatiblePathType) // can only take stem of a file path
|
|
727
|
-
*
|
|
689
|
+
*
|
|
728
690
|
* @since v0.5.5
|
|
729
691
|
*/
|
|
730
|
-
|
|
692
|
+
provide let stem = (path: Path) => {
|
|
731
693
|
match (pathInfo(path)) {
|
|
732
694
|
(_, Dir, _) => Err(IncompatiblePathType),
|
|
733
695
|
pathInfo => {
|
|
@@ -739,18 +701,18 @@ export let stem = (path: Path) => {
|
|
|
739
701
|
|
|
740
702
|
/**
|
|
741
703
|
* Retrieves the extension on the basename of a file path.
|
|
742
|
-
*
|
|
704
|
+
*
|
|
743
705
|
* @param path: The path to inspect
|
|
744
706
|
* @returns `Ok(path)` containing the extension of the file path or `Err(err)` if the path is a directory path
|
|
745
|
-
*
|
|
707
|
+
*
|
|
746
708
|
* @example extension(fromString("file.txt")) == Ok(".txt")
|
|
747
709
|
* @example extension(fromString(".gitignore")) == Ok("")
|
|
748
710
|
* @example extension(fromString(".a.tar.gz")) == Ok(".tar.gz")
|
|
749
711
|
* @example extension(fromString("/dir/")) == Err(IncompatiblePathType) // can only take extension of a file path
|
|
750
|
-
*
|
|
712
|
+
*
|
|
751
713
|
* @since v0.5.5
|
|
752
714
|
*/
|
|
753
|
-
|
|
715
|
+
provide let extension = (path: Path) => {
|
|
754
716
|
match (pathInfo(path)) {
|
|
755
717
|
(_, Dir, _) => Err(IncompatiblePathType),
|
|
756
718
|
pathInfo => {
|
|
@@ -761,25 +723,24 @@ export let extension = (path: Path) => {
|
|
|
761
723
|
}
|
|
762
724
|
|
|
763
725
|
// should only be used on absolute paths
|
|
764
|
-
let rootHelper = (path: PathInfo) =>
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
}
|
|
726
|
+
let rootHelper = (path: PathInfo) => match (path) {
|
|
727
|
+
(Abs(root), _, _) => root,
|
|
728
|
+
_ => fail "Impossible: malformed absolute path data",
|
|
729
|
+
}
|
|
769
730
|
|
|
770
731
|
/**
|
|
771
732
|
* Retrieves the root of the absolute path.
|
|
772
|
-
*
|
|
733
|
+
*
|
|
773
734
|
* @param path: The path to inspect
|
|
774
735
|
* @returns `Ok(root)` containing the root of the path or `Err(err)` if the path is a relative path
|
|
775
|
-
*
|
|
736
|
+
*
|
|
776
737
|
* @example root(fromString("C:/Users/me/")) == Ok(Drive('C'))
|
|
777
738
|
* @example root(fromString("/home/me/")) == Ok(Root)
|
|
778
739
|
* @example root(fromString("./file.txt")) == Err(IncompatiblePathType)
|
|
779
|
-
*
|
|
740
|
+
*
|
|
780
741
|
* @since v0.5.5
|
|
781
742
|
*/
|
|
782
|
-
|
|
743
|
+
provide let root = (path: Path) => {
|
|
783
744
|
match (pathInfo(path)) {
|
|
784
745
|
(Rel(_), _, _) => Err(IncompatiblePathType),
|
|
785
746
|
pathInfo => Ok(rootHelper(pathInfo)),
|