goscript 0.0.38 → 0.0.40

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 (180) hide show
  1. package/compiler/analysis.go +15 -6
  2. package/compiler/compiler.go +184 -34
  3. package/compiler/expr-call.go +19 -9
  4. package/compiler/field.go +17 -3
  5. package/compiler/gs_dependencies_test.go +80 -0
  6. package/compiler/lit.go +12 -6
  7. package/compiler/output.go +10 -4
  8. package/compiler/spec.go +15 -2
  9. package/compiler/type-assert.go +111 -21
  10. package/compiler/type.go +37 -8
  11. package/dist/gs/builtin/builtin.d.ts +55 -0
  12. package/dist/gs/builtin/builtin.js +213 -0
  13. package/dist/gs/builtin/builtin.js.map +1 -1
  14. package/dist/gs/builtin/slice.js +13 -0
  15. package/dist/gs/builtin/slice.js.map +1 -1
  16. package/dist/gs/bytes/buffer.gs.d.ts +56 -0
  17. package/dist/gs/bytes/buffer.gs.js +611 -0
  18. package/dist/gs/bytes/buffer.gs.js.map +1 -0
  19. package/dist/gs/bytes/bytes.gs.d.ts +78 -0
  20. package/dist/gs/bytes/bytes.gs.js +1107 -0
  21. package/dist/gs/bytes/bytes.gs.js.map +1 -0
  22. package/dist/gs/bytes/index.d.ts +4 -0
  23. package/dist/gs/bytes/index.js +5 -0
  24. package/dist/gs/bytes/index.js.map +1 -0
  25. package/dist/gs/bytes/iter.gs.d.ts +9 -0
  26. package/dist/gs/bytes/iter.gs.js +143 -0
  27. package/dist/gs/bytes/iter.gs.js.map +1 -0
  28. package/dist/gs/bytes/reader.gs.d.ts +34 -0
  29. package/dist/gs/bytes/reader.gs.js +198 -0
  30. package/dist/gs/bytes/reader.gs.js.map +1 -0
  31. package/dist/gs/fmt/fmt.d.ts +49 -0
  32. package/dist/gs/fmt/fmt.js +322 -0
  33. package/dist/gs/fmt/fmt.js.map +1 -0
  34. package/dist/gs/fmt/index.d.ts +1 -0
  35. package/dist/gs/fmt/index.js +2 -0
  36. package/dist/gs/fmt/index.js.map +1 -0
  37. package/dist/gs/internal/bytealg/index.d.ts +14 -2
  38. package/dist/gs/internal/bytealg/index.js +114 -8
  39. package/dist/gs/internal/bytealg/index.js.map +1 -1
  40. package/dist/gs/path/filepath/index.d.ts +3 -0
  41. package/dist/gs/path/filepath/index.js +3 -0
  42. package/dist/gs/path/filepath/index.js.map +1 -0
  43. package/dist/gs/path/filepath/match.d.ts +3 -0
  44. package/dist/gs/path/filepath/match.js +212 -0
  45. package/dist/gs/path/filepath/match.js.map +1 -0
  46. package/dist/gs/path/filepath/path.d.ts +25 -0
  47. package/dist/gs/path/filepath/path.js +265 -0
  48. package/dist/gs/path/filepath/path.js.map +1 -0
  49. package/dist/gs/reflect/deepequal.d.ts +2 -1
  50. package/dist/gs/reflect/deepequal.js +5 -53
  51. package/dist/gs/reflect/deepequal.js.map +1 -1
  52. package/dist/gs/reflect/map.d.ts +14 -8
  53. package/dist/gs/reflect/map.js +15 -11
  54. package/dist/gs/reflect/map.js.map +1 -1
  55. package/dist/gs/reflect/type.d.ts +17 -9
  56. package/dist/gs/reflect/type.js +1 -1
  57. package/dist/gs/reflect/type.js.map +1 -1
  58. package/dist/gs/reflect/value.js +15 -6
  59. package/dist/gs/reflect/value.js.map +1 -1
  60. package/dist/gs/reflect/visiblefields.js +18 -12
  61. package/dist/gs/reflect/visiblefields.js.map +1 -1
  62. package/dist/gs/sort/index.d.ts +4 -0
  63. package/dist/gs/sort/index.js +4 -0
  64. package/dist/gs/sort/index.js.map +1 -0
  65. package/dist/gs/sort/search.gs.d.ts +6 -0
  66. package/dist/gs/sort/search.gs.js +125 -0
  67. package/dist/gs/sort/search.gs.js.map +1 -0
  68. package/dist/gs/sort/slice.gs.d.ts +4 -0
  69. package/dist/gs/sort/slice.gs.js +49 -0
  70. package/dist/gs/sort/slice.gs.js.map +1 -0
  71. package/dist/gs/sort/sort.gs.d.ts +37 -0
  72. package/dist/gs/sort/sort.gs.js +203 -0
  73. package/dist/gs/sort/sort.gs.js.map +1 -0
  74. package/dist/gs/unicode/utf8/utf8.d.ts +1 -1
  75. package/dist/gs/unicode/utf8/utf8.js +4 -2
  76. package/dist/gs/unicode/utf8/utf8.js.map +1 -1
  77. package/gs/builtin/builtin.ts +236 -0
  78. package/gs/builtin/slice.ts +17 -1
  79. package/gs/bytes/buffer.gs.ts +614 -0
  80. package/gs/bytes/bytes.gs.ts +1288 -0
  81. package/gs/bytes/godoc.txt +69 -0
  82. package/gs/bytes/index.ts +69 -0
  83. package/gs/bytes/iter.gs.ts +149 -0
  84. package/gs/bytes/metadata.go +12 -0
  85. package/gs/bytes/reader.gs.ts +230 -0
  86. package/gs/fmt/fmt.ts +407 -0
  87. package/gs/fmt/godoc.txt +382 -0
  88. package/gs/fmt/index.ts +31 -0
  89. package/gs/fmt/metadata.go +7 -0
  90. package/gs/internal/bytealg/index.ts +125 -10
  91. package/gs/internal/metadata.go +7 -0
  92. package/gs/io/metadata.go +11 -0
  93. package/gs/maps/metadata.go +8 -0
  94. package/gs/math/metadata.go +7 -0
  95. package/gs/os/metadata.go +17 -0
  96. package/gs/path/filepath/godoc.txt +35 -0
  97. package/gs/path/filepath/index.ts +27 -0
  98. package/gs/path/filepath/match.test.ts +274 -0
  99. package/gs/path/filepath/match.ts +249 -0
  100. package/gs/path/filepath/path.test.ts +246 -0
  101. package/gs/path/filepath/path.ts +328 -0
  102. package/gs/path/metadata.go +8 -0
  103. package/gs/reflect/deepequal.test.ts +41 -0
  104. package/gs/reflect/deepequal.ts +19 -4
  105. package/gs/reflect/map.test.ts +30 -0
  106. package/gs/reflect/map.ts +22 -18
  107. package/gs/reflect/metadata.go +7 -0
  108. package/gs/reflect/type.ts +19 -15
  109. package/gs/reflect/value.ts +21 -7
  110. package/gs/reflect/visiblefields.ts +17 -13
  111. package/gs/sort/godoc.txt +27 -0
  112. package/gs/sort/index.ts +24 -0
  113. package/gs/sort/search.gs.ts +128 -0
  114. package/gs/sort/slice.gs.ts +59 -0
  115. package/gs/sort/sort.gs.ts +227 -0
  116. package/gs/strconv/metadata.go +7 -0
  117. package/gs/strings/metadata.go +11 -0
  118. package/gs/sync/metadata.go +7 -0
  119. package/gs/unicode/utf8/utf8.ts +8 -5
  120. package/package.json +1 -1
  121. package/dist/gs/internal/testlog/index.d.ts +0 -1
  122. package/dist/gs/internal/testlog/index.js +0 -5
  123. package/dist/gs/internal/testlog/index.js.map +0 -1
  124. package/dist/gs/maps/iter.gs.d.ts +0 -7
  125. package/dist/gs/maps/iter.gs.js +0 -65
  126. package/dist/gs/maps/iter.gs.js.map +0 -1
  127. package/dist/gs/maps/maps.gs.d.ts +0 -7
  128. package/dist/gs/maps/maps.gs.js +0 -79
  129. package/dist/gs/maps/maps.gs.js.map +0 -1
  130. package/dist/gs/reflect/abi.d.ts +0 -59
  131. package/dist/gs/reflect/abi.gs.d.ts +0 -59
  132. package/dist/gs/reflect/abi.gs.js +0 -79
  133. package/dist/gs/reflect/abi.gs.js.map +0 -1
  134. package/dist/gs/reflect/abi.js +0 -79
  135. package/dist/gs/reflect/abi.js.map +0 -1
  136. package/dist/gs/reflect/badlinkname.d.ts +0 -52
  137. package/dist/gs/reflect/badlinkname.gs.d.ts +0 -52
  138. package/dist/gs/reflect/badlinkname.gs.js +0 -72
  139. package/dist/gs/reflect/badlinkname.gs.js.map +0 -1
  140. package/dist/gs/reflect/badlinkname.js +0 -72
  141. package/dist/gs/reflect/badlinkname.js.map +0 -1
  142. package/dist/gs/reflect/deepequal.gs.d.ts +0 -25
  143. package/dist/gs/reflect/deepequal.gs.js +0 -308
  144. package/dist/gs/reflect/deepequal.gs.js.map +0 -1
  145. package/dist/gs/reflect/float32reg_generic.gs.d.ts +0 -2
  146. package/dist/gs/reflect/float32reg_generic.gs.js +0 -10
  147. package/dist/gs/reflect/float32reg_generic.gs.js.map +0 -1
  148. package/dist/gs/reflect/index.gs.d.ts +0 -1
  149. package/dist/gs/reflect/index.gs.js +0 -3
  150. package/dist/gs/reflect/index.gs.js.map +0 -1
  151. package/dist/gs/reflect/iter.gs.d.ts +0 -3
  152. package/dist/gs/reflect/iter.gs.js +0 -24
  153. package/dist/gs/reflect/iter.gs.js.map +0 -1
  154. package/dist/gs/reflect/makefunc.gs.d.ts +0 -34
  155. package/dist/gs/reflect/makefunc.gs.js +0 -288
  156. package/dist/gs/reflect/makefunc.gs.js.map +0 -1
  157. package/dist/gs/reflect/map_swiss.gs.d.ts +0 -14
  158. package/dist/gs/reflect/map_swiss.gs.js +0 -70
  159. package/dist/gs/reflect/map_swiss.gs.js.map +0 -1
  160. package/dist/gs/reflect/reflect.gs.d.ts +0 -132
  161. package/dist/gs/reflect/reflect.gs.js +0 -437
  162. package/dist/gs/reflect/reflect.gs.js.map +0 -1
  163. package/dist/gs/reflect/swapper.gs.d.ts +0 -1
  164. package/dist/gs/reflect/swapper.gs.js +0 -32
  165. package/dist/gs/reflect/swapper.gs.js.map +0 -1
  166. package/dist/gs/reflect/type.gs.d.ts +0 -4
  167. package/dist/gs/reflect/type.gs.js +0 -21
  168. package/dist/gs/reflect/type.gs.js.map +0 -1
  169. package/dist/gs/reflect/value.gs.d.ts +0 -4
  170. package/dist/gs/reflect/value.gs.js +0 -12
  171. package/dist/gs/reflect/value.gs.js.map +0 -1
  172. package/dist/gs/reflect/visiblefields.gs.d.ts +0 -3
  173. package/dist/gs/reflect/visiblefields.gs.js +0 -123
  174. package/dist/gs/reflect/visiblefields.gs.js.map +0 -1
  175. package/dist/gs/stringslite/index.d.ts +0 -1
  176. package/dist/gs/stringslite/index.js +0 -2
  177. package/dist/gs/stringslite/index.js.map +0 -1
  178. package/dist/gs/stringslite/strings.d.ts +0 -11
  179. package/dist/gs/stringslite/strings.js +0 -67
  180. package/dist/gs/stringslite/strings.js.map +0 -1
@@ -0,0 +1,246 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import {
3
+ Base,
4
+ Dir,
5
+ Ext,
6
+ Clean,
7
+ Join,
8
+ Split,
9
+ IsAbs,
10
+ ToSlash,
11
+ FromSlash,
12
+ VolumeName,
13
+ IsLocal,
14
+ SplitList,
15
+ HasPrefix,
16
+ Abs,
17
+ Rel,
18
+ EvalSymlinks,
19
+ Separator,
20
+ ListSeparator,
21
+ } from './path.js'
22
+
23
+ describe('path/filepath - Path manipulation functions', () => {
24
+ describe('Base', () => {
25
+ it('should return the last element of path', () => {
26
+ expect(Base('dir/subdir/file.txt')).toBe('file.txt')
27
+ expect(Base('/usr/bin/ls')).toBe('ls')
28
+ expect(Base('file.txt')).toBe('file.txt')
29
+ expect(Base('/')).toBe('/')
30
+ expect(Base('')).toBe('.')
31
+ expect(Base('//')).toBe('/')
32
+ expect(Base('dir/')).toBe('dir')
33
+ expect(Base('dir//')).toBe('dir')
34
+ })
35
+ })
36
+
37
+ describe('Dir', () => {
38
+ it('should return directory portion of path', () => {
39
+ expect(Dir('dir/subdir/file.txt')).toBe('dir/subdir')
40
+ expect(Dir('/usr/bin/ls')).toBe('/usr/bin')
41
+ expect(Dir('file.txt')).toBe('.')
42
+ expect(Dir('/')).toBe('/')
43
+ expect(Dir('')).toBe('.')
44
+ expect(Dir('/file')).toBe('/')
45
+ expect(Dir('dir/')).toBe('.')
46
+ })
47
+ })
48
+
49
+ describe('Ext', () => {
50
+ it('should return file extension', () => {
51
+ expect(Ext('file.txt')).toBe('.txt')
52
+ expect(Ext('file.tar.gz')).toBe('.gz')
53
+ expect(Ext('file')).toBe('')
54
+ expect(Ext('.hidden')).toBe('')
55
+ expect(Ext('dir/file.txt')).toBe('.txt')
56
+ expect(Ext('')).toBe('')
57
+ })
58
+ })
59
+
60
+ describe('Clean', () => {
61
+ it('should clean up path by resolving . and .. elements', () => {
62
+ expect(Clean('dir//subdir/../subdir/./file.txt')).toBe(
63
+ 'dir/subdir/file.txt',
64
+ )
65
+ expect(Clean('/dir/../file')).toBe('/file')
66
+ expect(Clean('./file')).toBe('file')
67
+ expect(Clean('../file')).toBe('../file')
68
+ expect(Clean('dir/..')).toBe('.')
69
+ expect(Clean('/dir/..')).toBe('/')
70
+ expect(Clean('')).toBe('.')
71
+ expect(Clean('/')).toBe('/')
72
+ expect(Clean('///')).toBe('/')
73
+ })
74
+ })
75
+
76
+ describe('Join', () => {
77
+ it('should join path elements with separator', () => {
78
+ expect(Join('dir', 'subdir', 'file.txt')).toBe('dir/subdir/file.txt')
79
+ expect(Join('/usr', 'bin', 'ls')).toBe('/usr/bin/ls')
80
+ expect(Join('', 'file')).toBe('file')
81
+ expect(Join('dir', '', 'file')).toBe('dir/file')
82
+ expect(Join()).toBe('')
83
+ expect(Join('', '', '')).toBe('')
84
+ })
85
+ })
86
+
87
+ describe('Split', () => {
88
+ it('should split path into directory and file', () => {
89
+ expect(Split('dir/subdir/file.txt')).toEqual(['dir/subdir/', 'file.txt'])
90
+ expect(Split('/usr/bin/ls')).toEqual(['/usr/bin/', 'ls'])
91
+ expect(Split('file.txt')).toEqual(['', 'file.txt'])
92
+ expect(Split('/')).toEqual(['/', ''])
93
+ expect(Split('')).toEqual(['', ''])
94
+ })
95
+ })
96
+
97
+ describe('IsAbs', () => {
98
+ it('should check if path is absolute', () => {
99
+ expect(IsAbs('/absolute/path')).toBe(true)
100
+ expect(IsAbs('relative/path')).toBe(false)
101
+ expect(IsAbs('/')).toBe(true)
102
+ expect(IsAbs('')).toBe(false)
103
+ expect(IsAbs('./relative')).toBe(false)
104
+ })
105
+ })
106
+
107
+ describe('ToSlash', () => {
108
+ it('should preserve path on Unix systems (backslashes are regular chars)', () => {
109
+ // On Unix systems, ToSlash doesn't convert backslashes because they're not separators
110
+ expect(ToSlash('dir\\subdir\\file.txt')).toBe('dir\\subdir\\file.txt')
111
+ expect(ToSlash('dir/subdir/file.txt')).toBe('dir/subdir/file.txt')
112
+ expect(ToSlash('')).toBe('')
113
+ })
114
+ })
115
+
116
+ describe('FromSlash', () => {
117
+ it('should preserve path on Unix systems', () => {
118
+ // On Unix systems, FromSlash doesn't change anything because separator is already '/'
119
+ expect(FromSlash('dir/subdir/file.txt')).toBe('dir/subdir/file.txt')
120
+ expect(FromSlash('')).toBe('')
121
+ })
122
+ })
123
+
124
+ describe('VolumeName', () => {
125
+ it('should return empty string on Unix systems', () => {
126
+ expect(VolumeName('C:\\Windows\\System32')).toBe('')
127
+ expect(VolumeName('/usr/local')).toBe('')
128
+ expect(VolumeName('')).toBe('')
129
+ })
130
+ })
131
+
132
+ describe('IsLocal', () => {
133
+ it('should check if path is local (not escaping)', () => {
134
+ expect(IsLocal('file.txt')).toBe(true)
135
+ expect(IsLocal('dir/file.txt')).toBe(true)
136
+ expect(IsLocal('../file.txt')).toBe(false)
137
+ expect(IsLocal('/absolute/path')).toBe(false)
138
+ expect(IsLocal('')).toBe(false)
139
+ expect(IsLocal('dir/../file')).toBe(true)
140
+ expect(IsLocal('dir/../../file')).toBe(false)
141
+ })
142
+ })
143
+
144
+ describe('SplitList', () => {
145
+ it('should split PATH-style lists', () => {
146
+ expect(SplitList('/usr/bin:/usr/local/bin:/bin')).toEqual([
147
+ '/usr/bin',
148
+ '/usr/local/bin',
149
+ '/bin',
150
+ ])
151
+ expect(SplitList('')).toEqual([])
152
+ expect(SplitList('/single/path')).toEqual(['/single/path'])
153
+ expect(SplitList('a:b:c')).toEqual(['a', 'b', 'c'])
154
+ })
155
+ })
156
+
157
+ describe('HasPrefix', () => {
158
+ it('should check if path has prefix', () => {
159
+ expect(HasPrefix('/usr/local/bin', '/usr/local')).toBe(true)
160
+ expect(HasPrefix('/usr/local', '/usr/local')).toBe(true)
161
+ expect(HasPrefix('/usr/local/bin', '/usr/bin')).toBe(false)
162
+ expect(HasPrefix('relative/path', 'relative')).toBe(true)
163
+ expect(HasPrefix('file.txt', '')).toBe(true)
164
+ expect(HasPrefix('', 'prefix')).toBe(false)
165
+ })
166
+ })
167
+
168
+ describe('Abs', () => {
169
+ it('should handle absolute paths', () => {
170
+ const [result1, err1] = Abs('/absolute/path')
171
+ expect(err1).toBeNull()
172
+ expect(result1).toBe('/absolute/path')
173
+
174
+ const [result2, err2] = Abs('relative/path')
175
+ expect(err2).toBeNull()
176
+ expect(result2).toBe('/relative/path')
177
+ })
178
+ })
179
+
180
+ describe('Rel', () => {
181
+ it('should calculate relative path', () => {
182
+ const [result1, err1] = Rel('/usr/local', '/usr/local')
183
+ expect(err1).toBeNull()
184
+ expect(result1).toBe('.')
185
+
186
+ const [result2, err2] = Rel('/usr/local', '/usr/local/bin')
187
+ expect(err2).toBeNull()
188
+ expect(result2).toBe('bin')
189
+
190
+ const [result3, err3] = Rel('/usr/local', '/other/path')
191
+ expect(err3).toBeNull()
192
+ expect(result3).toBe('/other/path')
193
+ })
194
+ })
195
+
196
+ describe('EvalSymlinks', () => {
197
+ it('should return cleaned path (stubbed)', () => {
198
+ const [result, err] = EvalSymlinks('/path/with/../dots')
199
+ expect(err).toBeNull()
200
+ expect(result).toBe('/path/dots')
201
+ })
202
+ })
203
+
204
+ describe('Constants', () => {
205
+ it('should have correct separator constants', () => {
206
+ expect(Separator).toBe('/')
207
+ expect(ListSeparator).toBe(':')
208
+ })
209
+ })
210
+ })
211
+
212
+ describe('Complex path operations', () => {
213
+ it('should handle edge cases correctly', () => {
214
+ // Test Clean with complex paths
215
+ expect(Clean('/a/b/../c/./d/')).toBe('/a/c/d')
216
+ expect(Clean('a/b/../../c')).toBe('c')
217
+ expect(Clean('../../a/b')).toBe('../../a/b')
218
+
219
+ // Test Join with various inputs
220
+ expect(Join('/a', '../b', 'c')).toBe('/b/c')
221
+ expect(Join('a', '/b', 'c')).toBe('/b/c')
222
+
223
+ // Test Split edge cases
224
+ expect(Split('/a/')).toEqual(['/a/', ''])
225
+ expect(Split('//a')).toEqual(['//', 'a'])
226
+ })
227
+
228
+ it('should maintain path consistency', () => {
229
+ const testPaths = [
230
+ 'simple/path',
231
+ '/absolute/path',
232
+ 'path/with/../dots',
233
+ './relative/path',
234
+ '../../parent/path',
235
+ ]
236
+
237
+ for (const path of testPaths) {
238
+ const cleaned = Clean(path)
239
+ const [dir, file] = Split(cleaned)
240
+ const rejoined = dir + file
241
+
242
+ // Split and rejoin should preserve the cleaned path
243
+ expect(rejoined).toBe(cleaned)
244
+ }
245
+ })
246
+ })
@@ -0,0 +1,328 @@
1
+ // Package filepath implements utility routines for manipulating filename paths
2
+ // in a way compatible with the target operating system-defined file paths.
3
+
4
+ // Path separator constants
5
+ export const Separator = '/'
6
+ export const ListSeparator = ':'
7
+
8
+ // Error constants
9
+ export const SkipDir = new Error('skip this directory')
10
+ export const SkipAll = new Error('skip everything and stop the walk')
11
+
12
+ // Base returns the last element of path.
13
+ // Trailing path separators are removed before extracting the last element.
14
+ // If the path is empty, Base returns ".".
15
+ // If the path consists entirely of separators, Base returns a single separator.
16
+ export function Base(path: string): string {
17
+ if (path === '') {
18
+ return '.'
19
+ }
20
+
21
+ // Strip trailing slashes
22
+ path = path.replace(/\/+$/, '')
23
+
24
+ if (path === '') {
25
+ return '/'
26
+ }
27
+
28
+ // Find the last slash
29
+ const i = path.lastIndexOf('/')
30
+ if (i >= 0) {
31
+ return path.substring(i + 1)
32
+ }
33
+
34
+ return path
35
+ }
36
+
37
+ // Dir returns all but the last element of path, typically the path's directory.
38
+ // After dropping the final element, Dir calls Clean on the path and trailing
39
+ // slashes are removed. If the path is empty, Dir returns ".".
40
+ // If the path consists entirely of separators, Dir returns a single separator.
41
+ export function Dir(path: string): string {
42
+ if (path === '') {
43
+ return '.'
44
+ }
45
+
46
+ // Strip trailing slashes
47
+ path = path.replace(/\/+$/, '')
48
+
49
+ if (path === '') {
50
+ return '/'
51
+ }
52
+
53
+ // Find the last slash
54
+ const i = path.lastIndexOf('/')
55
+ if (i >= 0) {
56
+ const dir = path.substring(0, i)
57
+ return Clean(dir === '' ? '/' : dir)
58
+ }
59
+
60
+ return '.'
61
+ }
62
+
63
+ // Ext returns the file name extension used by path.
64
+ // The extension is the suffix beginning at the final dot
65
+ // in the final element of path; it is empty if there is no dot.
66
+ export function Ext(path: string): string {
67
+ const base = Base(path)
68
+
69
+ // Handle special case: if the base starts with a dot and has no other dots,
70
+ // it's a hidden file with no extension
71
+ if (base.startsWith('.') && base.indexOf('.', 1) === -1) {
72
+ return ''
73
+ }
74
+
75
+ const i = base.lastIndexOf('.')
76
+ if (i >= 0) {
77
+ return base.substring(i)
78
+ }
79
+ return ''
80
+ }
81
+
82
+ // Clean returns the shortest path name equivalent to path
83
+ // by purely lexical processing.
84
+ export function Clean(path: string): string {
85
+ if (path === '') {
86
+ return '.'
87
+ }
88
+
89
+ const isAbs = path.startsWith('/')
90
+ const segments = path
91
+ .split('/')
92
+ .filter((segment) => segment !== '' && segment !== '.')
93
+ const result: string[] = []
94
+
95
+ for (const segment of segments) {
96
+ if (segment === '..') {
97
+ if (result.length > 0 && result[result.length - 1] !== '..') {
98
+ result.pop()
99
+ } else if (!isAbs) {
100
+ result.push('..')
101
+ }
102
+ } else {
103
+ result.push(segment)
104
+ }
105
+ }
106
+
107
+ let cleaned = result.join('/')
108
+ if (isAbs) {
109
+ cleaned = '/' + cleaned
110
+ }
111
+
112
+ return (
113
+ cleaned === '' ?
114
+ isAbs ? '/'
115
+ : '.'
116
+ : cleaned
117
+ )
118
+ }
119
+
120
+ // Join joins any number of path elements into a single path,
121
+ // separating them with an OS specific Separator. Empty elements
122
+ // are ignored. The result is Cleaned. However, if the argument
123
+ // list is empty or all its elements are empty, Join returns
124
+ // an empty string.
125
+ export function Join(...elem: string[]): string {
126
+ if (elem.length === 0) {
127
+ return ''
128
+ }
129
+
130
+ // Filter out empty elements but handle absolute paths
131
+ const parts: string[] = []
132
+
133
+ for (const e of elem) {
134
+ if (e === '') {
135
+ continue
136
+ }
137
+
138
+ // If this element is absolute, start over from here
139
+ if (IsAbs(e)) {
140
+ parts.length = 0 // Clear previous parts
141
+ parts.push(e)
142
+ } else {
143
+ parts.push(e)
144
+ }
145
+ }
146
+
147
+ if (parts.length === 0) {
148
+ return ''
149
+ }
150
+
151
+ return Clean(parts.join('/'))
152
+ }
153
+
154
+ // Split splits path immediately following the final Separator,
155
+ // separating it into a directory and file name component.
156
+ // If there is no Separator in path, Split returns an empty dir
157
+ // and file set to path. The returned values have the property
158
+ // that path = dir+file.
159
+ export function Split(path: string): [string, string] {
160
+ const i = path.lastIndexOf('/')
161
+ if (i < 0) {
162
+ return ['', path]
163
+ }
164
+ return [path.substring(0, i + 1), path.substring(i + 1)]
165
+ }
166
+
167
+ // IsAbs reports whether the path is absolute.
168
+ export function IsAbs(path: string): boolean {
169
+ return path.startsWith('/')
170
+ }
171
+
172
+ // ToSlash returns the result of replacing each separator character
173
+ // in path with a slash ('/') character. Multiple separators are
174
+ // replaced by multiple slashes.
175
+ export function ToSlash(path: string): string {
176
+ // On Unix-like systems (including our JS environment), the separator is already '/'
177
+ // so backslashes are just regular characters and should not be converted
178
+ // This matches Go's behavior on Unix systems
179
+ return path
180
+ }
181
+
182
+ // FromSlash returns the result of replacing each slash ('/') character
183
+ // in path with a separator character. Multiple slashes are replaced
184
+ // by multiple separators.
185
+ export function FromSlash(path: string): string {
186
+ // On Unix-like systems (including our JS environment), separator is '/'
187
+ // so no conversion needed
188
+ return path
189
+ }
190
+
191
+ // VolumeName returns leading volume name.
192
+ // Given "C:\foo\bar" it returns "C:" on Windows.
193
+ // Given "\\host\share\foo" it returns "\\host\share".
194
+ // On other systems, it returns "".
195
+ export function VolumeName(_path: string): string {
196
+ // In our JS environment, we don't have volume names
197
+ return ''
198
+ }
199
+
200
+ // IsLocal reports whether path, using lexical analysis only,
201
+ // has all of these properties:
202
+ // - is within the subtree rooted at the directory in which path is evaluated
203
+ // - is not an absolute path
204
+ // - is not empty
205
+ // - on Windows, is not a reserved name such as "NUL"
206
+ export function IsLocal(path: string): boolean {
207
+ if (path === '' || IsAbs(path)) {
208
+ return false
209
+ }
210
+
211
+ // Check for .. components that would escape
212
+ const segments = path.split('/')
213
+ let depth = 0
214
+
215
+ for (const segment of segments) {
216
+ if (segment === '..') {
217
+ depth--
218
+ if (depth < 0) {
219
+ return false
220
+ }
221
+ } else if (segment !== '.' && segment !== '') {
222
+ depth++
223
+ }
224
+ }
225
+
226
+ return true
227
+ }
228
+
229
+ // SplitList splits a list of paths joined by the OS-specific ListSeparator,
230
+ // usually found in PATH or GOPATH environment variables.
231
+ // Unlike strings.Split, SplitList returns an empty slice when passed an empty string.
232
+ export function SplitList(path: string): string[] {
233
+ if (path === '') {
234
+ return []
235
+ }
236
+ return path.split(ListSeparator)
237
+ }
238
+
239
+ // HasPrefix tests whether the path p begins with prefix.
240
+ export function HasPrefix(p: string, prefix: string): boolean {
241
+ if (prefix === '') {
242
+ return true
243
+ }
244
+
245
+ // Normalize both paths
246
+ const normalP = Clean(p)
247
+ const normalPrefix = Clean(prefix)
248
+
249
+ if (normalP === normalPrefix) {
250
+ return true
251
+ }
252
+
253
+ // Check if p starts with prefix followed by a separator
254
+ if (normalP.startsWith(normalPrefix)) {
255
+ const remaining = normalP.substring(normalPrefix.length)
256
+ return remaining.startsWith('/')
257
+ }
258
+
259
+ return false
260
+ }
261
+
262
+ // Stubs for functions that require filesystem operations
263
+ // These are simplified implementations for compatibility
264
+
265
+ export function Abs(path: string): [string, Error | null] {
266
+ if (IsAbs(path)) {
267
+ return [Clean(path), null]
268
+ }
269
+ // In a real implementation, this would resolve relative to current working directory
270
+ // For our purposes, we'll just prepend a fake absolute path
271
+ return ['/' + Clean(path), null]
272
+ }
273
+
274
+ export function Rel(
275
+ basepath: string,
276
+ targpath: string,
277
+ ): [string, Error | null] {
278
+ // Simplified implementation - in reality this is much more complex
279
+ const base = Clean(basepath)
280
+ const targ = Clean(targpath)
281
+
282
+ if (base === targ) {
283
+ return ['.', null]
284
+ }
285
+
286
+ // Very basic relative path calculation
287
+ if (targ.startsWith(base + '/')) {
288
+ return [targ.substring(base.length + 1), null]
289
+ }
290
+
291
+ return [targ, null]
292
+ }
293
+
294
+ export function EvalSymlinks(path: string): [string, Error | null] {
295
+ // No filesystem support, just return the cleaned path
296
+ return [Clean(path), null]
297
+ }
298
+
299
+ export function Glob(_pattern: string): [string[], Error | null] {
300
+ // No filesystem support, return empty array
301
+ return [[], null]
302
+ }
303
+
304
+ // WalkFunc is the type of the function called for each file or directory
305
+ // visited by Walk. The path argument contains the argument to Walk as a
306
+ // prefix; that is, if Walk is called with "dir" and finds a file "a"
307
+ // in that directory, the walk function will be called with argument
308
+ // "dir/a". The info argument is the fs.FileInfo for the named path.
309
+ export type WalkFunc = (
310
+ path: string,
311
+ info: any,
312
+ err: Error | null,
313
+ ) => Error | null
314
+
315
+ export function Walk(root: string, walkFn: WalkFunc): Error | null {
316
+ // No filesystem support, just call the function with the root
317
+ return walkFn(root, null, new Error('filesystem not supported'))
318
+ }
319
+
320
+ export function WalkDir(_root: string, _walkFn: any): Error | null {
321
+ // No filesystem support
322
+ return new Error('filesystem not supported')
323
+ }
324
+
325
+ // Localize is a stub - in Go it's used for Windows path localization
326
+ export function Localize(path: string): [string, Error | null] {
327
+ return [path, null]
328
+ }
@@ -0,0 +1,8 @@
1
+ package path
2
+
3
+ // GsDependencies lists the import paths that this gs/ package requires
4
+ // These dependencies will be automatically copied when this package is included
5
+ var GsDependencies = []string{
6
+ "errors",
7
+ "unicode/utf8",
8
+ }
@@ -0,0 +1,41 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { DeepEqual } from './deepequal.js'
3
+ import { Value, BasicType, Int, String as StringType } from './type.js'
4
+
5
+ describe('DeepEqual', () => {
6
+ it('should compare primitive values correctly', () => {
7
+ expect(DeepEqual(5, 5)).toBe(true)
8
+ expect(DeepEqual(5, 10)).toBe(false)
9
+
10
+ expect(DeepEqual('hello', 'hello')).toBe(true)
11
+ expect(DeepEqual('hello', 'world')).toBe(false)
12
+
13
+ expect(DeepEqual(true, true)).toBe(true)
14
+ expect(DeepEqual(true, false)).toBe(false)
15
+
16
+ expect(DeepEqual(null, null)).toBe(true)
17
+ expect(DeepEqual(undefined, undefined)).toBe(true)
18
+ expect(DeepEqual(null, undefined)).toBe(false)
19
+ })
20
+
21
+ it('should compare arrays correctly', () => {
22
+ expect(DeepEqual([1, 2, 3], [1, 2, 3])).toBe(true)
23
+ expect(DeepEqual([1, 2, 3], [1, 2, 4])).toBe(false)
24
+ expect(DeepEqual([1, 2, 3], [1, 2])).toBe(false)
25
+ })
26
+
27
+ it('should compare objects correctly', () => {
28
+ expect(DeepEqual({ a: 1, b: 2 }, { a: 1, b: 2 })).toBe(true)
29
+ expect(DeepEqual({ a: 1, b: 2 }, { a: 1, b: 3 })).toBe(false)
30
+ expect(DeepEqual({ a: 1, b: 2 }, { a: 1 })).toBe(false)
31
+ })
32
+
33
+ it('should compare Value objects correctly', () => {
34
+ const v1 = new Value(42, new BasicType(Int, 'int'))
35
+ const v2 = new Value(42, new BasicType(Int, 'int'))
36
+ const v3 = new Value('hello', new BasicType(StringType, 'string'))
37
+
38
+ expect(DeepEqual(v1, v2)).toBe(true)
39
+ expect(DeepEqual(v1, v3)).toBe(false)
40
+ })
41
+ })
@@ -49,7 +49,12 @@
49
49
  // values that have been compared before, it treats the values as
50
50
  // equal rather than examining the values to which they point.
51
51
  // This ensures that DeepEqual terminates.
52
- export function DeepEqual(x: null | any, y: null | any): boolean {
52
+ import { ReflectValue } from './types.js'
53
+
54
+ export function DeepEqual(
55
+ x: ReflectValue | null | undefined,
56
+ y: ReflectValue | null | undefined,
57
+ ): boolean {
53
58
  // Handle null/undefined cases
54
59
  if (x === y) {
55
60
  return true
@@ -112,7 +117,12 @@ export function DeepEqual(x: null | any, y: null | any): boolean {
112
117
 
113
118
  // Compare elements
114
119
  for (let i = 0; i < xMeta.length; i++) {
115
- if (!DeepEqual(xMeta.backing[i], yMeta.backing[i])) {
120
+ if (
121
+ !DeepEqual(
122
+ xMeta.backing[i] as ReflectValue,
123
+ yMeta.backing[i] as ReflectValue,
124
+ )
125
+ ) {
116
126
  return false
117
127
  }
118
128
  }
@@ -127,7 +137,10 @@ export function DeepEqual(x: null | any, y: null | any): boolean {
127
137
  return false
128
138
  }
129
139
  for (const [key, value] of x) {
130
- if (!y.has(key) || !DeepEqual(value, y.get(key))) {
140
+ if (
141
+ !y.has(key) ||
142
+ !DeepEqual(value as ReflectValue, y.get(key) as ReflectValue)
143
+ ) {
131
144
  return false
132
145
  }
133
146
  }
@@ -142,7 +155,9 @@ export function DeepEqual(x: null | any, y: null | any): boolean {
142
155
  return false
143
156
  }
144
157
  for (const key of keysX) {
145
- if (!keysY.includes(key) || !DeepEqual(x[key], y[key])) {
158
+ const xObj = x as Record<string, ReflectValue>
159
+ const yObj = y as Record<string, ReflectValue>
160
+ if (!keysY.includes(key) || !DeepEqual(xObj[key], yObj[key])) {
146
161
  return false
147
162
  }
148
163
  }