@bash0816/claude-code 2.1.241 → 2.1.248

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.
@@ -0,0 +1,265 @@
1
+ 'use strict';
2
+
3
+ const test = require('node:test');
4
+ const assert = require('node:assert/strict');
5
+ const fs = require('node:fs');
6
+ const os = require('node:os');
7
+ const path = require('node:path');
8
+
9
+ const {
10
+ discoverModuleGraph,
11
+ extractToProcessOwnedDir,
12
+ cleanupStaleOwnedDirs,
13
+ prepareProcessOwnedDir,
14
+ readEntryContentPrefix,
15
+ } = require('./bunfs-extract.js');
16
+
17
+ const TRAILER = '\n---- Bun! ----\n';
18
+
19
+ // StandaloneModuleGraphの最小合成バイナリを構築する。
20
+ // レイアウト: [preamble padding][module contents][module table][Offsets(32byte)][trailer]
21
+ function buildSyntheticBinary({ modules, entryPointId, corruptTrailer = false, preamblePadding = 64 }) {
22
+ const nameBuffers = modules.map((m) => Buffer.from(m.name, 'utf8'));
23
+ const contentBuffers = modules.map((m) => Buffer.from(m.content ?? '', 'utf8'));
24
+
25
+ const dataParts = [];
26
+ const nameOffsets = [];
27
+ const contOffsets = [];
28
+ let cursor = 0;
29
+ for (let i = 0; i < modules.length; i += 1) {
30
+ nameOffsets.push(cursor);
31
+ dataParts.push(nameBuffers[i]);
32
+ cursor += nameBuffers[i].length;
33
+ }
34
+ for (let i = 0; i < modules.length; i += 1) {
35
+ contOffsets.push(cursor);
36
+ dataParts.push(contentBuffers[i]);
37
+ cursor += contentBuffers[i].length;
38
+ }
39
+ const byteCountBeforeTable = cursor;
40
+
41
+ const MODULE_TABLE_ENTRY_SIZE = 52;
42
+ const modTable = Buffer.alloc(MODULE_TABLE_ENTRY_SIZE * modules.length);
43
+ for (let i = 0; i < modules.length; i += 1) {
44
+ const base = i * MODULE_TABLE_ENTRY_SIZE;
45
+ modTable.writeUInt32LE(nameOffsets[i], base);
46
+ modTable.writeUInt32LE(nameBuffers[i].length, base + 4);
47
+ modTable.writeUInt32LE(contOffsets[i], base + 8);
48
+ modTable.writeUInt32LE(contentBuffers[i].length, base + 12);
49
+ modTable[base + 49] = modules[i].loader ?? 1; // 1 = js
50
+ }
51
+ const modulesOffset = byteCountBeforeTable;
52
+ const modulesLength = modTable.length;
53
+ const byteCount = byteCountBeforeTable + modulesLength;
54
+
55
+ const offsetsBuf = Buffer.alloc(32);
56
+ offsetsBuf.writeBigUInt64LE(BigInt(byteCount), 0);
57
+ offsetsBuf.writeUInt32LE(modulesOffset, 8);
58
+ offsetsBuf.writeUInt32LE(modulesLength, 12);
59
+ offsetsBuf.writeUInt32LE(entryPointId, 16);
60
+
61
+ const trailerBuf = Buffer.from(corruptTrailer ? '\n---- NOT BUN ----\n' : TRAILER, 'utf8');
62
+
63
+ return Buffer.concat([
64
+ Buffer.alloc(preamblePadding),
65
+ ...dataParts,
66
+ modTable,
67
+ offsetsBuf,
68
+ trailerBuf,
69
+ ]);
70
+ }
71
+
72
+ function writeTempBinary(buf) {
73
+ const file = path.join(os.tmpdir(), `bunfs-extract-test-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.bin`);
74
+ fs.writeFileSync(file, buf);
75
+ return file;
76
+ }
77
+
78
+ test('discoverModuleGraph parses a well-formed synthetic StandaloneModuleGraph', () => {
79
+ const buf = buildSyntheticBinary({
80
+ modules: [
81
+ { name: '/$bunfs/root/cli', content: 'console.log("entry")' },
82
+ { name: '/$bunfs/root/chunk-a.js', content: 'export const a = 1;' },
83
+ ],
84
+ entryPointId: 0,
85
+ });
86
+ const file = writeTempBinary(buf);
87
+ try {
88
+ const graph = discoverModuleGraph(file);
89
+ try {
90
+ assert.equal(graph.numModules, 2);
91
+ assert.equal(graph.entryName, '/$bunfs/root/cli');
92
+ assert.equal(graph.modules.length, 2);
93
+ const prefix = readEntryContentPrefix(graph.fd, graph.entryModule, 256).toString('utf8');
94
+ assert.equal(prefix, 'console.log("entry")');
95
+ } finally {
96
+ fs.closeSync(graph.fd);
97
+ }
98
+ } finally {
99
+ fs.rmSync(file, { force: true });
100
+ }
101
+ });
102
+
103
+ test('discoverModuleGraph rejects a binary with a corrupted trailer', () => {
104
+ const buf = buildSyntheticBinary({
105
+ modules: [{ name: '/$bunfs/root/cli', content: 'x' }],
106
+ entryPointId: 0,
107
+ corruptTrailer: true,
108
+ });
109
+ const file = writeTempBinary(buf);
110
+ try {
111
+ assert.throws(() => discoverModuleGraph(file), /trailer not found/);
112
+ } finally {
113
+ fs.rmSync(file, { force: true });
114
+ }
115
+ });
116
+
117
+ test('discoverModuleGraph rejects entry_point_id out of range', () => {
118
+ const buf = buildSyntheticBinary({
119
+ modules: [{ name: '/$bunfs/root/cli', content: 'x' }],
120
+ entryPointId: 5, // 存在しないインデックス
121
+ });
122
+ const file = writeTempBinary(buf);
123
+ try {
124
+ assert.throws(() => discoverModuleGraph(file), /entry_point_id.*out of range/);
125
+ } finally {
126
+ fs.rmSync(file, { force: true });
127
+ }
128
+ });
129
+
130
+ test('discoverModuleGraph rejects duplicate module names', () => {
131
+ const buf = buildSyntheticBinary({
132
+ modules: [
133
+ { name: '/$bunfs/root/cli', content: 'a' },
134
+ { name: '/$bunfs/root/cli', content: 'b' },
135
+ ],
136
+ entryPointId: 0,
137
+ });
138
+ const file = writeTempBinary(buf);
139
+ try {
140
+ assert.throws(() => discoverModuleGraph(file), /duplicate module name/);
141
+ } finally {
142
+ fs.rmSync(file, { force: true });
143
+ }
144
+ });
145
+
146
+ test('discoverModuleGraph skips NAPI loader modules from extraction list', () => {
147
+ const buf = buildSyntheticBinary({
148
+ modules: [
149
+ { name: '/$bunfs/root/cli', content: 'x' },
150
+ { name: '/$bunfs/root/native.node', content: 'BINARY', loader: 10 },
151
+ ],
152
+ entryPointId: 0,
153
+ });
154
+ const file = writeTempBinary(buf);
155
+ try {
156
+ const graph = discoverModuleGraph(file);
157
+ try {
158
+ assert.equal(graph.modules.length, 1);
159
+ assert.equal(graph.modules[0].name, '/$bunfs/root/cli');
160
+ } finally {
161
+ fs.closeSync(graph.fd);
162
+ }
163
+ } finally {
164
+ fs.rmSync(file, { force: true });
165
+ }
166
+ });
167
+
168
+ test('extractToProcessOwnedDir rejects path traversal via module name', () => {
169
+ const buf = buildSyntheticBinary({
170
+ modules: [{ name: '/$bunfs/root/../../etc/passwd', content: 'evil' }],
171
+ entryPointId: 0,
172
+ });
173
+ const file = writeTempBinary(buf);
174
+ const ownedDir = path.join(os.tmpdir(), `bunfs-extract-owned-${process.pid}-${Date.now()}`);
175
+ try {
176
+ assert.throws(() => extractToProcessOwnedDir(file, ownedDir), /rejected unsafe module name|escapes owned dir/);
177
+ } finally {
178
+ fs.rmSync(file, { force: true });
179
+ fs.rmSync(ownedDir, { recursive: true, force: true });
180
+ }
181
+ });
182
+
183
+ test('extractToProcessOwnedDir writes module contents to the owned directory', () => {
184
+ const buf = buildSyntheticBinary({
185
+ modules: [
186
+ { name: '/$bunfs/root/cli', content: 'entry-content' },
187
+ { name: '/$bunfs/root/chunk-a.js', content: 'chunk-content' },
188
+ ],
189
+ entryPointId: 0,
190
+ });
191
+ const file = writeTempBinary(buf);
192
+ const ownedDir = path.join(os.tmpdir(), `bunfs-extract-owned-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
193
+ try {
194
+ const { entryRelPath } = extractToProcessOwnedDir(file, ownedDir);
195
+ assert.equal(entryRelPath, 'cli');
196
+ assert.equal(fs.readFileSync(path.join(ownedDir, 'cli'), 'utf8'), 'entry-content');
197
+ assert.equal(fs.readFileSync(path.join(ownedDir, 'chunk-a.js'), 'utf8'), 'chunk-content');
198
+ } finally {
199
+ fs.rmSync(file, { force: true });
200
+ fs.rmSync(ownedDir, { recursive: true, force: true });
201
+ }
202
+ });
203
+
204
+ test('cleanupStaleOwnedDirs keeps directories whose PID is still alive', () => {
205
+ const workdir = path.join(os.tmpdir(), `bunfs-cleanup-test-${process.pid}-${Date.now()}`);
206
+ fs.mkdirSync(workdir, { recursive: true });
207
+ const aliveDir = path.join(workdir, `esm.${process.pid}.old.marker.bare-dir`);
208
+ fs.mkdirSync(aliveDir);
209
+ const oldTime = new Date(Date.now() - 48 * 60 * 60 * 1000);
210
+ fs.utimesSync(aliveDir, oldTime, oldTime);
211
+ try {
212
+ cleanupStaleOwnedDirs(workdir, 'esm.');
213
+ assert.ok(fs.existsSync(aliveDir), 'directory owned by a live PID must not be removed even if old');
214
+ } finally {
215
+ fs.rmSync(workdir, { recursive: true, force: true });
216
+ }
217
+ });
218
+
219
+ test('cleanupStaleOwnedDirs removes old directories whose PID is dead', () => {
220
+ const workdir = path.join(os.tmpdir(), `bunfs-cleanup-test-${process.pid}-${Date.now()}-dead`);
221
+ fs.mkdirSync(workdir, { recursive: true });
222
+ // 実在しない可能性が極めて高い巨大なPID番号を使う
223
+ const deadDir = path.join(workdir, `esm.999999999.old.marker.bare-dir`);
224
+ fs.mkdirSync(deadDir);
225
+ const oldTime = new Date(Date.now() - 48 * 60 * 60 * 1000);
226
+ fs.utimesSync(deadDir, oldTime, oldTime);
227
+ try {
228
+ cleanupStaleOwnedDirs(workdir, 'esm.');
229
+ assert.ok(!fs.existsSync(deadDir), 'stale directory owned by a dead PID should be removed');
230
+ } finally {
231
+ fs.rmSync(workdir, { recursive: true, force: true });
232
+ }
233
+ });
234
+
235
+ test('cleanupStaleOwnedDirs keeps recently modified directories regardless of PID', () => {
236
+ const workdir = path.join(os.tmpdir(), `bunfs-cleanup-test-${process.pid}-${Date.now()}-recent`);
237
+ fs.mkdirSync(workdir, { recursive: true });
238
+ const recentDir = path.join(workdir, `esm.999999998.recent.marker.bare-dir`);
239
+ fs.mkdirSync(recentDir);
240
+ try {
241
+ cleanupStaleOwnedDirs(workdir, 'esm.');
242
+ assert.ok(fs.existsSync(recentDir), 'recently created directory must not be removed regardless of PID liveness');
243
+ } finally {
244
+ fs.rmSync(workdir, { recursive: true, force: true });
245
+ }
246
+ });
247
+
248
+ test('prepareProcessOwnedDir extracts into a unique directory and returns entry path', () => {
249
+ const buf = buildSyntheticBinary({
250
+ modules: [{ name: '/$bunfs/root/cli', content: 'hello' }],
251
+ entryPointId: 0,
252
+ });
253
+ const file = writeTempBinary(buf);
254
+ const workdir = path.join(os.tmpdir(), `bunfs-prepare-test-${process.pid}-${Date.now()}`);
255
+ fs.mkdirSync(workdir, { recursive: true });
256
+ try {
257
+ const { ownedDir, entryRelPath } = prepareProcessOwnedDir(file, workdir);
258
+ assert.ok(ownedDir.startsWith(workdir));
259
+ assert.equal(entryRelPath, 'cli');
260
+ assert.equal(fs.readFileSync(path.join(ownedDir, 'cli'), 'utf8'), 'hello');
261
+ } finally {
262
+ fs.rmSync(file, { force: true });
263
+ fs.rmSync(workdir, { recursive: true, force: true });
264
+ }
265
+ });
@@ -0,0 +1,116 @@
1
+ import { createRequire } from 'node:module';
2
+
3
+ const require = createRequire(import.meta.url);
4
+ const realVm = require('node:vm');
5
+
6
+ function injectBunIntoContext(context) {
7
+ if (!context || typeof context !== 'object') return context;
8
+ try {
9
+ if (!Object.prototype.hasOwnProperty.call(context, '__claudeYaml')) {
10
+ Object.defineProperty(context, '__claudeYaml', {
11
+ value: globalThis.__claudeYaml,
12
+ configurable: true,
13
+ writable: true,
14
+ });
15
+ }
16
+ if (!Object.prototype.hasOwnProperty.call(context, '__claudeBunShim')) {
17
+ Object.defineProperty(context, '__claudeBunShim', {
18
+ value: globalThis.__claudeBunShim,
19
+ configurable: true,
20
+ writable: true,
21
+ });
22
+ }
23
+ if (!Object.prototype.hasOwnProperty.call(context, '__claudeBun')) {
24
+ Object.defineProperty(context, '__claudeBun', {
25
+ value: globalThis.__claudeBunShim,
26
+ configurable: true,
27
+ writable: true,
28
+ });
29
+ }
30
+ if (Object.prototype.hasOwnProperty.call(context, 'Bun')) {
31
+ if (context.Bun && typeof context.Bun === 'object' && context.Bun !== globalThis.Bun) {
32
+ try {
33
+ context.Bun = globalThis.Bun;
34
+ } catch {
35
+ Object.defineProperty(context, 'Bun', {
36
+ value: globalThis.Bun,
37
+ configurable: true,
38
+ writable: true,
39
+ });
40
+ }
41
+ }
42
+ if (!context.Bun || typeof context.Bun !== 'object') {
43
+ Object.defineProperty(context, 'Bun', {
44
+ value: globalThis.Bun,
45
+ configurable: true,
46
+ writable: true,
47
+ });
48
+ }
49
+ } else {
50
+ Object.defineProperty(context, 'Bun', {
51
+ value: globalThis.Bun,
52
+ configurable: true,
53
+ writable: true,
54
+ });
55
+ }
56
+ if (context.Bun && globalThis.__claudeYaml) {
57
+ context.Bun.YAML = globalThis.__claudeYaml;
58
+ }
59
+ } catch {}
60
+ return context;
61
+ }
62
+
63
+ if (!realVm.__claudeBunShimPatched) {
64
+ const originalCreateContext = realVm.createContext.bind(realVm);
65
+ const originalRunInNewContext = realVm.runInNewContext.bind(realVm);
66
+ const originalRunInContext = realVm.runInContext.bind(realVm);
67
+ const originalRunInThisContext = realVm.runInThisContext && realVm.runInThisContext.bind(realVm);
68
+ const scriptProto = realVm.Script && realVm.Script.prototype;
69
+
70
+ realVm.createContext = (contextObject, ...rest) =>
71
+ originalCreateContext(injectBunIntoContext(contextObject), ...rest);
72
+ realVm.runInNewContext = (code, contextObject, ...rest) =>
73
+ originalRunInNewContext(code, injectBunIntoContext(contextObject), ...rest);
74
+ realVm.runInContext = (code, contextObject, ...rest) =>
75
+ originalRunInContext(code, injectBunIntoContext(contextObject), ...rest);
76
+ if (originalRunInThisContext) {
77
+ realVm.runInThisContext = (code, ...rest) => originalRunInThisContext(code, ...rest);
78
+ }
79
+
80
+ if (scriptProto && !scriptProto.__claudeBunShimPatched) {
81
+ const originalScriptRunInContext = scriptProto.runInContext;
82
+ const originalScriptRunInNewContext = scriptProto.runInNewContext;
83
+ const originalScriptRunInThisContext = scriptProto.runInThisContext;
84
+
85
+ scriptProto.runInContext = function (contextObject, ...rest) {
86
+ return originalScriptRunInContext.call(this, injectBunIntoContext(contextObject), ...rest);
87
+ };
88
+ scriptProto.runInNewContext = function (contextObject, ...rest) {
89
+ return originalScriptRunInNewContext.call(this, injectBunIntoContext(contextObject), ...rest);
90
+ };
91
+ if (originalScriptRunInThisContext) {
92
+ scriptProto.runInThisContext = function (...rest) {
93
+ return originalScriptRunInThisContext.call(this, ...rest);
94
+ };
95
+ }
96
+
97
+ Object.defineProperty(scriptProto, '__claudeBunShimPatched', { value: true });
98
+ }
99
+
100
+ Object.defineProperty(realVm, '__claudeBunShimPatched', { value: true });
101
+ }
102
+
103
+ export const createContext = realVm.createContext;
104
+ export const isContext = realVm.isContext;
105
+ export const runInContext = realVm.runInContext;
106
+ export const runInNewContext = realVm.runInNewContext;
107
+ export const runInThisContext = realVm.runInThisContext;
108
+ export const createScript = realVm.createScript;
109
+ export const compileFunction = realVm.compileFunction;
110
+ export const measureMemory = realVm.measureMemory;
111
+ export const Script = realVm.Script;
112
+ export const SourceTextModule = realVm.SourceTextModule;
113
+ export const SyntheticModule = realVm.SyntheticModule;
114
+ export const constants = realVm.constants;
115
+
116
+ export default realVm;
@@ -0,0 +1,142 @@
1
+ 'use strict';
2
+
3
+ const test = require('node:test');
4
+ const assert = require('node:assert/strict');
5
+
6
+ test('bunfs-vm-guard exports all vm module methods', async () => {
7
+ const vmGuard = await import('./bunfs-vm-guard.mjs');
8
+
9
+ assert.equal(typeof vmGuard.createContext, 'function');
10
+ assert.equal(typeof vmGuard.isContext, 'function');
11
+ assert.equal(typeof vmGuard.runInContext, 'function');
12
+ assert.equal(typeof vmGuard.runInNewContext, 'function');
13
+ assert.equal(typeof vmGuard.runInThisContext, 'function');
14
+ assert.equal(typeof vmGuard.createScript, 'function');
15
+ assert.equal(typeof vmGuard.compileFunction, 'function');
16
+ assert.equal(typeof vmGuard.measureMemory, 'function');
17
+ assert.equal(typeof vmGuard.Script, 'function');
18
+ // SourceTextModule and SyntheticModule only exist with --experimental-vm-modules flag
19
+ assert.ok('SourceTextModule' in vmGuard);
20
+ assert.ok('SyntheticModule' in vmGuard);
21
+ assert.ok(vmGuard.constants);
22
+ });
23
+
24
+ test('bunfs-vm-guard provides default export with vm module API', async () => {
25
+ const vmGuard = await import('./bunfs-vm-guard.mjs');
26
+ const defaultExport = vmGuard.default;
27
+
28
+ assert.ok(defaultExport);
29
+ assert.equal(typeof defaultExport, 'object');
30
+ assert.equal(typeof defaultExport.createContext, 'function');
31
+ assert.equal(typeof defaultExport.isContext, 'function');
32
+ assert.equal(typeof defaultExport.runInContext, 'function');
33
+ assert.equal(typeof defaultExport.runInNewContext, 'function');
34
+ assert.equal(typeof defaultExport.runInThisContext, 'function');
35
+ assert.equal(typeof defaultExport.createScript, 'function');
36
+ assert.equal(typeof defaultExport.compileFunction, 'function');
37
+ assert.equal(typeof defaultExport.measureMemory, 'function');
38
+ assert.equal(typeof defaultExport.Script, 'function');
39
+ // SourceTextModule and SyntheticModule may not exist in default export without --experimental-vm-modules
40
+ // They are exported as named exports if they exist
41
+ assert.ok(defaultExport.constants);
42
+ });
43
+
44
+ test('bunfs-vm-guard injects Bun into context in createContext', async () => {
45
+ globalThis.Bun = { __dummy: true };
46
+ try {
47
+ const vmGuard = await import('./bunfs-vm-guard.mjs');
48
+
49
+ const context = vmGuard.createContext({});
50
+ // Check that Bun property exists in context
51
+ assert.ok(Object.prototype.hasOwnProperty.call(context, 'Bun'));
52
+
53
+ // Verify Bun is defined when we run code in context
54
+ const result = vmGuard.runInContext('typeof Bun', context);
55
+ assert.equal(result, 'object');
56
+ } finally {
57
+ delete globalThis.Bun;
58
+ }
59
+ });
60
+
61
+ test('bunfs-vm-guard injects Bun into context in runInNewContext', async () => {
62
+ globalThis.Bun = { __dummy: true };
63
+ try {
64
+ const vmGuard = await import('./bunfs-vm-guard.mjs');
65
+
66
+ const code = 'typeof Bun';
67
+ const result = vmGuard.runInNewContext(code, {});
68
+ assert.equal(result, 'object');
69
+ } finally {
70
+ delete globalThis.Bun;
71
+ }
72
+ });
73
+
74
+ test('bunfs-vm-guard injects __claudeYaml into context', async () => {
75
+ const vmGuard = await import('./bunfs-vm-guard.mjs');
76
+
77
+ const context = vmGuard.createContext({});
78
+ // Check that __claudeYaml property exists
79
+ assert.ok(Object.prototype.hasOwnProperty.call(context, '__claudeYaml'));
80
+ });
81
+
82
+ test('bunfs-vm-guard injects __claudeBun and __claudeBunShim into context', async () => {
83
+ const vmGuard = await import('./bunfs-vm-guard.mjs');
84
+
85
+ const context = vmGuard.createContext({});
86
+ // Check that shim properties exist
87
+ assert.ok(Object.prototype.hasOwnProperty.call(context, '__claudeBun'));
88
+ assert.ok(Object.prototype.hasOwnProperty.call(context, '__claudeBunShim'));
89
+ });
90
+
91
+ test('bunfs-vm-guard Script class works with context injection', async () => {
92
+ globalThis.Bun = { __dummy: true };
93
+ try {
94
+ const vmGuard = await import('./bunfs-vm-guard.mjs');
95
+
96
+ const code = 'typeof Bun';
97
+ const script = new vmGuard.Script(code);
98
+ const context = vmGuard.createContext({});
99
+ const result = script.runInContext(context);
100
+ assert.equal(result, 'object');
101
+ } finally {
102
+ delete globalThis.Bun;
103
+ }
104
+ });
105
+
106
+ test('bunfs-vm-guard handles context with existing Bun property', async () => {
107
+ globalThis.Bun = { __dummy: true };
108
+ try {
109
+ const vmGuard = await import('./bunfs-vm-guard.mjs');
110
+
111
+ // Create context with pre-existing Bun property
112
+ const context = vmGuard.createContext({ Bun: { custom: true } });
113
+ // The guard should have replaced/overwritten it with globalThis.Bun
114
+ const result = vmGuard.runInContext('typeof Bun', context);
115
+ assert.equal(result, 'object');
116
+ } finally {
117
+ delete globalThis.Bun;
118
+ }
119
+ });
120
+
121
+ test('bunfs-vm-guard does not break normal vm functionality', async () => {
122
+ const vmGuard = await import('./bunfs-vm-guard.mjs');
123
+
124
+ // Test that normal code execution still works
125
+ const code = '2 + 2';
126
+ const result = vmGuard.runInNewContext(code);
127
+ assert.equal(result, 4);
128
+ });
129
+
130
+ test('bunfs-vm-guard Script.runInNewContext works with injections', async () => {
131
+ globalThis.Bun = { __dummy: true };
132
+ try {
133
+ const vmGuard = await import('./bunfs-vm-guard.mjs');
134
+
135
+ const code = 'typeof Bun';
136
+ const script = new vmGuard.Script(code);
137
+ const result = script.runInNewContext({});
138
+ assert.equal(result, 'object');
139
+ } finally {
140
+ delete globalThis.Bun;
141
+ }
142
+ });
@@ -0,0 +1,11 @@
1
+ class WS {
2
+ on() {}
3
+ once() {}
4
+ addEventListener() {}
5
+ close() {}
6
+ send() {}
7
+ ping() {}
8
+ }
9
+
10
+ export default WS;
11
+ export { WS as WebSocket };
@@ -0,0 +1,91 @@
1
+ function parseScalar(value) {
2
+ const text = String(value ?? '').trim();
3
+ if (text === '') return '';
4
+ if (text === 'true') return true;
5
+ if (text === 'false') return false;
6
+ if (text === 'null' || text === '~') return null;
7
+ if (/^-?(?:0|[1-9]\d*)(?:\.\d+)?$/.test(text)) return Number(text);
8
+ if (
9
+ (text.startsWith('"') && text.endsWith('"')) ||
10
+ (text.startsWith("'") && text.endsWith("'"))
11
+ ) {
12
+ return text.slice(1, -1);
13
+ }
14
+ return text;
15
+ }
16
+
17
+ function parseInlineArray(value) {
18
+ const inner = String(value ?? '').trim().slice(1, -1).trim();
19
+ if (inner === '') return [];
20
+ const items = [];
21
+ let current = '';
22
+ let quote = null;
23
+
24
+ for (let i = 0; i < inner.length; i += 1) {
25
+ const ch = inner[i];
26
+ if (quote) {
27
+ if (ch === quote && inner[i - 1] !== '\\') quote = null;
28
+ current += ch;
29
+ continue;
30
+ }
31
+ if (ch === '"' || ch === "'") {
32
+ quote = ch;
33
+ current += ch;
34
+ continue;
35
+ }
36
+ if (ch === ',') {
37
+ items.push(parseScalar(current));
38
+ current = '';
39
+ continue;
40
+ }
41
+ current += ch;
42
+ }
43
+
44
+ if (current !== '') items.push(parseScalar(current));
45
+ return items;
46
+ }
47
+
48
+ export function yamlParse(text) {
49
+ const source = String(text ?? '');
50
+ const result = {};
51
+ for (const rawLine of source.split(/\r?\n/)) {
52
+ const line = rawLine.trim();
53
+ if (!line || line.startsWith('#')) continue;
54
+ const idx = line.indexOf(':');
55
+ if (idx < 0) continue;
56
+ const key = line.slice(0, idx).trim();
57
+ const rawValue = line.slice(idx + 1).trim();
58
+ if (!key) continue;
59
+ result[key] = rawValue.startsWith('[') && rawValue.endsWith(']')
60
+ ? parseInlineArray(rawValue)
61
+ : parseScalar(rawValue);
62
+ }
63
+ return result;
64
+ }
65
+
66
+ export function yamlStringify(value) {
67
+ if (!value || typeof value !== 'object') return String(value ?? '');
68
+ const lines = [];
69
+ for (const [key, raw] of Object.entries(value)) {
70
+ if (Array.isArray(raw)) {
71
+ lines.push(`${key}: [${raw.map(item => JSON.stringify(String(item))).join(', ')}]`);
72
+ } else if (raw === null) {
73
+ lines.push(`${key}: null`);
74
+ } else if (typeof raw === 'string') {
75
+ lines.push(`${key}: ${JSON.stringify(raw)}`);
76
+ } else {
77
+ lines.push(`${key}: ${String(raw)}`);
78
+ }
79
+ }
80
+ return lines.join('\n');
81
+ }
82
+
83
+ export function createYamlShim() {
84
+ const yaml = {
85
+ parse: yamlParse,
86
+ stringify: yamlStringify,
87
+ };
88
+ yaml.YAML = yaml;
89
+ yaml.default = yaml;
90
+ return yaml;
91
+ }