goscript 0.2.5 → 0.2.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.
- package/cmd/goscript/cmd-compile.go +7 -0
- package/cmd/goscript/cmd_compile_test.go +83 -0
- package/compiler/compile-request.go +3 -0
- package/compiler/compiler-cache.go +828 -0
- package/compiler/compiler-cache_test.go +705 -0
- package/compiler/config.go +2 -0
- package/compiler/index.test.ts +26 -1
- package/compiler/index.ts +5 -0
- package/compiler/lowered-program.go +31 -20
- package/compiler/lowering.go +349 -93
- package/compiler/lowering_bench_test.go +1 -0
- package/compiler/override-facts.go +309 -8
- package/compiler/override-parity-verifier.go +45 -1
- package/compiler/override-parity-verifier_test.go +100 -0
- package/compiler/override-registry_test.go +1 -0
- package/compiler/package-graph.go +40 -12
- package/compiler/package-graph_test.go +29 -0
- package/compiler/runtime-contract.go +8 -0
- package/compiler/service.go +98 -11
- package/compiler/skeleton_test.go +110 -14
- package/compiler/typescript-emitter.go +120 -23
- package/dist/compiler/index.d.ts +2 -0
- package/dist/compiler/index.js +3 -0
- package/dist/compiler/index.js.map +1 -1
- package/dist/gs/builtin/builtin.d.ts +24 -33
- package/dist/gs/builtin/builtin.js +54 -61
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/hostio.d.ts +1 -0
- package/dist/gs/builtin/hostio.js +1 -1
- package/dist/gs/builtin/hostio.js.map +1 -1
- package/dist/gs/builtin/index.d.ts +1 -0
- package/dist/gs/builtin/index.js +1 -0
- package/dist/gs/builtin/index.js.map +1 -1
- package/dist/gs/builtin/panic.d.ts +18 -0
- package/dist/gs/builtin/panic.js +98 -0
- package/dist/gs/builtin/panic.js.map +1 -0
- package/dist/gs/builtin/slice.d.ts +10 -0
- package/dist/gs/builtin/slice.js +110 -53
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.js +15 -3
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/builtin/varRef.d.ts +1 -1
- package/dist/gs/builtin/varRef.js +3 -2
- package/dist/gs/builtin/varRef.js.map +1 -1
- package/dist/gs/bytes/bytes.gs.js +51 -38
- package/dist/gs/bytes/bytes.gs.js.map +1 -1
- package/dist/gs/bytes/reader.gs.d.ts +1 -1
- package/dist/gs/bytes/reader.gs.js +6 -7
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/cmp/index.d.ts +1 -1
- package/dist/gs/cmp/index.js +43 -10
- package/dist/gs/cmp/index.js.map +1 -1
- package/dist/gs/context/context.d.ts +2 -2
- package/dist/gs/context/context.js +1 -1
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/embed/index.js +1 -1
- package/dist/gs/embed/index.js.map +1 -1
- package/dist/gs/encoding/binary/index.js +201 -8
- package/dist/gs/encoding/binary/index.js.map +1 -1
- package/dist/gs/encoding/json/index.d.ts +5 -0
- package/dist/gs/encoding/json/index.js +388 -25
- package/dist/gs/encoding/json/index.js.map +1 -1
- package/dist/gs/errors/errors.js +17 -24
- package/dist/gs/errors/errors.js.map +1 -1
- package/dist/gs/fmt/fmt.js +129 -35
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/golang.org/x/crypto/cryptobyte/index.js +1 -1
- package/dist/gs/golang.org/x/crypto/cryptobyte/index.js.map +1 -1
- package/dist/gs/internal/bytealg/index.js +43 -8
- package/dist/gs/internal/bytealg/index.js.map +1 -1
- package/dist/gs/internal/byteorder/index.d.ts +2 -2
- package/dist/gs/internal/byteorder/index.js +2 -2
- package/dist/gs/internal/byteorder/index.js.map +1 -1
- package/dist/gs/io/fs/format.js +2 -2
- package/dist/gs/io/fs/format.js.map +1 -1
- package/dist/gs/io/fs/fs.d.ts +1 -1
- package/dist/gs/io/fs/fs.js +1 -1
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/io/io.d.ts +21 -21
- package/dist/gs/io/io.js +49 -50
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/math/bits/index.js +26 -8
- package/dist/gs/math/bits/index.js.map +1 -1
- package/dist/gs/math/copysign.gs.js +10 -17
- package/dist/gs/math/copysign.gs.js.map +1 -1
- package/dist/gs/math/pow.gs.js +5 -0
- package/dist/gs/math/pow.gs.js.map +1 -1
- package/dist/gs/math/signbit.gs.js +6 -2
- package/dist/gs/math/signbit.gs.js.map +1 -1
- package/dist/gs/mime/index.js +1 -0
- package/dist/gs/mime/index.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +6 -6
- package/dist/gs/net/http/index.js +507 -43
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/os/stat.gs.d.ts +2 -2
- package/dist/gs/os/types.gs.d.ts +1 -1
- package/dist/gs/os/types.gs.js +1 -1
- package/dist/gs/os/types.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.d.ts +1 -1
- package/dist/gs/os/types_js.gs.js +7 -7
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.d.ts +1 -1
- package/dist/gs/os/types_unix.gs.js +1 -1
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/dist/gs/os/zero_copy_posix.gs.d.ts +1 -1
- package/dist/gs/os/zero_copy_posix.gs.js +1 -1
- package/dist/gs/os/zero_copy_posix.gs.js.map +1 -1
- package/dist/gs/path/filepath/match.js +8 -4
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/filepath/path.js +216 -42
- package/dist/gs/path/filepath/path.js.map +1 -1
- package/dist/gs/path/match.js +6 -3
- package/dist/gs/path/match.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +5 -4
- package/dist/gs/reflect/type.js +29 -11
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/slices/slices.js +11 -11
- package/dist/gs/slices/slices.js.map +1 -1
- package/dist/gs/strconv/atof.gs.js +156 -43
- package/dist/gs/strconv/atof.gs.js.map +1 -1
- package/dist/gs/strconv/atoi.gs.d.ts +3 -2
- package/dist/gs/strconv/atoi.gs.js +86 -67
- package/dist/gs/strconv/atoi.gs.js.map +1 -1
- package/dist/gs/strconv/ftoa.gs.js +73 -3
- package/dist/gs/strconv/ftoa.gs.js.map +1 -1
- package/dist/gs/strconv/itoa.gs.d.ts +4 -4
- package/dist/gs/strconv/itoa.gs.js +5 -4
- package/dist/gs/strconv/itoa.gs.js.map +1 -1
- package/dist/gs/strconv/quote.gs.d.ts +1 -1
- package/dist/gs/strconv/quote.gs.js +311 -103
- package/dist/gs/strconv/quote.gs.js.map +1 -1
- package/dist/gs/strings/reader.d.ts +1 -1
- package/dist/gs/strings/reader.js +8 -8
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/strings.js +87 -61
- package/dist/gs/strings/strings.js.map +1 -1
- package/dist/gs/sync/atomic/doc_64.gs.d.ts +14 -14
- package/dist/gs/sync/atomic/doc_64.gs.js +10 -10
- package/dist/gs/sync/atomic/doc_64.gs.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.d.ts +22 -22
- package/dist/gs/sync/atomic/type.gs.js +4 -4
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/sync.js +50 -12
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/syscall/fs.d.ts +6 -6
- package/dist/gs/syscall/fs.js +1 -1
- package/dist/gs/syscall/fs.js.map +1 -1
- package/dist/gs/time/time.d.ts +18 -18
- package/dist/gs/time/time.js +58 -55
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/tables.d.ts +11 -0
- package/dist/gs/unicode/tables.js +635 -0
- package/dist/gs/unicode/tables.js.map +1 -0
- package/dist/gs/unicode/unicode.d.ts +58 -38
- package/dist/gs/unicode/unicode.js +362 -278
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/go.sum +13 -0
- package/gs/builtin/builtin.ts +83 -93
- package/gs/builtin/hostio.ts +1 -1
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/panic.test.ts +189 -0
- package/gs/builtin/panic.ts +107 -0
- package/gs/builtin/runtime-contract.test.ts +5 -5
- package/gs/builtin/slice.test.ts +23 -0
- package/gs/builtin/slice.ts +133 -95
- package/gs/builtin/type.ts +16 -3
- package/gs/builtin/varRef.ts +4 -2
- package/gs/builtin/wide-int.test.ts +41 -0
- package/gs/bytes/bytes.gs.ts +54 -41
- package/gs/bytes/bytes.test.ts +18 -1
- package/gs/bytes/reader.gs.ts +7 -8
- package/gs/cmp/index.test.ts +55 -0
- package/gs/cmp/index.ts +45 -9
- package/gs/context/context.ts +3 -3
- package/gs/embed/index.ts +2 -2
- package/gs/encoding/binary/index.test.ts +104 -0
- package/gs/encoding/binary/index.ts +259 -11
- package/gs/encoding/json/index.test.ts +107 -0
- package/gs/encoding/json/index.ts +400 -29
- package/gs/errors/errors.test.ts +44 -1
- package/gs/errors/errors.ts +15 -31
- package/gs/fmt/fmt.test.ts +70 -2
- package/gs/fmt/fmt.ts +128 -34
- package/gs/golang.org/x/crypto/cryptobyte/index.ts +1 -1
- package/gs/internal/bytealg/index.test.ts +26 -1
- package/gs/internal/bytealg/index.ts +44 -8
- package/gs/internal/byteorder/index.ts +6 -4
- package/gs/io/fs/format.ts +2 -2
- package/gs/io/fs/fs.ts +2 -2
- package/gs/io/fs/stat.test.ts +2 -2
- package/gs/io/fs/sub.test.ts +2 -2
- package/gs/io/fs/walk.test.ts +2 -2
- package/gs/io/io.test.ts +47 -5
- package/gs/io/io.ts +73 -73
- package/gs/io/limit.test.ts +103 -0
- package/gs/math/bits/index.test.ts +128 -0
- package/gs/math/bits/index.ts +26 -8
- package/gs/math/copysign.gs.test.ts +3 -1
- package/gs/math/copysign.gs.ts +10 -22
- package/gs/math/pow.gs.test.ts +4 -5
- package/gs/math/pow.gs.ts +5 -0
- package/gs/math/signbit.gs.test.ts +2 -1
- package/gs/math/signbit.gs.ts +6 -3
- package/gs/mime/index.ts +1 -0
- package/gs/net/http/index.test.ts +683 -2
- package/gs/net/http/index.ts +598 -57
- package/gs/net/http/meta.json +3 -0
- package/gs/os/stat.gs.ts +2 -2
- package/gs/os/types.gs.ts +2 -2
- package/gs/os/types_js.gs.ts +9 -9
- package/gs/os/types_unix.gs.ts +2 -2
- package/gs/os/zero_copy_posix.gs.ts +2 -2
- package/gs/path/filepath/match.test.ts +16 -0
- package/gs/path/filepath/match.ts +8 -4
- package/gs/path/filepath/path.test.ts +91 -9
- package/gs/path/filepath/path.ts +223 -49
- package/gs/path/match.test.ts +32 -0
- package/gs/path/match.ts +6 -3
- package/gs/reflect/deepequal.test.ts +1 -1
- package/gs/reflect/field.test.ts +1 -1
- package/gs/reflect/function-types.test.ts +6 -6
- package/gs/reflect/sliceat.test.ts +13 -13
- package/gs/reflect/structof.test.ts +4 -4
- package/gs/reflect/type.ts +34 -14
- package/gs/reflect/typefor.test.ts +5 -5
- package/gs/runtime/pprof/index.test.ts +20 -0
- package/gs/runtime/trace/index.test.ts +3 -0
- package/gs/slices/slices.test.ts +31 -0
- package/gs/slices/slices.ts +11 -11
- package/gs/strconv/append.test.ts +99 -0
- package/gs/strconv/atof.gs.ts +156 -42
- package/gs/strconv/atof.test.ts +45 -0
- package/gs/strconv/atoi.gs.ts +87 -69
- package/gs/strconv/atoi.test.ts +49 -0
- package/gs/strconv/ftoa.gs.ts +85 -10
- package/gs/strconv/ftoa.test.ts +43 -0
- package/gs/strconv/itoa.gs.ts +10 -9
- package/gs/strconv/quote.gs.ts +335 -108
- package/gs/strconv/quote.test.ts +111 -0
- package/gs/strings/reader.test.ts +10 -10
- package/gs/strings/reader.ts +9 -9
- package/gs/strings/strings.test.ts +18 -5
- package/gs/strings/strings.ts +81 -68
- package/gs/sync/atomic/doc_64.gs.ts +24 -24
- package/gs/sync/atomic/doc_64.test.ts +5 -5
- package/gs/sync/atomic/type.gs.ts +28 -28
- package/gs/sync/sync.test.ts +109 -1
- package/gs/sync/sync.ts +46 -12
- package/gs/syscall/fs.ts +8 -8
- package/gs/syscall/net.test.ts +1 -1
- package/gs/time/parse.test.ts +45 -0
- package/gs/time/time.test.ts +46 -23
- package/gs/time/time.ts +69 -66
- package/gs/unicode/gen.go +198 -0
- package/gs/unicode/tables.ts +646 -0
- package/gs/unicode/unicode.test.ts +69 -0
- package/gs/unicode/unicode.ts +396 -312
- package/package.json +2 -2
- package/dist/gs/github.com/aperturerobotics/util/conc/index.d.ts +0 -20
- package/dist/gs/github.com/aperturerobotics/util/conc/index.js +0 -134
- package/dist/gs/github.com/aperturerobotics/util/conc/index.js.map +0 -1
- package/gs/github.com/aperturerobotics/util/conc/index.test.ts +0 -30
- package/gs/github.com/aperturerobotics/util/conc/index.ts +0 -172
- package/gs/github.com/aperturerobotics/util/conc/meta.json +0 -9
package/gs/net/http/meta.json
CHANGED
package/gs/os/stat.gs.ts
CHANGED
|
@@ -9,7 +9,7 @@ export function Stat(name: string): [null | {
|
|
|
9
9
|
ModTime(): any
|
|
10
10
|
Mode(): any
|
|
11
11
|
Name(): string
|
|
12
|
-
Size():
|
|
12
|
+
Size(): bigint
|
|
13
13
|
Sys(): null | any
|
|
14
14
|
}, $.GoError] {
|
|
15
15
|
// testlog.Stat(name) // Testlog not available in JavaScript
|
|
@@ -29,7 +29,7 @@ export function Lstat(name: string): [null | {
|
|
|
29
29
|
ModTime(): Time
|
|
30
30
|
Mode(): FileMode
|
|
31
31
|
Name(): string
|
|
32
|
-
Size():
|
|
32
|
+
Size(): bigint
|
|
33
33
|
Sys(): null | any
|
|
34
34
|
}, $.GoError] {
|
|
35
35
|
// testlog.Stat(name) // Testlog not available in JavaScript
|
package/gs/os/types.gs.ts
CHANGED
|
@@ -73,8 +73,8 @@ export class File {
|
|
|
73
73
|
return [0, ErrUnimplemented]
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
public Seek(offset:
|
|
77
|
-
return [
|
|
76
|
+
public Seek(offset: bigint, whence: number): [bigint, $.GoError] {
|
|
77
|
+
return [0n, ErrUnimplemented]
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
public WriteString(s: string): [number, $.GoError] {
|
package/gs/os/types_js.gs.ts
CHANGED
|
@@ -163,7 +163,7 @@ class hostFileInfo {
|
|
|
163
163
|
|
|
164
164
|
constructor(init?: Partial<{modTime?: time.Time, mode?: fs.FileMode, name?: string, size?: number, sys?: HostStatLike | null}>) {
|
|
165
165
|
this.name = init?.name ?? ""
|
|
166
|
-
this.modTime = init?.modTime ?? time.Unix(
|
|
166
|
+
this.modTime = init?.modTime ?? time.Unix(0n, 0n)
|
|
167
167
|
this.mode = init?.mode ?? 0
|
|
168
168
|
this.size = init?.size ?? 0
|
|
169
169
|
this.sys = init?.sys ?? null
|
|
@@ -185,8 +185,8 @@ class hostFileInfo {
|
|
|
185
185
|
return this.name
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
public Size():
|
|
189
|
-
return this.size
|
|
188
|
+
public Size(): bigint {
|
|
189
|
+
return BigInt(this.size)
|
|
190
190
|
}
|
|
191
191
|
|
|
192
192
|
public Sys(): HostStatLike | null {
|
|
@@ -212,10 +212,10 @@ export function createFileInfo(name: string, stat: HostStatLike): fs.FileInfo {
|
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
return new hostFileInfo({
|
|
215
|
-
modTime: time.UnixMilli(mtimeMs),
|
|
215
|
+
modTime: time.UnixMilli(BigInt(Math.trunc(mtimeMs))),
|
|
216
216
|
mode,
|
|
217
217
|
name: normalizedName,
|
|
218
|
-
size: stat.size ?? 0,
|
|
218
|
+
size: Math.trunc(stat.size ?? 0),
|
|
219
219
|
sys: stat,
|
|
220
220
|
})
|
|
221
221
|
}
|
|
@@ -589,15 +589,15 @@ export class File {
|
|
|
589
589
|
}
|
|
590
590
|
}
|
|
591
591
|
|
|
592
|
-
public Seek(offset:
|
|
592
|
+
public Seek(offset: bigint, whence: number): [bigint, $.GoError] {
|
|
593
593
|
const handle = this.file?.handle
|
|
594
594
|
if (!handle || typeof handle.seekSync !== "function") {
|
|
595
|
-
return [
|
|
595
|
+
return [0n, ErrUnimplemented]
|
|
596
596
|
}
|
|
597
597
|
try {
|
|
598
|
-
return [handle.seekSync(offset, whence), null]
|
|
598
|
+
return [BigInt(handle.seekSync(Number(offset), whence)), null]
|
|
599
599
|
} catch (err) {
|
|
600
|
-
return [
|
|
600
|
+
return [0n, newHostError(err)]
|
|
601
601
|
}
|
|
602
602
|
}
|
|
603
603
|
|
package/gs/os/types_unix.gs.ts
CHANGED
|
@@ -20,9 +20,9 @@ export function wrapSyscallError(name: string, err: $.GoError): $.GoError {
|
|
|
20
20
|
// tryLimitedReader tries to assert the io.Reader to io.LimitedReader, it returns the io.LimitedReader,
|
|
21
21
|
// the underlying io.Reader and the remaining amount of bytes if the assertion succeeds,
|
|
22
22
|
// otherwise it just returns the original io.Reader and the theoretical unlimited remaining amount of bytes.
|
|
23
|
-
export function tryLimitedReader(r: io.Reader): [io.LimitedReader | null, io.Reader,
|
|
23
|
+
export function tryLimitedReader(r: io.Reader): [io.LimitedReader | null, io.Reader, bigint] {
|
|
24
24
|
// by default, copy until EOF
|
|
25
|
-
let remain:
|
|
25
|
+
let remain: bigint = (1n << 63n) - 1n
|
|
26
26
|
|
|
27
27
|
let { value: lr, ok: ok } = $.typeAssert<io.LimitedReader | null>(r, {kind: $.TypeKind.Pointer, elemType: 'io.LimitedReader'})
|
|
28
28
|
if (!ok) {
|
|
@@ -173,6 +173,22 @@ describe('path/filepath - Pattern matching functions', () => {
|
|
|
173
173
|
expect(err1).toBeNull()
|
|
174
174
|
expect(match1).toBe(false)
|
|
175
175
|
})
|
|
176
|
+
|
|
177
|
+
it('should not let a star cross a path separator', () => {
|
|
178
|
+
// Go: '*' matches a non-Separator run only.
|
|
179
|
+
const [m1, e1] = Match('*c', 'a/c')
|
|
180
|
+
expect(e1).toBeNull()
|
|
181
|
+
expect(m1).toBe(false)
|
|
182
|
+
|
|
183
|
+
const [m2, e2] = Match('*', 'a/b')
|
|
184
|
+
expect(e2).toBeNull()
|
|
185
|
+
expect(m2).toBe(false)
|
|
186
|
+
|
|
187
|
+
// A star can still consume the run right up to a separator.
|
|
188
|
+
const [m3, e3] = Match('*/c', 'a/c')
|
|
189
|
+
expect(e3).toBeNull()
|
|
190
|
+
expect(m3).toBe(true)
|
|
191
|
+
})
|
|
176
192
|
})
|
|
177
193
|
|
|
178
194
|
describe('Error cases', () => {
|
|
@@ -102,20 +102,24 @@ function matchPattern(pattern: string, name: string): boolean {
|
|
|
102
102
|
|
|
103
103
|
switch (p) {
|
|
104
104
|
case '*':
|
|
105
|
-
// Handle star - match any sequence of characters
|
|
105
|
+
// Handle star - match any sequence of non-Separator characters.
|
|
106
106
|
patternIndex++
|
|
107
107
|
if (patternIndex >= pattern.length) {
|
|
108
|
-
//
|
|
109
|
-
return
|
|
108
|
+
// Trailing * matches the rest of name unless it crosses a separator.
|
|
109
|
+
return name.substring(nameIndex).indexOf('/') < 0
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
// Try to match the rest of the pattern with remaining name
|
|
112
|
+
// Try to match the rest of the pattern with remaining name, but the
|
|
113
|
+
// star cannot consume a separator (Go matches non-Separator runs only).
|
|
113
114
|
for (let i = nameIndex; i <= name.length; i++) {
|
|
114
115
|
if (
|
|
115
116
|
matchPattern(pattern.substring(patternIndex), name.substring(i))
|
|
116
117
|
) {
|
|
117
118
|
return true
|
|
118
119
|
}
|
|
120
|
+
if (i < name.length && name[i] === '/') {
|
|
121
|
+
break
|
|
122
|
+
}
|
|
119
123
|
}
|
|
120
124
|
return false
|
|
121
125
|
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
mkdirSync,
|
|
4
|
+
mkdtempSync,
|
|
5
|
+
realpathSync,
|
|
6
|
+
rmSync,
|
|
7
|
+
symlinkSync,
|
|
8
|
+
writeFileSync,
|
|
9
|
+
} from 'node:fs'
|
|
3
10
|
import { tmpdir } from 'node:os'
|
|
4
11
|
import { join } from 'node:path'
|
|
5
12
|
import {
|
|
@@ -18,6 +25,7 @@ import {
|
|
|
18
25
|
HasPrefix,
|
|
19
26
|
Abs,
|
|
20
27
|
Rel,
|
|
28
|
+
Localize,
|
|
21
29
|
EvalSymlinks,
|
|
22
30
|
Walk,
|
|
23
31
|
WalkDir,
|
|
@@ -177,9 +185,11 @@ describe('path/filepath - Path manipulation functions', () => {
|
|
|
177
185
|
expect(err1).toBeNull()
|
|
178
186
|
expect(result1).toBe('/absolute/path')
|
|
179
187
|
|
|
188
|
+
// A relative path is joined against the real working directory, matching
|
|
189
|
+
// Go's filepath.Abs (os.Getwd), not a fabricated root.
|
|
180
190
|
const [result2, err2] = Abs('relative/path')
|
|
181
191
|
expect(err2).toBeNull()
|
|
182
|
-
expect(result2).toBe('
|
|
192
|
+
expect(result2).toBe(Join(process.cwd(), 'relative/path'))
|
|
183
193
|
})
|
|
184
194
|
})
|
|
185
195
|
|
|
@@ -193,17 +203,66 @@ describe('path/filepath - Path manipulation functions', () => {
|
|
|
193
203
|
expect(err2).toBeNull()
|
|
194
204
|
expect(result2).toBe('bin')
|
|
195
205
|
|
|
206
|
+
// Go emits ".." components to climb out of base before descending into
|
|
207
|
+
// the divergent target tail.
|
|
196
208
|
const [result3, err3] = Rel('/usr/local', '/other/path')
|
|
197
209
|
expect(err3).toBeNull()
|
|
198
|
-
expect(result3).toBe('
|
|
210
|
+
expect(result3).toBe('../../other/path')
|
|
211
|
+
|
|
212
|
+
const [result4, err4] = Rel('/a/b', '/a/c')
|
|
213
|
+
expect(err4).toBeNull()
|
|
214
|
+
expect(result4).toBe('../c')
|
|
215
|
+
|
|
216
|
+
const [result5, err5] = Rel('a/b', 'a/c')
|
|
217
|
+
expect(err5).toBeNull()
|
|
218
|
+
expect(result5).toBe('../c')
|
|
219
|
+
|
|
220
|
+
// A relative base cannot be made relative to an absolute target.
|
|
221
|
+
const [, err6] = Rel('a/b', '/a/c')
|
|
222
|
+
expect(err6).not.toBeNull()
|
|
223
|
+
})
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
describe('Localize', () => {
|
|
227
|
+
it('should accept io/fs.ValidPath inputs and reject the rest', () => {
|
|
228
|
+
const [ok, okErr] = Localize('a/b')
|
|
229
|
+
expect(okErr).toBeNull()
|
|
230
|
+
expect(ok).toBe('a/b')
|
|
231
|
+
|
|
232
|
+
const [dot, dotErr] = Localize('.')
|
|
233
|
+
expect(dotErr).toBeNull()
|
|
234
|
+
expect(dot).toBe('.')
|
|
235
|
+
|
|
236
|
+
for (const bad of ['', '/a', '../a', 'a/../b', 'a/']) {
|
|
237
|
+
const [, err] = Localize(bad)
|
|
238
|
+
expect(err).not.toBeNull()
|
|
239
|
+
}
|
|
199
240
|
})
|
|
200
241
|
})
|
|
201
242
|
|
|
202
243
|
describe('EvalSymlinks', () => {
|
|
203
|
-
it('should
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
244
|
+
it('should resolve symlinks against the host filesystem', () => {
|
|
245
|
+
// realpathSync canonicalizes the temp root (macOS /var -> /private/var) so
|
|
246
|
+
// the expected resolved path uses the same canonical base.
|
|
247
|
+
const root = realpathSync(
|
|
248
|
+
mkdtempSync(join(tmpdir(), 'goscript-filepath-eval-')),
|
|
249
|
+
)
|
|
250
|
+
try {
|
|
251
|
+
mkdirSync(join(root, 'real'))
|
|
252
|
+
writeFileSync(join(root, 'real', 'file.txt'), 'ok')
|
|
253
|
+
symlinkSync(join(root, 'real'), join(root, 'link'))
|
|
254
|
+
|
|
255
|
+
const [result, err] = EvalSymlinks(join(root, 'link', 'file.txt'))
|
|
256
|
+
expect(err).toBeNull()
|
|
257
|
+
expect(result).toBe(join(root, 'real', 'file.txt'))
|
|
258
|
+
} finally {
|
|
259
|
+
rmSync(root, { force: true, recursive: true })
|
|
260
|
+
}
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
it('should error when a path component does not exist', () => {
|
|
264
|
+
const [, err] = EvalSymlinks('/goscript-nonexistent-xyz/file')
|
|
265
|
+
expect(err).not.toBeNull()
|
|
207
266
|
})
|
|
208
267
|
})
|
|
209
268
|
|
|
@@ -226,6 +285,28 @@ describe('path/filepath - Path manipulation functions', () => {
|
|
|
226
285
|
rmSync(root, { force: true, recursive: true })
|
|
227
286
|
}
|
|
228
287
|
})
|
|
288
|
+
|
|
289
|
+
it('should not descend into a symlinked directory (Lstat walk)', async () => {
|
|
290
|
+
const root = mkdtempSync(join(tmpdir(), 'goscript-filepath-walklink-'))
|
|
291
|
+
try {
|
|
292
|
+
mkdirSync(join(root, 'real'))
|
|
293
|
+
writeFileSync(join(root, 'real', 'inside.txt'), 'ok')
|
|
294
|
+
symlinkSync(join(root, 'real'), join(root, 'link'))
|
|
295
|
+
|
|
296
|
+
const visited: string[] = []
|
|
297
|
+
const err = await Walk(root, (path) => {
|
|
298
|
+
visited.push(path.slice(root.length).replace(/^\/?/, '') || '.')
|
|
299
|
+
return null
|
|
300
|
+
})
|
|
301
|
+
|
|
302
|
+
expect(err).toBeNull()
|
|
303
|
+
// The symlink is visited but not traversed, so link/inside.txt never
|
|
304
|
+
// appears.
|
|
305
|
+
expect(visited).toEqual(['.', 'link', 'real', 'real/inside.txt'])
|
|
306
|
+
} finally {
|
|
307
|
+
rmSync(root, { force: true, recursive: true })
|
|
308
|
+
}
|
|
309
|
+
})
|
|
229
310
|
})
|
|
230
311
|
|
|
231
312
|
describe('WalkDir', () => {
|
|
@@ -296,9 +377,10 @@ describe('Complex path operations', () => {
|
|
|
296
377
|
expect(Clean('a/b/../../c')).toBe('c')
|
|
297
378
|
expect(Clean('../../a/b')).toBe('../../a/b')
|
|
298
379
|
|
|
299
|
-
// Test Join with various inputs
|
|
380
|
+
// Test Join with various inputs. A later absolute element does not discard
|
|
381
|
+
// earlier elements; Go joins the suffix and Clean collapses double slashes.
|
|
300
382
|
expect(Join('/a', '../b', 'c')).toBe('/b/c')
|
|
301
|
-
expect(Join('a', '/b', 'c')).toBe('/b/c')
|
|
383
|
+
expect(Join('a', '/b', 'c')).toBe('a/b/c')
|
|
302
384
|
|
|
303
385
|
// Test Split edge cases
|
|
304
386
|
expect(Split('/a/')).toEqual(['/a/', ''])
|
package/gs/path/filepath/path.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
// Package filepath implements utility routines for manipulating filename paths
|
|
2
2
|
// in a way compatible with the target operating system-defined file paths.
|
|
3
3
|
import * as $ from '@goscript/builtin/index.js'
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
getCurrentWorkingDirectory,
|
|
6
|
+
getHostRuntime,
|
|
7
|
+
} from '@goscript/builtin/hostio.js'
|
|
5
8
|
import type { DirEntry } from '@goscript/io/fs/fs.js'
|
|
9
|
+
import { ValidPath } from '@goscript/io/fs/fs.js'
|
|
6
10
|
import { FileInfoToDirEntry } from '@goscript/io/fs/readdir.js'
|
|
7
11
|
|
|
8
12
|
type JoinElement = string | $.Slice<string>
|
|
@@ -142,32 +146,15 @@ export function Clean(path: string): string {
|
|
|
142
146
|
// an empty string.
|
|
143
147
|
export function Join(...elem: JoinElement[]): string {
|
|
144
148
|
const partsArg = normalizeJoinElements(elem)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
for (const e of partsArg) {
|
|
153
|
-
if (e === '') {
|
|
154
|
-
continue
|
|
149
|
+
// Join all elements from the first non-empty one onward, then Clean. A later
|
|
150
|
+
// absolute element does not discard earlier elements (Go joins the suffix and
|
|
151
|
+
// lets Clean collapse the resulting double separators).
|
|
152
|
+
for (let i = 0; i < partsArg.length; i++) {
|
|
153
|
+
if (partsArg[i] !== '') {
|
|
154
|
+
return Clean(partsArg.slice(i).join('/'))
|
|
155
155
|
}
|
|
156
|
-
|
|
157
|
-
// If this element is absolute, start over from here
|
|
158
|
-
if (IsAbs(e)) {
|
|
159
|
-
parts.length = 0 // Clear previous parts
|
|
160
|
-
parts.push(e)
|
|
161
|
-
} else {
|
|
162
|
-
parts.push(e)
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (parts.length === 0) {
|
|
167
|
-
return ''
|
|
168
156
|
}
|
|
169
|
-
|
|
170
|
-
return Clean(parts.join('/'))
|
|
157
|
+
return ''
|
|
171
158
|
}
|
|
172
159
|
|
|
173
160
|
// Split splits path immediately following the final Separator,
|
|
@@ -278,38 +265,183 @@ export function HasPrefix(p: string, prefix: string): boolean {
|
|
|
278
265
|
return false
|
|
279
266
|
}
|
|
280
267
|
|
|
281
|
-
//
|
|
282
|
-
//
|
|
283
|
-
|
|
268
|
+
// Abs returns an absolute representation of path. If the path is not absolute
|
|
269
|
+
// it is joined with the current working directory to turn it into an absolute
|
|
270
|
+
// path, then Cleaned. This mirrors Go's filepath.Abs, which calls os.Getwd for
|
|
271
|
+
// relative inputs rather than fabricating a root.
|
|
284
272
|
export function Abs(path: string): [string, $.GoError] {
|
|
285
273
|
if (IsAbs(path)) {
|
|
286
274
|
return [Clean(path), null]
|
|
287
275
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
276
|
+
const wd = getCurrentWorkingDirectory()
|
|
277
|
+
if (wd === null) {
|
|
278
|
+
return ['', $.newError('filepath: cannot determine working directory')]
|
|
279
|
+
}
|
|
280
|
+
return [Join(wd, path), null]
|
|
291
281
|
}
|
|
292
282
|
|
|
293
283
|
export function Rel(basepath: string, targpath: string): [string, $.GoError] {
|
|
294
|
-
// Simplified implementation - in reality this is much more complex
|
|
295
284
|
const base = Clean(basepath)
|
|
296
285
|
const targ = Clean(targpath)
|
|
297
|
-
|
|
298
|
-
if (base === targ) {
|
|
286
|
+
if (targ === base) {
|
|
299
287
|
return ['.', null]
|
|
300
288
|
}
|
|
301
289
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
290
|
+
const b = base === '.' ? '' : base
|
|
291
|
+
const t = targ === '.' ? '' : targ
|
|
292
|
+
const baseSlashed = b.length > 0 && b[0] === '/'
|
|
293
|
+
const targSlashed = t.length > 0 && t[0] === '/'
|
|
294
|
+
if (baseSlashed !== targSlashed) {
|
|
295
|
+
return [
|
|
296
|
+
'',
|
|
297
|
+
$.newError(`Rel: can't make ${targpath} relative to ${basepath}`),
|
|
298
|
+
]
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Walk both paths element by element until they first differ.
|
|
302
|
+
const bl = b.length
|
|
303
|
+
const tl = t.length
|
|
304
|
+
let b0 = 0
|
|
305
|
+
let bi = 0
|
|
306
|
+
let t0 = 0
|
|
307
|
+
let ti = 0
|
|
308
|
+
for (;;) {
|
|
309
|
+
while (bi < bl && b[bi] !== '/') {
|
|
310
|
+
bi++
|
|
311
|
+
}
|
|
312
|
+
while (ti < tl && t[ti] !== '/') {
|
|
313
|
+
ti++
|
|
314
|
+
}
|
|
315
|
+
if (t.slice(t0, ti) !== b.slice(b0, bi)) {
|
|
316
|
+
break
|
|
317
|
+
}
|
|
318
|
+
if (bi < bl) {
|
|
319
|
+
bi++
|
|
320
|
+
}
|
|
321
|
+
if (ti < tl) {
|
|
322
|
+
ti++
|
|
323
|
+
}
|
|
324
|
+
b0 = bi
|
|
325
|
+
t0 = ti
|
|
326
|
+
}
|
|
327
|
+
if (b.slice(b0, bi) === '..') {
|
|
328
|
+
return [
|
|
329
|
+
'',
|
|
330
|
+
$.newError(`Rel: can't make ${targpath} relative to ${basepath}`),
|
|
331
|
+
]
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (b0 !== bl) {
|
|
335
|
+
// Base elements remain; emit one ".." per leftover base element, then the
|
|
336
|
+
// remaining target tail.
|
|
337
|
+
let seps = 0
|
|
338
|
+
for (let i = b0; i < bl; i++) {
|
|
339
|
+
if (b[i] === '/') {
|
|
340
|
+
seps++
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
let out = '..'
|
|
344
|
+
for (let i = 0; i < seps; i++) {
|
|
345
|
+
out += '/..'
|
|
346
|
+
}
|
|
347
|
+
if (t0 !== tl) {
|
|
348
|
+
out += '/' + t.slice(t0)
|
|
349
|
+
}
|
|
350
|
+
return [out, null]
|
|
305
351
|
}
|
|
306
|
-
|
|
307
|
-
return [targ, null]
|
|
352
|
+
return [t.slice(t0), null]
|
|
308
353
|
}
|
|
309
354
|
|
|
355
|
+
// EvalSymlinks returns the path name after the evaluation of any symbolic
|
|
356
|
+
// links. This is a lexical port of Go's path/filepath walkSymlinks: it resolves
|
|
357
|
+
// each component with Lstat and follows symlinks with Readlink, preserving the
|
|
358
|
+
// relative-vs-absolute shape of the input. It deliberately does not use a host
|
|
359
|
+
// realpath, which would always force an absolute result and would not surface
|
|
360
|
+
// Go's per-component ENOTDIR and link-cycle errors. volLen is 0 for a relative
|
|
361
|
+
// input and 1 for an absolute root.
|
|
310
362
|
export function EvalSymlinks(path: string): [string, $.GoError] {
|
|
311
|
-
|
|
312
|
-
|
|
363
|
+
let p = path
|
|
364
|
+
const volLen = p.length > 0 && p[0] === '/' ? 1 : 0
|
|
365
|
+
const vol = p.slice(0, volLen)
|
|
366
|
+
let dest = vol
|
|
367
|
+
let linksWalked = 0
|
|
368
|
+
for (let start = volLen; start < p.length; ) {
|
|
369
|
+
while (start < p.length && p[start] === '/') {
|
|
370
|
+
start++
|
|
371
|
+
}
|
|
372
|
+
let end = start
|
|
373
|
+
while (end < p.length && p[end] !== '/') {
|
|
374
|
+
end++
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
const component = p.slice(start, end)
|
|
378
|
+
if (end === start) {
|
|
379
|
+
break
|
|
380
|
+
} else if (component === '.') {
|
|
381
|
+
start = end
|
|
382
|
+
continue
|
|
383
|
+
} else if (component === '..') {
|
|
384
|
+
// Back up to the previous component unless it is itself a kept "..".
|
|
385
|
+
let r = dest.length - 1
|
|
386
|
+
for (; r >= volLen; r--) {
|
|
387
|
+
if (dest[r] === '/') {
|
|
388
|
+
break
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (r < volLen || dest.slice(r + 1) === '..') {
|
|
392
|
+
if (dest.length > volLen) {
|
|
393
|
+
dest += '/'
|
|
394
|
+
}
|
|
395
|
+
dest += '..'
|
|
396
|
+
} else {
|
|
397
|
+
dest = dest.slice(0, r)
|
|
398
|
+
}
|
|
399
|
+
start = end
|
|
400
|
+
continue
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (dest.length > volLen && dest[dest.length - 1] !== '/') {
|
|
404
|
+
dest += '/'
|
|
405
|
+
}
|
|
406
|
+
dest += component
|
|
407
|
+
|
|
408
|
+
const [stat, statErr] = lstatPath(dest)
|
|
409
|
+
if (statErr !== null) {
|
|
410
|
+
return ['', statErr]
|
|
411
|
+
}
|
|
412
|
+
if (!statIsSymlink(stat!)) {
|
|
413
|
+
if (!statIsDir(stat!) && end < p.length) {
|
|
414
|
+
return ['', $.newError('not a directory')]
|
|
415
|
+
}
|
|
416
|
+
start = end
|
|
417
|
+
continue
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
linksWalked++
|
|
421
|
+
if (linksWalked > 255) {
|
|
422
|
+
return ['', $.newError('EvalSymlinks: too many links')]
|
|
423
|
+
}
|
|
424
|
+
const [link, linkErr] = readlinkPath(dest)
|
|
425
|
+
if (linkErr !== null) {
|
|
426
|
+
return ['', linkErr]
|
|
427
|
+
}
|
|
428
|
+
p = link! + p.slice(end)
|
|
429
|
+
if (link!.length > 0 && link![0] === '/') {
|
|
430
|
+
// Absolute symlink target: restart from the root.
|
|
431
|
+
dest = '/'
|
|
432
|
+
} else {
|
|
433
|
+
// Relative symlink target: replace the last component of dest.
|
|
434
|
+
let r = dest.length - 1
|
|
435
|
+
for (; r >= volLen; r--) {
|
|
436
|
+
if (dest[r] === '/') {
|
|
437
|
+
break
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
dest = r < volLen ? vol : dest.slice(0, r)
|
|
441
|
+
}
|
|
442
|
+
start = 0
|
|
443
|
+
}
|
|
444
|
+
return [Clean(dest), null]
|
|
313
445
|
}
|
|
314
446
|
|
|
315
447
|
export function Glob(_pattern: string): [string[], $.GoError] {
|
|
@@ -345,8 +477,13 @@ export async function WalkDir(
|
|
|
345
477
|
return await walkDirHost(root, walkFn)
|
|
346
478
|
}
|
|
347
479
|
|
|
348
|
-
// Localize
|
|
480
|
+
// Localize converts a slash-separated path into an operating system path.
|
|
481
|
+
// The input must be a valid path as reported by io/fs.ValidPath. On a
|
|
482
|
+
// Unix-like target the only further restriction is the absence of a NUL byte.
|
|
349
483
|
export function Localize(path: string): [string, $.GoError] {
|
|
484
|
+
if (!ValidPath(path) || path.indexOf('\x00') >= 0) {
|
|
485
|
+
return ['', $.newError('invalid path')]
|
|
486
|
+
}
|
|
350
487
|
return [path, null]
|
|
351
488
|
}
|
|
352
489
|
|
|
@@ -377,6 +514,13 @@ function statIsDir(stat: HostStat): boolean {
|
|
|
377
514
|
return !!stat.isDirectory
|
|
378
515
|
}
|
|
379
516
|
|
|
517
|
+
function statIsSymlink(stat: any): boolean {
|
|
518
|
+
if (typeof stat?.isSymbolicLink === 'function') {
|
|
519
|
+
return stat.isSymbolicLink()
|
|
520
|
+
}
|
|
521
|
+
return !!stat?.isSymlink
|
|
522
|
+
}
|
|
523
|
+
|
|
380
524
|
function fileInfo(path: string, stat: HostStat): any {
|
|
381
525
|
return {
|
|
382
526
|
IsDir: () => statIsDir(stat),
|
|
@@ -392,20 +536,50 @@ function dirEntry(path: string, stat: HostStat): DirEntry {
|
|
|
392
536
|
return FileInfoToDirEntry(fileInfo(path, stat))
|
|
393
537
|
}
|
|
394
538
|
|
|
395
|
-
|
|
539
|
+
// lstatPath stats a path without following a terminal symlink, matching Go's
|
|
540
|
+
// Walk/WalkDir, which Lstat every entry so a symlinked directory is reported as
|
|
541
|
+
// a symlink and is never descended into. Falls back to stat only when the host
|
|
542
|
+
// exposes no lstat.
|
|
543
|
+
function lstatPath(path: string): [HostStat | null, $.GoError] {
|
|
544
|
+
const runtime = getHostRuntime()
|
|
545
|
+
const deno = runtime.deno
|
|
546
|
+
const denoStat = deno?.lstatSync ?? deno?.statSync
|
|
547
|
+
if (denoStat) {
|
|
548
|
+
try {
|
|
549
|
+
return [denoStat.call(deno, path), null]
|
|
550
|
+
} catch (err) {
|
|
551
|
+
return [null, hostError(err)]
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const nodeFS = runtime.nodeFS
|
|
556
|
+
const nodeStat = nodeFS?.lstatSync ?? nodeFS?.statSync
|
|
557
|
+
if (nodeStat) {
|
|
558
|
+
try {
|
|
559
|
+
return [nodeStat.call(nodeFS, path), null]
|
|
560
|
+
} catch (err) {
|
|
561
|
+
return [null, hostError(err)]
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
return [null, $.newError('filesystem not supported')]
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
function readlinkPath(path: string): [string | null, $.GoError] {
|
|
396
569
|
const runtime = getHostRuntime()
|
|
397
|
-
|
|
570
|
+
const deno = runtime.deno
|
|
571
|
+
if (deno?.readLinkSync) {
|
|
398
572
|
try {
|
|
399
|
-
return [
|
|
573
|
+
return [deno.readLinkSync(path), null]
|
|
400
574
|
} catch (err) {
|
|
401
575
|
return [null, hostError(err)]
|
|
402
576
|
}
|
|
403
577
|
}
|
|
404
578
|
|
|
405
579
|
const nodeFS = runtime.nodeFS
|
|
406
|
-
if (nodeFS?.
|
|
580
|
+
if (nodeFS?.readlinkSync) {
|
|
407
581
|
try {
|
|
408
|
-
return [nodeFS.
|
|
582
|
+
return [String(nodeFS.readlinkSync(path)), null]
|
|
409
583
|
} catch (err) {
|
|
410
584
|
return [null, hostError(err)]
|
|
411
585
|
}
|
|
@@ -452,7 +626,7 @@ function readDir(path: string): [HostEntry[] | null, $.GoError] {
|
|
|
452
626
|
}
|
|
453
627
|
|
|
454
628
|
async function walkHost(path: string, walkFn: WalkFunc): Promise<$.GoError> {
|
|
455
|
-
const [stat, statErr] =
|
|
629
|
+
const [stat, statErr] = lstatPath(path)
|
|
456
630
|
if (statErr !== null) {
|
|
457
631
|
return await walkFn(path, null, statErr)
|
|
458
632
|
}
|
|
@@ -514,7 +688,7 @@ async function walkDirHost(
|
|
|
514
688
|
path: string,
|
|
515
689
|
walkFn: WalkDirFunc,
|
|
516
690
|
): Promise<$.GoError> {
|
|
517
|
-
const [stat, statErr] =
|
|
691
|
+
const [stat, statErr] = lstatPath(path)
|
|
518
692
|
if (statErr !== null) {
|
|
519
693
|
return normalizeRootWalkDirErr(await walkFn(path, null, statErr))
|
|
520
694
|
}
|