goscript 0.0.84 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -1
- package/cmd/goscript/cmd_compile.go +70 -69
- package/cmd/goscript/cmd_compile_test.go +79 -0
- package/cmd/goscript/main.go +10 -5
- package/compiler/compile-request.go +218 -0
- package/compiler/compiler.go +16 -1336
- package/compiler/compliance_test.go +196 -0
- package/compiler/config.go +6 -13
- package/compiler/diagnostic.go +70 -0
- package/compiler/index.test.ts +28 -28
- package/compiler/index.ts +40 -72
- package/compiler/lowered-program.go +132 -0
- package/compiler/lowering.go +3576 -0
- package/compiler/override-registry.go +422 -0
- package/compiler/override-registry_test.go +207 -0
- package/compiler/package-graph.go +231 -0
- package/compiler/package-graph_test.go +281 -0
- package/compiler/result.go +13 -0
- package/compiler/runtime-contract.go +279 -0
- package/compiler/runtime-contract_test.go +90 -0
- package/compiler/semantic-model-types.go +110 -0
- package/compiler/semantic-model.go +922 -0
- package/compiler/semantic-model_test.go +416 -0
- package/compiler/service.go +133 -0
- package/compiler/skeleton_test.go +1145 -0
- package/compiler/typescript-emitter.go +663 -0
- package/compiler/wasm/compile.go +2 -3
- package/compiler/wasm/compile_test.go +29 -0
- package/compiler/wasm_api.go +10 -159
- package/dist/compiler/index.d.ts +1 -3
- package/dist/compiler/index.js +31 -55
- package/dist/compiler/index.js.map +1 -1
- package/dist/gs/builtin/builtin.d.ts +13 -0
- package/dist/gs/builtin/builtin.js +23 -0
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/channel.d.ts +3 -3
- package/dist/gs/builtin/channel.js.map +1 -1
- package/dist/gs/builtin/hostio.d.ts +15 -1
- package/dist/gs/builtin/hostio.js +134 -49
- 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/slice.d.ts +1 -1
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.d.ts +11 -0
- package/dist/gs/builtin/type.js +55 -1
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/bytes/buffer.gs.js.map +1 -1
- package/dist/gs/bytes/bytes.gs.js.map +1 -1
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/crypto/rand/index.d.ts +5 -0
- package/dist/gs/crypto/rand/index.js +77 -0
- package/dist/gs/crypto/rand/index.js.map +1 -0
- package/dist/gs/encoding/json/index.d.ts +3 -0
- package/dist/gs/encoding/json/index.js +160 -0
- package/dist/gs/encoding/json/index.js.map +1 -0
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +1 -1
- package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
- package/dist/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/browser.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/errors.js.map +1 -1
- package/dist/gs/github.com/pkg/errors/stack.js.map +1 -1
- package/dist/gs/go/scanner/index.d.ts +29 -0
- package/dist/gs/go/scanner/index.js +120 -0
- package/dist/gs/go/scanner/index.js.map +1 -0
- package/dist/gs/go/token/index.d.ts +31 -0
- package/dist/gs/go/token/index.js +82 -0
- package/dist/gs/go/token/index.js.map +1 -0
- package/dist/gs/internal/abi/index.js.map +1 -1
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/io/fs/readdir.js.map +1 -1
- package/dist/gs/io/fs/readfile.js.map +1 -1
- package/dist/gs/io/fs/stat.js.map +1 -1
- package/dist/gs/io/fs/sub.js.map +1 -1
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/os/dir_unix.gs.js.map +1 -1
- package/dist/gs/os/error.gs.js +2 -4
- package/dist/gs/os/error.gs.js.map +1 -1
- package/dist/gs/os/exec.gs.js.map +1 -1
- package/dist/gs/os/exec_posix.gs.js.map +1 -1
- package/dist/gs/os/rawconn_js.gs.js.map +1 -1
- package/dist/gs/os/root_js.gs.js.map +1 -1
- package/dist/gs/os/tempfile.gs.js +66 -9
- package/dist/gs/os/tempfile.gs.js.map +1 -1
- package/dist/gs/os/types.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.js +9 -9
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/match.js.map +1 -1
- package/dist/gs/path/path.js.map +1 -1
- package/dist/gs/reflect/index.d.ts +2 -2
- package/dist/gs/reflect/index.js +1 -1
- package/dist/gs/reflect/index.js.map +1 -1
- package/dist/gs/reflect/map.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +2 -1
- package/dist/gs/reflect/type.js +85 -14
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/reflect/types.js.map +1 -1
- package/dist/gs/reflect/visiblefields.js.map +1 -1
- package/dist/gs/runtime/runtime.js.map +1 -1
- package/dist/gs/sort/sort.gs.js.map +1 -1
- package/dist/gs/strconv/atoi.gs.js.map +1 -1
- package/dist/gs/strconv/quote.gs.js.map +1 -1
- package/dist/gs/strings/builder.js.map +1 -1
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/replace.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/atomic/value.gs.js.map +1 -1
- package/dist/gs/sync/sync.d.ts +1 -0
- package/dist/gs/sync/sync.js +12 -0
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/go.mod +2 -2
- package/gs/builtin/builtin.ts +27 -0
- package/gs/builtin/hostio.test.ts +177 -0
- package/gs/builtin/hostio.ts +171 -56
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/runtime-contract.test.ts +230 -0
- package/gs/builtin/type.ts +84 -1
- package/gs/crypto/rand/index.test.ts +32 -0
- package/gs/crypto/rand/index.ts +90 -0
- package/gs/crypto/rand/meta.json +5 -0
- package/gs/encoding/json/index.test.ts +65 -0
- package/gs/encoding/json/index.ts +186 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +23 -0
- package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +3 -1
- package/gs/github.com/aperturerobotics/wasivm/wazero/kernel/runtime/browser/meta.json +3 -1
- package/gs/go/scanner/index.test.ts +50 -0
- package/gs/go/scanner/index.ts +157 -0
- package/gs/go/token/index.test.ts +21 -0
- package/gs/go/token/index.ts +120 -0
- package/gs/os/file_unix_js.test.ts +50 -0
- package/gs/os/meta.json +1 -2
- package/gs/os/tempfile.gs.test.ts +85 -0
- package/gs/os/tempfile.gs.ts +71 -11
- package/gs/os/types_js.gs.ts +9 -9
- package/gs/reflect/index.ts +1 -1
- package/gs/reflect/type.ts +106 -17
- package/gs/reflect/typefor.test.ts +75 -0
- package/gs/sync/sync.test.ts +24 -0
- package/gs/sync/sync.ts +12 -0
- package/package.json +13 -13
- package/compiler/analysis.go +0 -3475
- package/compiler/analysis_test.go +0 -338
- package/compiler/assignment.go +0 -580
- package/compiler/builtin_test.go +0 -92
- package/compiler/code-writer.go +0 -115
- package/compiler/compiler_test.go +0 -149
- package/compiler/composite-lit.go +0 -779
- package/compiler/config_test.go +0 -62
- package/compiler/constraint.go +0 -86
- package/compiler/decl.go +0 -801
- package/compiler/expr-call-async.go +0 -188
- package/compiler/expr-call-builtins.go +0 -208
- package/compiler/expr-call-helpers.go +0 -382
- package/compiler/expr-call-make.go +0 -318
- package/compiler/expr-call-type-conversion.go +0 -520
- package/compiler/expr-call.go +0 -413
- package/compiler/expr-selector.go +0 -343
- package/compiler/expr-star.go +0 -82
- package/compiler/expr-type.go +0 -442
- package/compiler/expr-value.go +0 -89
- package/compiler/expr.go +0 -773
- package/compiler/field.go +0 -183
- package/compiler/gs_dependencies_test.go +0 -298
- package/compiler/lit.go +0 -322
- package/compiler/output.go +0 -72
- package/compiler/primitive.go +0 -149
- package/compiler/protobuf.go +0 -697
- package/compiler/sanitize.go +0 -100
- package/compiler/spec-struct.go +0 -995
- package/compiler/spec-value.go +0 -540
- package/compiler/spec.go +0 -725
- package/compiler/stmt-assign.go +0 -664
- package/compiler/stmt-for.go +0 -266
- package/compiler/stmt-range.go +0 -475
- package/compiler/stmt-select.go +0 -262
- package/compiler/stmt-type-switch.go +0 -147
- package/compiler/stmt.go +0 -1308
- package/compiler/type-assert.go +0 -386
- package/compiler/type-info.go +0 -156
- package/compiler/type-utils.go +0 -207
- package/compiler/type.go +0 -892
package/go.mod
CHANGED
|
@@ -6,17 +6,17 @@ toolchain go1.26.2
|
|
|
6
6
|
|
|
7
7
|
require (
|
|
8
8
|
github.com/aperturerobotics/cli v1.1.0
|
|
9
|
+
github.com/aperturerobotics/json-iterator-lite v1.0.1-0.20251104042408-0c9eb8a3f726
|
|
9
10
|
github.com/aperturerobotics/protobuf-go-lite v0.12.2
|
|
10
11
|
github.com/aperturerobotics/util v1.33.0
|
|
11
12
|
github.com/pkg/errors v0.9.1
|
|
12
13
|
github.com/sirupsen/logrus v1.9.5-0.20260309202648-9f0600962f75
|
|
13
|
-
golang.org/x/mod v0.34.0
|
|
14
14
|
golang.org/x/tools v0.43.0
|
|
15
15
|
)
|
|
16
16
|
|
|
17
17
|
require (
|
|
18
|
-
github.com/aperturerobotics/json-iterator-lite v1.0.1-0.20251104042408-0c9eb8a3f726 // indirect
|
|
19
18
|
github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect
|
|
19
|
+
golang.org/x/mod v0.34.0 // indirect
|
|
20
20
|
golang.org/x/sync v0.20.0 // indirect
|
|
21
21
|
golang.org/x/sys v0.42.0 // indirect
|
|
22
22
|
)
|
package/gs/builtin/builtin.ts
CHANGED
|
@@ -2,6 +2,15 @@ import type { Slice, SliceProxy } from './slice.js'
|
|
|
2
2
|
import { writeHostStdoutText } from './hostio.js'
|
|
3
3
|
import { formatPrintedArgs } from './print.js'
|
|
4
4
|
import { isSliceProxy } from './slice.js'
|
|
5
|
+
import { isVarRef, type VarRef } from './varRef.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Implementation of Go's built-in print function
|
|
9
|
+
* @param args Arguments to print
|
|
10
|
+
*/
|
|
11
|
+
export function print(...args: any[]): void {
|
|
12
|
+
writeHostStdoutText(args.length === 0 ? '' : formatPrintedArgs(args))
|
|
13
|
+
}
|
|
5
14
|
|
|
6
15
|
/**
|
|
7
16
|
* Implementation of Go's built-in println function
|
|
@@ -69,6 +78,24 @@ export function assignStruct<T>(target: T, source: T): void {
|
|
|
69
78
|
}
|
|
70
79
|
}
|
|
71
80
|
|
|
81
|
+
/**
|
|
82
|
+
* pointerValue unwraps a Go pointer value for generated field, method, and
|
|
83
|
+
* dereference access. Struct pointers may be represented directly as class
|
|
84
|
+
* instances or indirectly as VarRef values when the pointer came from taking a
|
|
85
|
+
* variable's address.
|
|
86
|
+
*/
|
|
87
|
+
export function pointerValue<T>(value: T | VarRef<T> | null | undefined): T {
|
|
88
|
+
if (value === null || value === undefined) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
'runtime error: invalid memory address or nil pointer dereference',
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
if (isVarRef(value)) {
|
|
94
|
+
return value.value as T
|
|
95
|
+
}
|
|
96
|
+
return value
|
|
97
|
+
}
|
|
98
|
+
|
|
72
99
|
// Bytes represents all valid []byte representations in TypeScript
|
|
73
100
|
// This includes Uint8Array (the preferred representation) and $.Slice<number> (which includes null)
|
|
74
101
|
export type Bytes = Uint8Array | Slice<number>
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
+
getHostRuntime,
|
|
5
|
+
HostRuntimeOwner,
|
|
6
|
+
type HostRuntime,
|
|
7
|
+
isMainScript,
|
|
4
8
|
resetHostRuntimeForTests,
|
|
5
9
|
writeHostStderrText,
|
|
6
10
|
writeHostStdoutText,
|
|
@@ -10,6 +14,8 @@ const originalDeno = (globalThis as any).Deno
|
|
|
10
14
|
const originalProcess = (globalThis as any).process
|
|
11
15
|
|
|
12
16
|
afterEach(() => {
|
|
17
|
+
vi.restoreAllMocks()
|
|
18
|
+
|
|
13
19
|
if (originalDeno === undefined) {
|
|
14
20
|
delete (globalThis as any).Deno
|
|
15
21
|
} else {
|
|
@@ -25,6 +31,40 @@ afterEach(() => {
|
|
|
25
31
|
resetHostRuntimeForTests()
|
|
26
32
|
})
|
|
27
33
|
|
|
34
|
+
function runtimeFixture(platform: string): HostRuntime {
|
|
35
|
+
return {
|
|
36
|
+
deno: null,
|
|
37
|
+
getEnv: () => '',
|
|
38
|
+
getStdioHandle: () => null,
|
|
39
|
+
nodeFS: null,
|
|
40
|
+
platform,
|
|
41
|
+
processObj: null,
|
|
42
|
+
readFD: () => null,
|
|
43
|
+
writeFD: () => 0,
|
|
44
|
+
writeStderrText: () => {},
|
|
45
|
+
writeStdoutText: () => {},
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
describe('hostio runtime owner', () => {
|
|
50
|
+
it('caches host capability detection until reset', () => {
|
|
51
|
+
let detects = 0
|
|
52
|
+
const owner = new HostRuntimeOwner(() => {
|
|
53
|
+
detects++
|
|
54
|
+
return runtimeFixture(`host-${detects}`)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
expect(owner.current().platform).toBe('host-1')
|
|
58
|
+
expect(owner.current().platform).toBe('host-1')
|
|
59
|
+
expect(detects).toBe(1)
|
|
60
|
+
|
|
61
|
+
owner.reset()
|
|
62
|
+
|
|
63
|
+
expect(owner.current().platform).toBe('host-2')
|
|
64
|
+
expect(detects).toBe(2)
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
|
|
28
68
|
describe('hostio text writes', () => {
|
|
29
69
|
it('uses sync node fs writes for stdout and stderr', () => {
|
|
30
70
|
const writes: Array<{ fd: number; bytes: number[] }> = []
|
|
@@ -66,4 +106,141 @@ describe('hostio text writes', () => {
|
|
|
66
106
|
expect((globalThis as any).process.stdout.write).not.toHaveBeenCalled()
|
|
67
107
|
expect((globalThis as any).process.stderr.write).not.toHaveBeenCalled()
|
|
68
108
|
})
|
|
109
|
+
|
|
110
|
+
it('falls back to node fs when Deno is present without sync stdio', () => {
|
|
111
|
+
const writes: Array<{ fd: number; bytes: number[] }> = []
|
|
112
|
+
const writeSync = vi.fn(
|
|
113
|
+
(
|
|
114
|
+
fd: number,
|
|
115
|
+
buffer: Uint8Array,
|
|
116
|
+
_offset?: number,
|
|
117
|
+
length?: number,
|
|
118
|
+
_position?: number | null,
|
|
119
|
+
) => {
|
|
120
|
+
writes.push({
|
|
121
|
+
bytes: Array.from(buffer.subarray(0, length ?? buffer.length)),
|
|
122
|
+
fd,
|
|
123
|
+
})
|
|
124
|
+
return length ?? buffer.length
|
|
125
|
+
},
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
;(globalThis as any).Deno = {
|
|
129
|
+
stderr: {},
|
|
130
|
+
stdout: {},
|
|
131
|
+
}
|
|
132
|
+
;(globalThis as any).process = {
|
|
133
|
+
getBuiltinModule: vi.fn(() => ({
|
|
134
|
+
readSync: vi.fn(),
|
|
135
|
+
writeSync,
|
|
136
|
+
})),
|
|
137
|
+
}
|
|
138
|
+
resetHostRuntimeForTests()
|
|
139
|
+
|
|
140
|
+
writeHostStdoutText('bun\n')
|
|
141
|
+
writeHostStderrText('err\n')
|
|
142
|
+
|
|
143
|
+
expect(writeSync).toHaveBeenCalledTimes(2)
|
|
144
|
+
expect(writes).toEqual([
|
|
145
|
+
{ bytes: [98, 117, 110, 10], fd: 1 },
|
|
146
|
+
{ bytes: [101, 114, 114, 10], fd: 2 },
|
|
147
|
+
])
|
|
148
|
+
expect(getHostRuntime().platform).toBe('unknown')
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it('prefers Deno sync stdio when it is available', () => {
|
|
152
|
+
const denoWrites: Array<{ bytes: number[]; stream: string }> = []
|
|
153
|
+
const nodeWriteSync = vi.fn()
|
|
154
|
+
const denoWriteSync = vi.fn((buffer: Uint8Array) => {
|
|
155
|
+
denoWrites.push({
|
|
156
|
+
bytes: Array.from(buffer),
|
|
157
|
+
stream: 'stdout',
|
|
158
|
+
})
|
|
159
|
+
return buffer.length
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
;(globalThis as any).Deno = {
|
|
163
|
+
build: { os: 'darwin' },
|
|
164
|
+
stdout: { writeSync: denoWriteSync },
|
|
165
|
+
}
|
|
166
|
+
;(globalThis as any).process = {
|
|
167
|
+
getBuiltinModule: vi.fn(() => ({
|
|
168
|
+
readSync: vi.fn(),
|
|
169
|
+
writeSync: nodeWriteSync,
|
|
170
|
+
})),
|
|
171
|
+
}
|
|
172
|
+
resetHostRuntimeForTests()
|
|
173
|
+
|
|
174
|
+
writeHostStdoutText('deno\n')
|
|
175
|
+
|
|
176
|
+
expect(denoWriteSync).toHaveBeenCalledTimes(1)
|
|
177
|
+
expect(nodeWriteSync).not.toHaveBeenCalled()
|
|
178
|
+
expect(denoWrites).toEqual([
|
|
179
|
+
{ bytes: [100, 101, 110, 111, 10], stream: 'stdout' },
|
|
180
|
+
])
|
|
181
|
+
expect(getHostRuntime().platform).toBe('darwin')
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
it('uses console fallback in browser-like hosts', () => {
|
|
185
|
+
const consoleLog = vi.spyOn(console, 'log').mockImplementation(() => {})
|
|
186
|
+
|
|
187
|
+
delete (globalThis as any).Deno
|
|
188
|
+
delete (globalThis as any).process
|
|
189
|
+
resetHostRuntimeForTests()
|
|
190
|
+
|
|
191
|
+
writeHostStdoutText('browser\n')
|
|
192
|
+
|
|
193
|
+
expect(getHostRuntime().platform).toBe('unknown')
|
|
194
|
+
expect(getHostRuntime().nodeFS).toBeNull()
|
|
195
|
+
expect(consoleLog).toHaveBeenCalledWith('browser')
|
|
196
|
+
})
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
describe('hostio isMainScript', () => {
|
|
200
|
+
it('returns true when the runtime marks the module as main', () => {
|
|
201
|
+
expect(
|
|
202
|
+
isMainScript({
|
|
203
|
+
main: true,
|
|
204
|
+
url: 'file:///tmp/example.gs.ts',
|
|
205
|
+
}),
|
|
206
|
+
).toBe(true)
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
it('matches process argv[1] against the module url', () => {
|
|
210
|
+
delete (globalThis as any).Deno
|
|
211
|
+
;(globalThis as any).process = {
|
|
212
|
+
argv: ['bun', './dist/app.gs.ts'],
|
|
213
|
+
cwd: vi.fn(() => '/tmp/project'),
|
|
214
|
+
getBuiltinModule: vi.fn(() => ({
|
|
215
|
+
readSync: vi.fn(),
|
|
216
|
+
writeSync: vi.fn(),
|
|
217
|
+
})),
|
|
218
|
+
}
|
|
219
|
+
resetHostRuntimeForTests()
|
|
220
|
+
|
|
221
|
+
expect(
|
|
222
|
+
isMainScript({
|
|
223
|
+
url: 'file:///tmp/project/dist/app.gs.ts',
|
|
224
|
+
}),
|
|
225
|
+
).toBe(true)
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
it('returns false when the module was imported instead of executed', () => {
|
|
229
|
+
delete (globalThis as any).Deno
|
|
230
|
+
;(globalThis as any).process = {
|
|
231
|
+
argv: ['bun', './runner.ts'],
|
|
232
|
+
cwd: vi.fn(() => '/tmp/project'),
|
|
233
|
+
getBuiltinModule: vi.fn(() => ({
|
|
234
|
+
readSync: vi.fn(),
|
|
235
|
+
writeSync: vi.fn(),
|
|
236
|
+
})),
|
|
237
|
+
}
|
|
238
|
+
resetHostRuntimeForTests()
|
|
239
|
+
|
|
240
|
+
expect(
|
|
241
|
+
isMainScript({
|
|
242
|
+
url: 'file:///tmp/project/dist/app.gs.ts',
|
|
243
|
+
}),
|
|
244
|
+
).toBe(false)
|
|
245
|
+
})
|
|
69
246
|
})
|
package/gs/builtin/hostio.ts
CHANGED
|
@@ -29,19 +29,29 @@ export type NodeFSModule = {
|
|
|
29
29
|
lchownSync?(path: string, uid: number, gid: number): void
|
|
30
30
|
linkSync?(existingPath: string, newPath: string): void
|
|
31
31
|
lstatSync?(path: string): any
|
|
32
|
-
mkdirSync?(
|
|
32
|
+
mkdirSync?(
|
|
33
|
+
path: string,
|
|
34
|
+
options?: number | { mode?: number; recursive?: boolean },
|
|
35
|
+
): void
|
|
33
36
|
readFileSync?(path: string): Uint8Array
|
|
34
37
|
readdirSync?(path: string, options?: { withFileTypes?: boolean }): any[]
|
|
35
38
|
readlinkSync?(path: string): string
|
|
36
39
|
renameSync?(oldPath: string, newPath: string): void
|
|
37
|
-
rmSync?(
|
|
40
|
+
rmSync?(
|
|
41
|
+
path: string,
|
|
42
|
+
options?: { force?: boolean; recursive?: boolean },
|
|
43
|
+
): void
|
|
38
44
|
rmdirSync?(path: string): void
|
|
39
45
|
statSync?(path: string): any
|
|
40
46
|
symlinkSync?(target: string, path: string): void
|
|
41
47
|
truncateSync?(path: string, len?: number): void
|
|
42
48
|
unlinkSync?(path: string): void
|
|
43
49
|
utimesSync?(path: string, atime: Date | number, mtime: Date | number): void
|
|
44
|
-
writeFileSync?(
|
|
50
|
+
writeFileSync?(
|
|
51
|
+
path: string,
|
|
52
|
+
data: Uint8Array,
|
|
53
|
+
options?: { mode?: number },
|
|
54
|
+
): void
|
|
45
55
|
}
|
|
46
56
|
|
|
47
57
|
export type DenoStream = {
|
|
@@ -75,6 +85,13 @@ export type HostRuntime = {
|
|
|
75
85
|
writeStdoutText: HostTextWrite
|
|
76
86
|
}
|
|
77
87
|
|
|
88
|
+
export type HostRuntimeDetector = () => HostRuntime
|
|
89
|
+
|
|
90
|
+
export type MainScriptMeta = {
|
|
91
|
+
url: string
|
|
92
|
+
main?: boolean
|
|
93
|
+
}
|
|
94
|
+
|
|
78
95
|
const encoder = new TextEncoder()
|
|
79
96
|
|
|
80
97
|
function getDynamicRequire(): ((specifier: string) => unknown) | null {
|
|
@@ -149,12 +166,66 @@ function detectNodeFS(processObj: any | null): NodeFSModule | null {
|
|
|
149
166
|
return null
|
|
150
167
|
}
|
|
151
168
|
|
|
152
|
-
function
|
|
153
|
-
|
|
169
|
+
function hasURLScheme(path: string): boolean {
|
|
170
|
+
return /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(path)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function isAbsoluteScriptPath(path: string): boolean {
|
|
174
|
+
return path.startsWith('/') || /^[A-Za-z]:[\\/]/.test(path)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function normalizePath(path: string): string {
|
|
178
|
+
return path.replace(/\\/g, '/')
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function absolutePathToFileURL(path: string, isDirectory: boolean): string {
|
|
182
|
+
const normalized = normalizePath(path)
|
|
183
|
+
const suffix = isDirectory && !normalized.endsWith('/') ? '/' : ''
|
|
184
|
+
if (/^[A-Za-z]:\//.test(normalized)) {
|
|
185
|
+
return new URL(`file:///${normalized}${suffix}`).href
|
|
186
|
+
}
|
|
187
|
+
return new URL(`file://${normalized}${suffix}`).href
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function getCurrentWorkingDirectory(): string | null {
|
|
191
|
+
const runtime = getHostRuntime()
|
|
192
|
+
try {
|
|
193
|
+
if (typeof runtime.processObj?.cwd === 'function') {
|
|
194
|
+
return runtime.processObj.cwd()
|
|
195
|
+
}
|
|
196
|
+
} catch {
|
|
197
|
+
// Fall through to Deno cwd.
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
try {
|
|
201
|
+
if (typeof runtime.deno?.cwd === 'function') {
|
|
202
|
+
return runtime.deno.cwd()
|
|
203
|
+
}
|
|
204
|
+
} catch {
|
|
205
|
+
// No cwd fallback available.
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return null
|
|
154
209
|
}
|
|
155
210
|
|
|
156
|
-
function
|
|
157
|
-
|
|
211
|
+
function fileURLFromScriptPath(path: string): string | null {
|
|
212
|
+
try {
|
|
213
|
+
if (hasURLScheme(path)) {
|
|
214
|
+
return new URL(path).href
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (isAbsoluteScriptPath(path)) {
|
|
218
|
+
return absolutePathToFileURL(path, false)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const cwd = getCurrentWorkingDirectory()
|
|
222
|
+
if (!cwd) {
|
|
223
|
+
return null
|
|
224
|
+
}
|
|
225
|
+
return new URL(normalizePath(path), absolutePathToFileURL(cwd, true)).href
|
|
226
|
+
} catch {
|
|
227
|
+
return null
|
|
228
|
+
}
|
|
158
229
|
}
|
|
159
230
|
|
|
160
231
|
function fallbackConsoleWriter(method: 'error' | 'log'): HostTextWrite {
|
|
@@ -193,10 +264,7 @@ function detectHostRuntime(): HostRuntime {
|
|
|
193
264
|
}
|
|
194
265
|
}
|
|
195
266
|
|
|
196
|
-
const platform =
|
|
197
|
-
deno?.build?.os ??
|
|
198
|
-
processObj?.platform ??
|
|
199
|
-
'unknown'
|
|
267
|
+
const platform = deno?.build?.os ?? processObj?.platform ?? 'unknown'
|
|
200
268
|
|
|
201
269
|
const getEnv = (name: string): string => {
|
|
202
270
|
if (deno?.env?.get) {
|
|
@@ -209,64 +277,67 @@ function detectHostRuntime(): HostRuntime {
|
|
|
209
277
|
return processObj?.env?.[name] ?? ''
|
|
210
278
|
}
|
|
211
279
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
readFD = (fd: number, buffer: Uint8Array): number | null => {
|
|
219
|
-
const handle = getStdioHandle(fd)
|
|
220
|
-
if (!handle || typeof handle.readSync !== 'function') {
|
|
221
|
-
throw new HostUnsupportedError()
|
|
222
|
-
}
|
|
280
|
+
const readFD: HostReadFD = (
|
|
281
|
+
fd: number,
|
|
282
|
+
buffer: Uint8Array,
|
|
283
|
+
): number | null => {
|
|
284
|
+
const handle = getStdioHandle(fd)
|
|
285
|
+
if (handle && typeof handle.readSync === 'function') {
|
|
223
286
|
return handle.readSync(buffer)
|
|
224
287
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
288
|
+
if (nodeFS) {
|
|
289
|
+
return nodeFS.readSync(fd, buffer, 0, buffer.length, null)
|
|
290
|
+
}
|
|
291
|
+
throw new HostUnsupportedError()
|
|
292
|
+
}
|
|
293
|
+
const writeFD: HostWriteFD = (fd: number, buffer: Uint8Array): number => {
|
|
294
|
+
const handle = getStdioHandle(fd)
|
|
295
|
+
if (handle && typeof handle.writeSync === 'function') {
|
|
230
296
|
return writeAllSync(
|
|
231
297
|
(chunk: Uint8Array) => handle.writeSync!(chunk),
|
|
232
298
|
buffer,
|
|
233
299
|
)
|
|
234
300
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if (!handle || typeof handle.writeSync !== 'function') {
|
|
238
|
-
fallbackConsoleWriter('log')(data)
|
|
239
|
-
return
|
|
240
|
-
}
|
|
241
|
-
writeAllText((chunk: Uint8Array) => handle.writeSync!(chunk), data)
|
|
242
|
-
}
|
|
243
|
-
writeStderrText = (data: string) => {
|
|
244
|
-
const handle = getStdioHandle(2)
|
|
245
|
-
if (!handle || typeof handle.writeSync !== 'function') {
|
|
246
|
-
fallbackConsoleWriter('error')(data)
|
|
247
|
-
return
|
|
248
|
-
}
|
|
249
|
-
writeAllText((chunk: Uint8Array) => handle.writeSync!(chunk), data)
|
|
250
|
-
}
|
|
251
|
-
} else if (nodeFS) {
|
|
252
|
-
readFD = (fd: number, buffer: Uint8Array): number | null =>
|
|
253
|
-
nodeFS.readSync(fd, buffer, 0, buffer.length, null)
|
|
254
|
-
writeFD = (fd: number, buffer: Uint8Array): number =>
|
|
255
|
-
writeAllSync(
|
|
301
|
+
if (nodeFS) {
|
|
302
|
+
return writeAllSync(
|
|
256
303
|
(chunk: Uint8Array) =>
|
|
257
304
|
nodeFS.writeSync(fd, chunk, 0, chunk.length, null),
|
|
258
305
|
buffer,
|
|
259
306
|
)
|
|
260
|
-
|
|
307
|
+
}
|
|
308
|
+
throw new HostUnsupportedError()
|
|
309
|
+
}
|
|
310
|
+
const writeStdoutText: HostTextWrite = (data: string) => {
|
|
311
|
+
const handle = getStdioHandle(1)
|
|
312
|
+
if (handle && typeof handle.writeSync === 'function') {
|
|
313
|
+
writeAllText((chunk: Uint8Array) => handle.writeSync!(chunk), data)
|
|
314
|
+
return
|
|
315
|
+
}
|
|
316
|
+
if (nodeFS) {
|
|
261
317
|
writeAllText(
|
|
262
|
-
(chunk: Uint8Array) =>
|
|
318
|
+
(chunk: Uint8Array) =>
|
|
319
|
+
nodeFS.writeSync(1, chunk, 0, chunk.length, null),
|
|
263
320
|
data,
|
|
264
321
|
)
|
|
265
|
-
|
|
322
|
+
return
|
|
323
|
+
}
|
|
324
|
+
fallbackConsoleWriter('log')(data)
|
|
325
|
+
}
|
|
326
|
+
const writeStderrText: HostTextWrite = (data: string) => {
|
|
327
|
+
const handle = getStdioHandle(2)
|
|
328
|
+
if (handle && typeof handle.writeSync === 'function') {
|
|
329
|
+
writeAllText((chunk: Uint8Array) => handle.writeSync!(chunk), data)
|
|
330
|
+
return
|
|
331
|
+
}
|
|
332
|
+
if (nodeFS) {
|
|
266
333
|
writeAllText(
|
|
267
|
-
(chunk: Uint8Array) =>
|
|
334
|
+
(chunk: Uint8Array) =>
|
|
335
|
+
nodeFS.writeSync(2, chunk, 0, chunk.length, null),
|
|
268
336
|
data,
|
|
269
337
|
)
|
|
338
|
+
return
|
|
339
|
+
}
|
|
340
|
+
fallbackConsoleWriter('error')(data)
|
|
270
341
|
}
|
|
271
342
|
|
|
272
343
|
return {
|
|
@@ -283,16 +354,60 @@ function detectHostRuntime(): HostRuntime {
|
|
|
283
354
|
}
|
|
284
355
|
}
|
|
285
356
|
|
|
286
|
-
export
|
|
357
|
+
export class HostRuntimeOwner {
|
|
358
|
+
private runtime: HostRuntime
|
|
359
|
+
|
|
360
|
+
constructor(
|
|
361
|
+
private readonly detector: HostRuntimeDetector = detectHostRuntime,
|
|
362
|
+
) {
|
|
363
|
+
this.runtime = detector()
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
current(): HostRuntime {
|
|
367
|
+
return this.runtime
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
reset(): void {
|
|
371
|
+
this.runtime = this.detector()
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
export const hostRuntimeOwner = new HostRuntimeOwner()
|
|
376
|
+
|
|
377
|
+
export function getHostRuntime(): HostRuntime {
|
|
378
|
+
return hostRuntimeOwner.current()
|
|
379
|
+
}
|
|
287
380
|
|
|
288
381
|
export function resetHostRuntimeForTests(): void {
|
|
289
|
-
|
|
382
|
+
hostRuntimeOwner.reset()
|
|
290
383
|
}
|
|
291
384
|
|
|
292
385
|
export function writeHostStdoutText(data: string): void {
|
|
293
|
-
|
|
386
|
+
getHostRuntime().writeStdoutText(data)
|
|
294
387
|
}
|
|
295
388
|
|
|
296
389
|
export function writeHostStderrText(data: string): void {
|
|
297
|
-
|
|
390
|
+
getHostRuntime().writeStderrText(data)
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export function isMainScript(meta: MainScriptMeta): boolean {
|
|
394
|
+
if (meta.main === true) {
|
|
395
|
+
return true
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const entryPath = getHostRuntime().processObj?.argv?.[1]
|
|
399
|
+
if (typeof entryPath !== 'string' || entryPath === '') {
|
|
400
|
+
return false
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const entryURL = fileURLFromScriptPath(entryPath)
|
|
404
|
+
if (!entryURL) {
|
|
405
|
+
return false
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
return new URL(meta.url).href === entryURL
|
|
410
|
+
} catch {
|
|
411
|
+
return meta.url === entryURL
|
|
412
|
+
}
|
|
298
413
|
}
|
package/gs/builtin/index.ts
CHANGED