zuzu-js 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.
Files changed (167) hide show
  1. package/LICENSE +5 -0
  2. package/README.md +113 -0
  3. package/bin/zuzu +17 -0
  4. package/bin/zuzu-build-browser-bundle +57 -0
  5. package/bin/zuzu-generate-browser-stdlib +584 -0
  6. package/bin/zuzu-js +23 -0
  7. package/bin/zuzu-js-compile +152 -0
  8. package/bin/zuzu-js-electron +19 -0
  9. package/dist/zuzu-browser-worker.js +45574 -0
  10. package/dist/zuzu-browser.js +45362 -0
  11. package/lib/browser-bundle-entry.js +160 -0
  12. package/lib/browser-gui-renderer.js +387 -0
  13. package/lib/browser-runtime.js +167 -0
  14. package/lib/browser-worker-entry.js +413 -0
  15. package/lib/browser-ztests/runner.html +103 -0
  16. package/lib/browser-ztests/runner.js +369 -0
  17. package/lib/cli.js +350 -0
  18. package/lib/collections.js +367 -0
  19. package/lib/compiler.js +303 -0
  20. package/lib/electron/launcher.js +70 -0
  21. package/lib/electron/main.js +956 -0
  22. package/lib/electron/preload.js +80 -0
  23. package/lib/electron/renderer.html +122 -0
  24. package/lib/electron/renderer.js +24 -0
  25. package/lib/execution-metadata.js +18 -0
  26. package/lib/gui/dom-renderer.js +778 -0
  27. package/lib/host/browser-host.js +278 -0
  28. package/lib/host/capabilities.js +47 -0
  29. package/lib/host/electron-host.js +15 -0
  30. package/lib/host/node-host.js +74 -0
  31. package/lib/paths.js +150 -0
  32. package/lib/runtime-entrypoints.js +60 -0
  33. package/lib/runtime-helpers.js +886 -0
  34. package/lib/runtime.js +3529 -0
  35. package/lib/tap.js +37 -0
  36. package/lib/transpiler-new/ast.js +23 -0
  37. package/lib/transpiler-new/codegen.js +2455 -0
  38. package/lib/transpiler-new/errors.js +28 -0
  39. package/lib/transpiler-new/index.js +26 -0
  40. package/lib/transpiler-new/lexer.js +834 -0
  41. package/lib/transpiler-new/parser.js +2332 -0
  42. package/lib/transpiler-new/validate-bindings.js +326 -0
  43. package/lib/transpiler-utils.js +95 -0
  44. package/lib/transpiler.js +33 -0
  45. package/lib/zuzu.js +53 -0
  46. package/modules/javascript.js +193 -0
  47. package/modules/std/archive.js +603 -0
  48. package/modules/std/clib.js +338 -0
  49. package/modules/std/data/csv.js +1331 -0
  50. package/modules/std/data/json.js +531 -0
  51. package/modules/std/data/xml.js +441 -0
  52. package/modules/std/data/yaml.js +256 -0
  53. package/modules/std/db-worker.js +250 -0
  54. package/modules/std/db.js +664 -0
  55. package/modules/std/digest/_hash.js +443 -0
  56. package/modules/std/digest/md5.js +26 -0
  57. package/modules/std/digest/sha.js +72 -0
  58. package/modules/std/eval.js +10 -0
  59. package/modules/std/gui/objects.js +1519 -0
  60. package/modules/std/internals.js +571 -0
  61. package/modules/std/io/socks-worker.js +318 -0
  62. package/modules/std/io/socks.js +186 -0
  63. package/modules/std/io.js +475 -0
  64. package/modules/std/marshal/cbor.js +463 -0
  65. package/modules/std/marshal/graph.js +1624 -0
  66. package/modules/std/marshal.js +87 -0
  67. package/modules/std/math/bignum.js +91 -0
  68. package/modules/std/math.js +79 -0
  69. package/modules/std/net/dns.js +306 -0
  70. package/modules/std/net/http.js +820 -0
  71. package/modules/std/net/smtp.js +943 -0
  72. package/modules/std/net/url.js +109 -0
  73. package/modules/std/proc.js +602 -0
  74. package/modules/std/secure.js +3724 -0
  75. package/modules/std/string/base64.js +138 -0
  76. package/modules/std/string.js +299 -0
  77. package/modules/std/task.js +914 -0
  78. package/modules/std/time.js +579 -0
  79. package/modules/std/tui.js +188 -0
  80. package/modules/std/worker-thread.js +246 -0
  81. package/modules/std/worker.js +790 -0
  82. package/package.json +67 -0
  83. package/stdlib/modules/javascript.zzm +99 -0
  84. package/stdlib/modules/perl.zzm +105 -0
  85. package/stdlib/modules/std/archive.zzm +132 -0
  86. package/stdlib/modules/std/cache/lru.zzm +174 -0
  87. package/stdlib/modules/std/clib.zzm +112 -0
  88. package/stdlib/modules/std/colour.zzm +220 -0
  89. package/stdlib/modules/std/config.zzm +818 -0
  90. package/stdlib/modules/std/data/cbor.zzm +497 -0
  91. package/stdlib/modules/std/data/csv.zzm +285 -0
  92. package/stdlib/modules/std/data/ini.zzm +472 -0
  93. package/stdlib/modules/std/data/json/schema/core.zzm +573 -0
  94. package/stdlib/modules/std/data/json/schema/format.zzm +581 -0
  95. package/stdlib/modules/std/data/json/schema/model.zzm +255 -0
  96. package/stdlib/modules/std/data/json/schema/output.zzm +272 -0
  97. package/stdlib/modules/std/data/json/schema/relative_pointer.zzm +299 -0
  98. package/stdlib/modules/std/data/json/schema/validation.zzm +1503 -0
  99. package/stdlib/modules/std/data/json/schema.zzm +306 -0
  100. package/stdlib/modules/std/data/json.zzm +102 -0
  101. package/stdlib/modules/std/data/kdl/json.zzm +460 -0
  102. package/stdlib/modules/std/data/kdl/xml.zzm +387 -0
  103. package/stdlib/modules/std/data/kdl.zzm +1631 -0
  104. package/stdlib/modules/std/data/toml.zzm +756 -0
  105. package/stdlib/modules/std/data/toon.zzm +1017 -0
  106. package/stdlib/modules/std/data/xml/escape.zzm +156 -0
  107. package/stdlib/modules/std/data/xml.zzm +276 -0
  108. package/stdlib/modules/std/data/yaml.zzm +94 -0
  109. package/stdlib/modules/std/db.zzm +173 -0
  110. package/stdlib/modules/std/defer.zzm +75 -0
  111. package/stdlib/modules/std/digest/crc32.zzm +196 -0
  112. package/stdlib/modules/std/digest/md5.zzm +54 -0
  113. package/stdlib/modules/std/digest/sha.zzm +83 -0
  114. package/stdlib/modules/std/dump.zzm +317 -0
  115. package/stdlib/modules/std/eval.zzm +63 -0
  116. package/stdlib/modules/std/getopt.zzm +432 -0
  117. package/stdlib/modules/std/gui/dialogue.zzm +592 -0
  118. package/stdlib/modules/std/gui/objects.zzm +123 -0
  119. package/stdlib/modules/std/gui.zzm +1914 -0
  120. package/stdlib/modules/std/internals.zzm +139 -0
  121. package/stdlib/modules/std/io/socks.zzm +139 -0
  122. package/stdlib/modules/std/io.zzm +157 -0
  123. package/stdlib/modules/std/lingua/en.zzm +347 -0
  124. package/stdlib/modules/std/log.zzm +169 -0
  125. package/stdlib/modules/std/mail.zzm +2726 -0
  126. package/stdlib/modules/std/marshal.zzm +138 -0
  127. package/stdlib/modules/std/math/bignum.zzm +98 -0
  128. package/stdlib/modules/std/math/range.zzm +116 -0
  129. package/stdlib/modules/std/math/roman.zzm +156 -0
  130. package/stdlib/modules/std/math.zzm +141 -0
  131. package/stdlib/modules/std/net/dns.zzm +93 -0
  132. package/stdlib/modules/std/net/http.zzm +278 -0
  133. package/stdlib/modules/std/net/smtp.zzm +257 -0
  134. package/stdlib/modules/std/net/url.zzm +69 -0
  135. package/stdlib/modules/std/path/jsonpointer.zzm +526 -0
  136. package/stdlib/modules/std/path/kdl.zzm +1003 -0
  137. package/stdlib/modules/std/path/simple.zzm +520 -0
  138. package/stdlib/modules/std/path/z/context.zzm +147 -0
  139. package/stdlib/modules/std/path/z/evaluate.zzm +549 -0
  140. package/stdlib/modules/std/path/z/functions.zzm +874 -0
  141. package/stdlib/modules/std/path/z/lexer.zzm +490 -0
  142. package/stdlib/modules/std/path/z/node.zzm +1455 -0
  143. package/stdlib/modules/std/path/z/operators.zzm +445 -0
  144. package/stdlib/modules/std/path/z/parser.zzm +359 -0
  145. package/stdlib/modules/std/path/z.zzm +403 -0
  146. package/stdlib/modules/std/path/zz/functions.zzm +828 -0
  147. package/stdlib/modules/std/path/zz/operators.zzm +1036 -0
  148. package/stdlib/modules/std/path/zz.zzm +100 -0
  149. package/stdlib/modules/std/proc.zzm +155 -0
  150. package/stdlib/modules/std/result.zzm +149 -0
  151. package/stdlib/modules/std/secure.zzm +606 -0
  152. package/stdlib/modules/std/string/base64.zzm +66 -0
  153. package/stdlib/modules/std/string/quoted_printable.zzm +485 -0
  154. package/stdlib/modules/std/string.zzm +179 -0
  155. package/stdlib/modules/std/task.zzm +221 -0
  156. package/stdlib/modules/std/template/z.zzm +531 -0
  157. package/stdlib/modules/std/template/zz.zzm +62 -0
  158. package/stdlib/modules/std/time.zzm +188 -0
  159. package/stdlib/modules/std/tui.zzm +89 -0
  160. package/stdlib/modules/std/uuid.zzm +223 -0
  161. package/stdlib/modules/std/web/session.zzm +388 -0
  162. package/stdlib/modules/std/web/static.zzm +329 -0
  163. package/stdlib/modules/std/web.zzm +1942 -0
  164. package/stdlib/modules/std/worker.zzm +202 -0
  165. package/stdlib/modules/std/zuzuzoo.zzm +3960 -0
  166. package/stdlib/modules/test/more.zzm +528 -0
  167. package/stdlib/modules/test/parser.zzm +209 -0
@@ -0,0 +1,109 @@
1
+ 'use strict';
2
+
3
+ function _str( value, fallback = '' ) {
4
+ if ( value == null ) {
5
+ return fallback;
6
+ }
7
+ return String( value );
8
+ }
9
+
10
+
11
+ function _dict( source = {} ) {
12
+ const out = { ...source };
13
+ Object.defineProperties( out, {
14
+ has: {
15
+ value( key ) {
16
+ return Object.prototype.hasOwnProperty.call( out, String( key ) ) ? 1 : 0;
17
+ },
18
+ enumerable: false,
19
+ },
20
+ exists: {
21
+ value( key ) {
22
+ return out.has( key );
23
+ },
24
+ enumerable: false,
25
+ },
26
+ get: {
27
+ value( key, fallback = null ) {
28
+ return out.has( key ) ? out[String( key )] : fallback;
29
+ },
30
+ enumerable: false,
31
+ },
32
+ } );
33
+ return out;
34
+ }
35
+
36
+ function escape( value ) {
37
+ return encodeURIComponent( _str( value ) );
38
+ }
39
+
40
+ function unescape( value ) {
41
+ return decodeURIComponent( _str( value ) );
42
+ }
43
+
44
+ function parse( value ) {
45
+ const urlText = _str( value );
46
+ const parsed = new URL( urlText, 'http://localhost' );
47
+ const out = _dict( {
48
+ url: parsed.href,
49
+ scheme: parsed.protocol.replace( /:$/u, '' ) || null,
50
+ authority: parsed.host || null,
51
+ userinfo: null,
52
+ host: parsed.hostname || null,
53
+ port: parsed.port || null,
54
+ path: parsed.pathname || '',
55
+ query: parsed.search.replace( /^\?/u, '' ) || null,
56
+ fragment: parsed.hash.replace( /^#/u, '' ) || null,
57
+ query_params: _dict( {} ),
58
+ } );
59
+ if ( parsed.username || parsed.password ) {
60
+ out.userinfo = parsed.username;
61
+ if ( parsed.password ) {
62
+ out.userinfo += `:${parsed.password}`;
63
+ }
64
+ }
65
+ for ( const [ key, item ] of parsed.searchParams.entries() ) {
66
+ out.query_params[key] = item;
67
+ }
68
+ return out;
69
+ }
70
+
71
+ function _templateVar( values, name ) {
72
+ if ( values[name] == null ) {
73
+ return '';
74
+ }
75
+ return encodeURIComponent( _str( values[name] ) );
76
+ }
77
+
78
+ function _templateQuery( values, namesText ) {
79
+ const names = String( namesText )
80
+ .split( /\s*,\s*/u )
81
+ .filter( Boolean );
82
+ const parts = [];
83
+ for ( const name of names ) {
84
+ if ( values[name] == null ) {
85
+ continue;
86
+ }
87
+ const key = encodeURIComponent( name );
88
+ const val = encodeURIComponent( _str( values[name] ) );
89
+ parts.push( `${key}=${val}` );
90
+ }
91
+ return parts.length > 0 ? `?${parts.join( '&' )}` : '';
92
+ }
93
+
94
+ function fill_template( template, values ) {
95
+ const source = _str( template );
96
+ const data = values && typeof values === 'object' && !Array.isArray( values )
97
+ ? values
98
+ : {};
99
+ return source
100
+ .replace( /\{\?([^}]+)\}/gu, ( _, names ) => _templateQuery( data, names ) )
101
+ .replace( /\{([a-zA-Z_][a-zA-Z0-9_]*)\}/gu, ( _, name ) => _templateVar( data, name ) );
102
+ }
103
+
104
+ module.exports = {
105
+ escape,
106
+ unescape,
107
+ parse,
108
+ fill_template,
109
+ };
@@ -0,0 +1,602 @@
1
+ 'use strict';
2
+
3
+ const { spawn, spawnSync } = require( 'node:child_process' );
4
+ const fs = require( 'node:fs' );
5
+ const path = require( 'node:path' );
6
+ const { Task, traceBlockingOperation } = require( './task' );
7
+
8
+ const signalCallbacks = new Map();
9
+ const installedSignals = new Set();
10
+
11
+ function normalizeSignalName( value ) {
12
+ return String( value ?? '' )
13
+ .trim()
14
+ .replace( /^SIG/iu, '' )
15
+ .toUpperCase();
16
+ }
17
+
18
+ function isPlainObject( value ) {
19
+ return value != null && typeof value === 'object' && !Array.isArray( value );
20
+ }
21
+
22
+ function toCommandArray( command, argv ) {
23
+ if ( Array.isArray( command ) ) {
24
+ return command.map( (item) => String( item ?? '' ) );
25
+ }
26
+ const args = Array.isArray( argv )
27
+ ? argv.map( (item) => String( item ?? '' ) )
28
+ : [];
29
+ return [ String( command ?? '' ), ...args ];
30
+ }
31
+
32
+ function normalizeCommandForCwd( cmd ) {
33
+ const out = cmd.slice();
34
+ if (
35
+ out.length > 0
36
+ && !path.isAbsolute( out[0] )
37
+ && /[\\/]/u.test( out[0] )
38
+ ) {
39
+ out[0] = path.resolve( out[0] );
40
+ }
41
+ return out;
42
+ }
43
+
44
+ function resultOk( result ) {
45
+ if ( !isPlainObject( result ) ) {
46
+ return 0;
47
+ }
48
+ if ( result.error != null && result.error !== '' ) {
49
+ return 0;
50
+ }
51
+ if ( Number( result.signal || 0 ) !== 0 ) {
52
+ return 0;
53
+ }
54
+ if ( Number( result.exit_code || 0 ) !== 0 ) {
55
+ return 0;
56
+ }
57
+ return 1;
58
+ }
59
+
60
+ function cwdErrorResult( cmd, options, message ) {
61
+ const captureStdout = Object.prototype.hasOwnProperty.call( options, 'capture_stdout' )
62
+ ? Boolean( options.capture_stdout )
63
+ : true;
64
+ const captureStderr = Object.prototype.hasOwnProperty.call( options, 'capture_stderr' )
65
+ ? Boolean( options.capture_stderr )
66
+ : true;
67
+ return {
68
+ command: cmd.slice(),
69
+ exit_code: 0,
70
+ signal: 0,
71
+ core_dump: 0,
72
+ ok: 0,
73
+ stdout: captureStdout ? '' : null,
74
+ stderr: captureStderr ? '' : null,
75
+ error: message,
76
+ timed_out: 0,
77
+ };
78
+ }
79
+
80
+ function normalizeCwd( options ) {
81
+ if ( !Object.prototype.hasOwnProperty.call( options, 'cwd' ) ) {
82
+ return { cwd: null };
83
+ }
84
+ const cwd = String( options.cwd ?? '' );
85
+ if ( cwd === '' ) {
86
+ return { cwd: null };
87
+ }
88
+ let stat;
89
+ try {
90
+ stat = fs.statSync( cwd );
91
+ }
92
+ catch ( err ) {
93
+ return {
94
+ error: `cwd does not exist: ${cwd}`,
95
+ };
96
+ }
97
+ if ( !stat.isDirectory() ) {
98
+ return {
99
+ error: `cwd is not a directory: ${cwd}`,
100
+ };
101
+ }
102
+ return { cwd };
103
+ }
104
+
105
+ function statusText( result ) {
106
+ if ( !isPlainObject( result ) ) {
107
+ return 'invalid result';
108
+ }
109
+ if ( result.error != null && result.error !== '' ) {
110
+ return `error: ${result.error}`;
111
+ }
112
+ if ( Number( result.signal || 0 ) !== 0 ) {
113
+ return `signal ${result.signal}`;
114
+ }
115
+ return `exit ${Number( result.exit_code || 0 )}`;
116
+ }
117
+
118
+ function runCommand( cmd, options = {} ) {
119
+ cmd = normalizeCommandForCwd( cmd );
120
+ const stdin = Object.prototype.hasOwnProperty.call( options, 'stdin' )
121
+ ? String( options.stdin ?? '' )
122
+ : '';
123
+ const captureStdout = Object.prototype.hasOwnProperty.call( options, 'capture_stdout' )
124
+ ? Boolean( options.capture_stdout )
125
+ : true;
126
+ const captureStderr = Object.prototype.hasOwnProperty.call( options, 'capture_stderr' )
127
+ ? Boolean( options.capture_stderr )
128
+ : true;
129
+ const mergeStderr = Boolean( options.merge_stderr );
130
+ const timeoutSeconds = Number( options.timeout || 0 );
131
+ const envOverrides = isPlainObject( options.env ) ? options.env : null;
132
+ const cwd = normalizeCwd( options );
133
+ if ( cwd.error ) {
134
+ return cwdErrorResult( cmd, options, cwd.error );
135
+ }
136
+
137
+ const spawnOptions = {
138
+ input: stdin,
139
+ encoding: 'utf8',
140
+ maxBuffer: 10 * 1024 * 1024,
141
+ stdio: [
142
+ 'pipe',
143
+ captureStdout ? 'pipe' : 'ignore',
144
+ mergeStderr ? 'pipe' : ( captureStderr ? 'pipe' : 'ignore' ),
145
+ ],
146
+ };
147
+
148
+ if ( timeoutSeconds > 0 ) {
149
+ spawnOptions.timeout = Math.floor( timeoutSeconds * 1000 );
150
+ spawnOptions.killSignal = 'SIGALRM';
151
+ }
152
+
153
+ if ( cwd.cwd != null ) {
154
+ spawnOptions.cwd = cwd.cwd;
155
+ }
156
+
157
+ if ( envOverrides ) {
158
+ spawnOptions.env = { ...process.env };
159
+ for ( const [ key, value ] of Object.entries( envOverrides ) ) {
160
+ if ( value == null ) {
161
+ delete spawnOptions.env[key];
162
+ }
163
+ else {
164
+ spawnOptions.env[key] = String( value );
165
+ }
166
+ }
167
+ }
168
+
169
+ const spawned = spawnSync( cmd[0], cmd.slice( 1 ), spawnOptions );
170
+ const timedOut = spawned.error && spawned.error.code === 'ETIMEDOUT';
171
+ const signal = timedOut
172
+ ? 14
173
+ : ( spawned.signal ? normalizeSignalName( spawned.signal ) : 0 );
174
+ const result = {
175
+ command: cmd.slice(),
176
+ exit_code: Number.isInteger( spawned.status ) ? spawned.status : 0,
177
+ signal,
178
+ core_dump: 0,
179
+ ok: 0,
180
+ stdout: captureStdout ? String( spawned.stdout ?? '' ) : null,
181
+ stderr: mergeStderr
182
+ ? ( captureStderr ? String( spawned.stdout ?? '' ) : null )
183
+ : ( captureStderr ? String( spawned.stderr ?? '' ) : null ),
184
+ error: null,
185
+ timed_out: timedOut ? 1 : 0,
186
+ };
187
+
188
+ if ( timedOut ) {
189
+ result.error = `timeout after ${timeoutSeconds}s`;
190
+ }
191
+ else if ( spawned.error && !Number.isInteger( spawned.status ) ) {
192
+ result.error = spawned.error.message || String( spawned.error );
193
+ }
194
+
195
+ result.ok = resultOk( result );
196
+ return result;
197
+ }
198
+
199
+ function runCommandAsync( cmd, options = {} ) {
200
+ cmd = normalizeCommandForCwd( cmd );
201
+ let child = null;
202
+ let timeoutTimer = null;
203
+ let timedOut = false;
204
+ const task = new Task( null, {
205
+ status: 'running',
206
+ name: 'proc.run_async',
207
+ cancel() {
208
+ if ( timeoutTimer != null ) {
209
+ clearTimeout( timeoutTimer );
210
+ timeoutTimer = null;
211
+ }
212
+ if ( child && !child.killed ) {
213
+ try {
214
+ child.kill( 'SIGTERM' );
215
+ }
216
+ catch ( _err ) {
217
+ }
218
+ }
219
+ },
220
+ } );
221
+ const stdin = Object.prototype.hasOwnProperty.call( options, 'stdin' )
222
+ ? String( options.stdin ?? '' )
223
+ : '';
224
+ const captureStdout = Object.prototype.hasOwnProperty.call( options, 'capture_stdout' )
225
+ ? Boolean( options.capture_stdout )
226
+ : true;
227
+ const captureStderr = Object.prototype.hasOwnProperty.call( options, 'capture_stderr' )
228
+ ? Boolean( options.capture_stderr )
229
+ : true;
230
+ const mergeStderr = Boolean( options.merge_stderr );
231
+ const timeoutSeconds = Number( options.timeout || 0 );
232
+ const envOverrides = isPlainObject( options.env ) ? options.env : null;
233
+ const cwd = normalizeCwd( options );
234
+ if ( cwd.error ) {
235
+ task._resolve( cwdErrorResult( cmd, options, cwd.error ) );
236
+ return task;
237
+ }
238
+ const spawnOptions = {
239
+ stdio: [
240
+ 'pipe',
241
+ captureStdout ? 'pipe' : 'ignore',
242
+ mergeStderr ? 'pipe' : ( captureStderr ? 'pipe' : 'ignore' ),
243
+ ],
244
+ };
245
+ if ( envOverrides ) {
246
+ spawnOptions.env = { ...process.env };
247
+ for ( const [ key, value ] of Object.entries( envOverrides ) ) {
248
+ if ( value == null ) {
249
+ delete spawnOptions.env[key];
250
+ }
251
+ else {
252
+ spawnOptions.env[key] = String( value );
253
+ }
254
+ }
255
+ }
256
+ if ( cwd.cwd != null ) {
257
+ spawnOptions.cwd = cwd.cwd;
258
+ }
259
+ let stdout = '';
260
+ let stderr = '';
261
+ let error = null;
262
+ try {
263
+ child = spawn( cmd[0], cmd.slice( 1 ), spawnOptions );
264
+ }
265
+ catch ( err ) {
266
+ task._resolve( {
267
+ command: cmd.slice(),
268
+ exit_code: 0,
269
+ signal: 0,
270
+ core_dump: 0,
271
+ ok: 0,
272
+ stdout: captureStdout ? '' : null,
273
+ stderr: captureStderr ? '' : null,
274
+ error: err.message || String( err ),
275
+ timed_out: 0,
276
+ } );
277
+ return task;
278
+ }
279
+ if ( timeoutSeconds > 0 ) {
280
+ timeoutTimer = setTimeout( () => {
281
+ timedOut = true;
282
+ error = `timeout after ${timeoutSeconds}s`;
283
+ if ( child && !child.killed ) {
284
+ try {
285
+ child.kill( 'SIGALRM' );
286
+ }
287
+ catch ( _err ) {
288
+ try {
289
+ child.kill( 'SIGTERM' );
290
+ }
291
+ catch ( _err2 ) {
292
+ }
293
+ }
294
+ }
295
+ }, Math.floor( timeoutSeconds * 1000 ) );
296
+ }
297
+ if ( child.stdout ) {
298
+ child.stdout.setEncoding( 'utf8' );
299
+ child.stdout.on( 'data', (chunk) => { stdout += chunk; } );
300
+ }
301
+ if ( child.stderr ) {
302
+ child.stderr.setEncoding( 'utf8' );
303
+ child.stderr.on( 'data', (chunk) => { stderr += chunk; } );
304
+ }
305
+ child.on( 'error', (err) => {
306
+ error = err.message || String( err );
307
+ } );
308
+ if ( child.stdin ) {
309
+ child.stdin.on( 'error', (err) => {
310
+ if ( err && err.code !== 'EPIPE' ) {
311
+ error = err.message || String( err );
312
+ }
313
+ } );
314
+ child.stdin.end( stdin );
315
+ }
316
+ child.on( 'close', (code, signalName) => {
317
+ if ( timeoutTimer != null ) {
318
+ clearTimeout( timeoutTimer );
319
+ timeoutTimer = null;
320
+ }
321
+ const signal = timedOut
322
+ ? 14
323
+ : ( signalName ? normalizeSignalName( signalName ) : 0 );
324
+ const result = {
325
+ command: cmd.slice(),
326
+ exit_code: Number.isInteger( code ) ? code : 0,
327
+ signal,
328
+ core_dump: 0,
329
+ ok: 0,
330
+ stdout: captureStdout ? stdout : null,
331
+ stderr: mergeStderr
332
+ ? ( captureStderr ? stdout : null )
333
+ : ( captureStderr ? stderr : null ),
334
+ error,
335
+ timed_out: timedOut ? 1 : 0,
336
+ };
337
+ result.ok = resultOk( result );
338
+ task._resolve( result );
339
+ } );
340
+ return task;
341
+ }
342
+
343
+ function installSignalHandler( signal ) {
344
+ if ( installedSignals.has( signal ) ) {
345
+ return;
346
+ }
347
+ process.on( `SIG${signal}`, () => {
348
+ const callbacks = signalCallbacks.get( signal ) || [];
349
+ for ( const callback of callbacks ) {
350
+ try {
351
+ callback();
352
+ }
353
+ catch ( _err ) {
354
+ }
355
+ }
356
+ } );
357
+ installedSignals.add( signal );
358
+ }
359
+
360
+ function dispatchSignalCallbacks( signal ) {
361
+ const callbacks = signalCallbacks.get( signal ) || [];
362
+ for ( const callback of callbacks ) {
363
+ try {
364
+ callback();
365
+ }
366
+ catch ( _err ) {
367
+ }
368
+ }
369
+ }
370
+
371
+ class Env {
372
+ static get( name, defaultValue = null ) {
373
+ const key = String( name ?? '' );
374
+ return Object.prototype.hasOwnProperty.call( process.env, key )
375
+ ? process.env[key]
376
+ : defaultValue;
377
+ }
378
+
379
+ static set( name, value ) {
380
+ const key = String( name ?? '' );
381
+ process.env[key] = String( value ?? '' );
382
+ return process.env[key];
383
+ }
384
+
385
+ static remove( name ) {
386
+ delete process.env[String( name ?? '' )];
387
+ return null;
388
+ }
389
+ }
390
+
391
+ class Proc {
392
+ static pid() {
393
+ return process.pid;
394
+ }
395
+
396
+ static exit( code = 0 ) {
397
+ process.exit( Number( code ) || 0 );
398
+ }
399
+
400
+ static run( command, argv = [], options = {} ) {
401
+ traceBlockingOperation( 'std/proc Proc.run' );
402
+ return runCommand(
403
+ toCommandArray( command, argv ),
404
+ isPlainObject( options ) ? options : {},
405
+ );
406
+ }
407
+
408
+ static run_async( command, argv = [], options = {} ) {
409
+ return runCommandAsync(
410
+ toCommandArray( command, argv ),
411
+ isPlainObject( options ) ? options : {},
412
+ );
413
+ }
414
+
415
+ static pipeline( commands, options = {} ) {
416
+ traceBlockingOperation( 'std/proc Proc.pipeline' );
417
+ const items = Array.isArray( commands ) ? commands : [];
418
+ const opts = isPlainObject( options ) ? { ...options } : {};
419
+ const steps = [];
420
+ let stdin = Object.prototype.hasOwnProperty.call( opts, 'stdin' )
421
+ ? String( opts.stdin ?? '' )
422
+ : '';
423
+
424
+ for ( const command of items ) {
425
+ const stepOptions = {
426
+ ...opts,
427
+ stdin,
428
+ capture_stdout: true,
429
+ };
430
+ const result = runCommand(
431
+ toCommandArray( command, [] ),
432
+ stepOptions,
433
+ );
434
+ steps.push( result );
435
+ stdin = result.stdout ?? '';
436
+ if ( !result.ok ) {
437
+ break;
438
+ }
439
+ }
440
+
441
+ const last = steps.length > 0
442
+ ? steps[steps.length - 1]
443
+ : {
444
+ command: [],
445
+ exit_code: 0,
446
+ signal: 0,
447
+ core_dump: 0,
448
+ ok: 1,
449
+ stdout: '',
450
+ stderr: '',
451
+ error: null,
452
+ timed_out: 0,
453
+ };
454
+
455
+ return {
456
+ ok: last.ok,
457
+ stdout: last.stdout,
458
+ stderr: last.stderr,
459
+ error: last.error,
460
+ exit_code: last.exit_code,
461
+ signal: last.signal,
462
+ core_dump: last.core_dump,
463
+ timed_out: last.timed_out,
464
+ steps,
465
+ };
466
+ }
467
+
468
+ static pipeline_async( commands, options = {} ) {
469
+ return new Task( async () => {
470
+ const items = Array.isArray( commands ) ? commands : [];
471
+ const opts = isPlainObject( options ) ? { ...options } : {};
472
+ const steps = [];
473
+ let stdin = Object.prototype.hasOwnProperty.call( opts, 'stdin' )
474
+ ? String( opts.stdin ?? '' )
475
+ : '';
476
+ for ( const command of items ) {
477
+ const result = await runCommandAsync(
478
+ toCommandArray( command, [] ),
479
+ {
480
+ ...opts,
481
+ stdin,
482
+ capture_stdout: true,
483
+ },
484
+ );
485
+ steps.push( result );
486
+ stdin = result.stdout ?? '';
487
+ if ( !result.ok ) {
488
+ break;
489
+ }
490
+ }
491
+ const last = steps.length > 0
492
+ ? steps[steps.length - 1]
493
+ : {
494
+ command: [],
495
+ exit_code: 0,
496
+ signal: 0,
497
+ core_dump: 0,
498
+ ok: 1,
499
+ stdout: '',
500
+ stderr: '',
501
+ error: null,
502
+ timed_out: 0,
503
+ };
504
+ return {
505
+ ok: last.ok,
506
+ stdout: last.stdout,
507
+ stderr: last.stderr,
508
+ error: last.error,
509
+ exit_code: last.exit_code,
510
+ signal: last.signal,
511
+ core_dump: last.core_dump,
512
+ timed_out: last.timed_out,
513
+ steps,
514
+ };
515
+ }, { name: 'proc.pipeline_async' } );
516
+ }
517
+
518
+ static is_success( result ) {
519
+ return resultOk( result );
520
+ }
521
+
522
+ static status_text( result ) {
523
+ return statusText( result );
524
+ }
525
+
526
+ static kill( signalName, pid = null ) {
527
+ const signal = normalizeSignalName( signalName );
528
+ const target = pid == null ? process.pid : Number( pid );
529
+ if ( target === process.pid && signalCallbacks.has( signal ) ) {
530
+ dispatchSignalCallbacks( signal );
531
+ return 1;
532
+ }
533
+ process.kill( target, `SIG${signal}` );
534
+ return 1;
535
+ }
536
+
537
+ static onsignal( signalName, callback ) {
538
+ const signal = normalizeSignalName( signalName );
539
+ if ( !signalCallbacks.has( signal ) ) {
540
+ signalCallbacks.set( signal, [] );
541
+ }
542
+ signalCallbacks.get( signal ).push( callback );
543
+ installSignalHandler( signal );
544
+ return signalCallbacks.get( signal ).length;
545
+ }
546
+ }
547
+
548
+ function sleep( seconds = 0 ) {
549
+ traceBlockingOperation( 'std/proc sleep' );
550
+ const durationMs = Math.max( 0, Number( seconds ) || 0 ) * 1000;
551
+ if ( durationMs <= 0 ) {
552
+ return null;
553
+ }
554
+
555
+ if ( typeof SharedArrayBuffer === 'function' && typeof Atomics.wait === 'function' ) {
556
+ const buffer = new SharedArrayBuffer( Int32Array.BYTES_PER_ELEMENT );
557
+ const view = new Int32Array( buffer );
558
+ Atomics.wait( view, 0, 0, durationMs );
559
+ return null;
560
+ }
561
+
562
+ const deadline = Date.now() + durationMs;
563
+ while ( Date.now() < deadline ) {
564
+ }
565
+ return null;
566
+ }
567
+
568
+ function sleep_async( seconds = 0 ) {
569
+ let timer = null;
570
+ const readyAt = Date.now() + Math.max( 0, Number( seconds ) || 0 ) * 1000;
571
+ const task = new Task( null, {
572
+ status: 'sleeping',
573
+ name: 'proc.sleep_async',
574
+ poll() {
575
+ if ( Date.now() >= readyAt ) {
576
+ if ( timer != null ) {
577
+ clearTimeout( timer );
578
+ timer = null;
579
+ }
580
+ task._resolve( null );
581
+ }
582
+ },
583
+ cancel() {
584
+ if ( timer != null ) {
585
+ clearTimeout( timer );
586
+ timer = null;
587
+ }
588
+ },
589
+ } );
590
+ timer = setTimeout( () => {
591
+ timer = null;
592
+ task._resolve( null );
593
+ }, Math.max( 0, Number( seconds ) || 0 ) * 1000 );
594
+ return task;
595
+ }
596
+
597
+ module.exports = {
598
+ Proc,
599
+ Env,
600
+ sleep,
601
+ sleep_async,
602
+ };