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.
- package/LICENSE +5 -0
- package/README.md +113 -0
- package/bin/zuzu +17 -0
- package/bin/zuzu-build-browser-bundle +57 -0
- package/bin/zuzu-generate-browser-stdlib +584 -0
- package/bin/zuzu-js +23 -0
- package/bin/zuzu-js-compile +152 -0
- package/bin/zuzu-js-electron +19 -0
- package/dist/zuzu-browser-worker.js +45574 -0
- package/dist/zuzu-browser.js +45362 -0
- package/lib/browser-bundle-entry.js +160 -0
- package/lib/browser-gui-renderer.js +387 -0
- package/lib/browser-runtime.js +167 -0
- package/lib/browser-worker-entry.js +413 -0
- package/lib/browser-ztests/runner.html +103 -0
- package/lib/browser-ztests/runner.js +369 -0
- package/lib/cli.js +350 -0
- package/lib/collections.js +367 -0
- package/lib/compiler.js +303 -0
- package/lib/electron/launcher.js +70 -0
- package/lib/electron/main.js +956 -0
- package/lib/electron/preload.js +80 -0
- package/lib/electron/renderer.html +122 -0
- package/lib/electron/renderer.js +24 -0
- package/lib/execution-metadata.js +18 -0
- package/lib/gui/dom-renderer.js +778 -0
- package/lib/host/browser-host.js +278 -0
- package/lib/host/capabilities.js +47 -0
- package/lib/host/electron-host.js +15 -0
- package/lib/host/node-host.js +74 -0
- package/lib/paths.js +150 -0
- package/lib/runtime-entrypoints.js +60 -0
- package/lib/runtime-helpers.js +886 -0
- package/lib/runtime.js +3529 -0
- package/lib/tap.js +37 -0
- package/lib/transpiler-new/ast.js +23 -0
- package/lib/transpiler-new/codegen.js +2455 -0
- package/lib/transpiler-new/errors.js +28 -0
- package/lib/transpiler-new/index.js +26 -0
- package/lib/transpiler-new/lexer.js +834 -0
- package/lib/transpiler-new/parser.js +2332 -0
- package/lib/transpiler-new/validate-bindings.js +326 -0
- package/lib/transpiler-utils.js +95 -0
- package/lib/transpiler.js +33 -0
- package/lib/zuzu.js +53 -0
- package/modules/javascript.js +193 -0
- package/modules/std/archive.js +603 -0
- package/modules/std/clib.js +338 -0
- package/modules/std/data/csv.js +1331 -0
- package/modules/std/data/json.js +531 -0
- package/modules/std/data/xml.js +441 -0
- package/modules/std/data/yaml.js +256 -0
- package/modules/std/db-worker.js +250 -0
- package/modules/std/db.js +664 -0
- package/modules/std/digest/_hash.js +443 -0
- package/modules/std/digest/md5.js +26 -0
- package/modules/std/digest/sha.js +72 -0
- package/modules/std/eval.js +10 -0
- package/modules/std/gui/objects.js +1519 -0
- package/modules/std/internals.js +571 -0
- package/modules/std/io/socks-worker.js +318 -0
- package/modules/std/io/socks.js +186 -0
- package/modules/std/io.js +475 -0
- package/modules/std/marshal/cbor.js +463 -0
- package/modules/std/marshal/graph.js +1624 -0
- package/modules/std/marshal.js +87 -0
- package/modules/std/math/bignum.js +91 -0
- package/modules/std/math.js +79 -0
- package/modules/std/net/dns.js +306 -0
- package/modules/std/net/http.js +820 -0
- package/modules/std/net/smtp.js +943 -0
- package/modules/std/net/url.js +109 -0
- package/modules/std/proc.js +602 -0
- package/modules/std/secure.js +3724 -0
- package/modules/std/string/base64.js +138 -0
- package/modules/std/string.js +299 -0
- package/modules/std/task.js +914 -0
- package/modules/std/time.js +579 -0
- package/modules/std/tui.js +188 -0
- package/modules/std/worker-thread.js +246 -0
- package/modules/std/worker.js +790 -0
- package/package.json +67 -0
- package/stdlib/modules/javascript.zzm +99 -0
- package/stdlib/modules/perl.zzm +105 -0
- package/stdlib/modules/std/archive.zzm +132 -0
- package/stdlib/modules/std/cache/lru.zzm +174 -0
- package/stdlib/modules/std/clib.zzm +112 -0
- package/stdlib/modules/std/colour.zzm +220 -0
- package/stdlib/modules/std/config.zzm +818 -0
- package/stdlib/modules/std/data/cbor.zzm +497 -0
- package/stdlib/modules/std/data/csv.zzm +285 -0
- package/stdlib/modules/std/data/ini.zzm +472 -0
- package/stdlib/modules/std/data/json/schema/core.zzm +573 -0
- package/stdlib/modules/std/data/json/schema/format.zzm +581 -0
- package/stdlib/modules/std/data/json/schema/model.zzm +255 -0
- package/stdlib/modules/std/data/json/schema/output.zzm +272 -0
- package/stdlib/modules/std/data/json/schema/relative_pointer.zzm +299 -0
- package/stdlib/modules/std/data/json/schema/validation.zzm +1503 -0
- package/stdlib/modules/std/data/json/schema.zzm +306 -0
- package/stdlib/modules/std/data/json.zzm +102 -0
- package/stdlib/modules/std/data/kdl/json.zzm +460 -0
- package/stdlib/modules/std/data/kdl/xml.zzm +387 -0
- package/stdlib/modules/std/data/kdl.zzm +1631 -0
- package/stdlib/modules/std/data/toml.zzm +756 -0
- package/stdlib/modules/std/data/toon.zzm +1017 -0
- package/stdlib/modules/std/data/xml/escape.zzm +156 -0
- package/stdlib/modules/std/data/xml.zzm +276 -0
- package/stdlib/modules/std/data/yaml.zzm +94 -0
- package/stdlib/modules/std/db.zzm +173 -0
- package/stdlib/modules/std/defer.zzm +75 -0
- package/stdlib/modules/std/digest/crc32.zzm +196 -0
- package/stdlib/modules/std/digest/md5.zzm +54 -0
- package/stdlib/modules/std/digest/sha.zzm +83 -0
- package/stdlib/modules/std/dump.zzm +317 -0
- package/stdlib/modules/std/eval.zzm +63 -0
- package/stdlib/modules/std/getopt.zzm +432 -0
- package/stdlib/modules/std/gui/dialogue.zzm +592 -0
- package/stdlib/modules/std/gui/objects.zzm +123 -0
- package/stdlib/modules/std/gui.zzm +1914 -0
- package/stdlib/modules/std/internals.zzm +139 -0
- package/stdlib/modules/std/io/socks.zzm +139 -0
- package/stdlib/modules/std/io.zzm +157 -0
- package/stdlib/modules/std/lingua/en.zzm +347 -0
- package/stdlib/modules/std/log.zzm +169 -0
- package/stdlib/modules/std/mail.zzm +2726 -0
- package/stdlib/modules/std/marshal.zzm +138 -0
- package/stdlib/modules/std/math/bignum.zzm +98 -0
- package/stdlib/modules/std/math/range.zzm +116 -0
- package/stdlib/modules/std/math/roman.zzm +156 -0
- package/stdlib/modules/std/math.zzm +141 -0
- package/stdlib/modules/std/net/dns.zzm +93 -0
- package/stdlib/modules/std/net/http.zzm +278 -0
- package/stdlib/modules/std/net/smtp.zzm +257 -0
- package/stdlib/modules/std/net/url.zzm +69 -0
- package/stdlib/modules/std/path/jsonpointer.zzm +526 -0
- package/stdlib/modules/std/path/kdl.zzm +1003 -0
- package/stdlib/modules/std/path/simple.zzm +520 -0
- package/stdlib/modules/std/path/z/context.zzm +147 -0
- package/stdlib/modules/std/path/z/evaluate.zzm +549 -0
- package/stdlib/modules/std/path/z/functions.zzm +874 -0
- package/stdlib/modules/std/path/z/lexer.zzm +490 -0
- package/stdlib/modules/std/path/z/node.zzm +1455 -0
- package/stdlib/modules/std/path/z/operators.zzm +445 -0
- package/stdlib/modules/std/path/z/parser.zzm +359 -0
- package/stdlib/modules/std/path/z.zzm +403 -0
- package/stdlib/modules/std/path/zz/functions.zzm +828 -0
- package/stdlib/modules/std/path/zz/operators.zzm +1036 -0
- package/stdlib/modules/std/path/zz.zzm +100 -0
- package/stdlib/modules/std/proc.zzm +155 -0
- package/stdlib/modules/std/result.zzm +149 -0
- package/stdlib/modules/std/secure.zzm +606 -0
- package/stdlib/modules/std/string/base64.zzm +66 -0
- package/stdlib/modules/std/string/quoted_printable.zzm +485 -0
- package/stdlib/modules/std/string.zzm +179 -0
- package/stdlib/modules/std/task.zzm +221 -0
- package/stdlib/modules/std/template/z.zzm +531 -0
- package/stdlib/modules/std/template/zz.zzm +62 -0
- package/stdlib/modules/std/time.zzm +188 -0
- package/stdlib/modules/std/tui.zzm +89 -0
- package/stdlib/modules/std/uuid.zzm +223 -0
- package/stdlib/modules/std/web/session.zzm +388 -0
- package/stdlib/modules/std/web/static.zzm +329 -0
- package/stdlib/modules/std/web.zzm +1942 -0
- package/stdlib/modules/std/worker.zzm +202 -0
- package/stdlib/modules/std/zuzuzoo.zzm +3960 -0
- package/stdlib/modules/test/more.zzm +528 -0
- package/stdlib/modules/test/parser.zzm +209 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const cbor = require( './marshal/cbor' );
|
|
4
|
+
const {
|
|
5
|
+
dumpGraph,
|
|
6
|
+
loadGraph,
|
|
7
|
+
safeToDumpGraph,
|
|
8
|
+
setRuntimePolicy,
|
|
9
|
+
} = require( './marshal/graph' );
|
|
10
|
+
|
|
11
|
+
class MarshallingException extends Error {
|
|
12
|
+
constructor( message = 'std/marshal.dump failed' ) {
|
|
13
|
+
super( String( message ) );
|
|
14
|
+
this.name = 'MarshallingException';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
to_String() {
|
|
18
|
+
return `${this.name}: ${this.message}`;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class UnmarshallingException extends Error {
|
|
23
|
+
constructor( message = 'std/marshal.load failed' ) {
|
|
24
|
+
super( String( message ) );
|
|
25
|
+
this.name = 'UnmarshallingException';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
to_String() {
|
|
29
|
+
return `${this.name}: ${this.message}`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function dump( value ) {
|
|
34
|
+
assertArity( 'dump', arguments.length, 1 );
|
|
35
|
+
try {
|
|
36
|
+
return dumpGraph( value );
|
|
37
|
+
}
|
|
38
|
+
catch ( err ) {
|
|
39
|
+
throw new MarshallingException(
|
|
40
|
+
`std/marshal.dump failed: ${err.message || err}`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function load( blob ) {
|
|
46
|
+
assertArity( 'load', arguments.length, 1 );
|
|
47
|
+
try {
|
|
48
|
+
return loadGraph( blob );
|
|
49
|
+
}
|
|
50
|
+
catch ( err ) {
|
|
51
|
+
if ( String( err && err.message || err ).startsWith( 'TypeException:' ) ) {
|
|
52
|
+
throw err;
|
|
53
|
+
}
|
|
54
|
+
throw new UnmarshallingException(
|
|
55
|
+
`std/marshal.load failed: ${err.message || err}`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function safe_to_dump( value ) {
|
|
61
|
+
assertArity( 'safe_to_dump', arguments.length, 1 );
|
|
62
|
+
return safeToDumpGraph( value );
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function assertArity( name, got, expected ) {
|
|
66
|
+
if ( got !== expected ) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`TypeException: ${name} expects ${expected} argument, got ${got}`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = {
|
|
74
|
+
dump,
|
|
75
|
+
load,
|
|
76
|
+
safe_to_dump,
|
|
77
|
+
MarshallingException,
|
|
78
|
+
UnmarshallingException,
|
|
79
|
+
__zuzu_set_runtime_policy: setRuntimePolicy,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
Object.defineProperty( module.exports, '__cbor', {
|
|
83
|
+
value: cbor,
|
|
84
|
+
enumerable: false,
|
|
85
|
+
configurable: false,
|
|
86
|
+
writable: false,
|
|
87
|
+
} );
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class BigNum {
|
|
4
|
+
constructor( value, text = null, isInt = null ) {
|
|
5
|
+
this._value = Number( value ?? 0 );
|
|
6
|
+
this._text = text == null ? String( this._value ) : String( text );
|
|
7
|
+
this._isInt = isInt == null ? Number.isInteger( this._value ) : Boolean( isInt );
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
static _coerce( value ) {
|
|
11
|
+
if ( value instanceof BigNum ) {
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
if ( typeof value === 'string' ) {
|
|
15
|
+
return BigNum.from_dec( value );
|
|
16
|
+
}
|
|
17
|
+
return new BigNum( Number( value ?? 0 ) );
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static from_dec( value ) {
|
|
21
|
+
const text = String( value ?? '0' ).trim();
|
|
22
|
+
return new BigNum( Number( text || '0' ), text || '0', !/[.eE]/.test( text ) );
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static from_hex( value ) {
|
|
26
|
+
const text = String( value ?? '0' ).trim().toLowerCase().replace( /^0x/u, '' ) || '0';
|
|
27
|
+
const parsed = Number.parseInt( text, 16 );
|
|
28
|
+
return new BigNum( parsed, String( parsed ), true );
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get is_int() {
|
|
32
|
+
return this._isInt;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
bcmp( other ) {
|
|
36
|
+
const rhs = BigNum._coerce( other )._value;
|
|
37
|
+
return this._value < rhs ? -1 : ( this._value > rhs ? 1 : 0 );
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
beq( other ) { return this.bcmp( other ) === 0; }
|
|
41
|
+
bne( other ) { return this.bcmp( other ) !== 0; }
|
|
42
|
+
blt( other ) { return this.bcmp( other ) < 0; }
|
|
43
|
+
ble( other ) { return this.bcmp( other ) <= 0; }
|
|
44
|
+
bgt( other ) { return this.bcmp( other ) > 0; }
|
|
45
|
+
bge( other ) { return this.bcmp( other ) >= 0; }
|
|
46
|
+
|
|
47
|
+
get babs() { return new BigNum( Math.abs( this._value ), String( Math.abs( this._value ) ), this._isInt ); }
|
|
48
|
+
get bneg() { return new BigNum( -this._value, String( -this._value ), this._isInt ); }
|
|
49
|
+
get binv() { return new BigNum( 1 / this._value ); }
|
|
50
|
+
get bsin() { return new BigNum( Math.sin( this._value ), String( Math.sin( this._value ) ), false ); }
|
|
51
|
+
get bcos() { return new BigNum( Math.cos( this._value ) ); }
|
|
52
|
+
get btan() { return new BigNum( Math.tan( this._value ), String( Math.tan( this._value ) ), false ); }
|
|
53
|
+
get bsqrt() { return new BigNum( Math.sqrt( this._value ) ); }
|
|
54
|
+
get bround() { return new BigNum( Math.round( this._value ) ); }
|
|
55
|
+
get bfloor() { return new BigNum( Math.floor( this._value ) ); }
|
|
56
|
+
get bceil() { return new BigNum( Math.ceil( this._value ) ); }
|
|
57
|
+
|
|
58
|
+
badd( other ) { return new BigNum( this._value + BigNum._coerce( other )._value, String( this._value + BigNum._coerce( other )._value ), false ); }
|
|
59
|
+
bsub( other ) { return new BigNum( this._value - BigNum._coerce( other )._value, String( this._value - BigNum._coerce( other )._value ), false ); }
|
|
60
|
+
bmul( other ) { return new BigNum( this._value * BigNum._coerce( other )._value, String( this._value * BigNum._coerce( other )._value ), false ); }
|
|
61
|
+
bdiv( other ) { return new BigNum( this._value / BigNum._coerce( other )._value ); }
|
|
62
|
+
bmod( other ) { return new BigNum( this._value % BigNum._coerce( other )._value ); }
|
|
63
|
+
bpow( other ) { return new BigNum( this._value ** BigNum._coerce( other )._value ); }
|
|
64
|
+
|
|
65
|
+
get to_hex() {
|
|
66
|
+
return `0x${Math.trunc( this._value ).toString( 16 )}`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get to_dec() {
|
|
70
|
+
return this._isInt ? Math.trunc( this._value ) : this._textify();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
get to_String() {
|
|
74
|
+
return this.to_dec;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
get to_Number() {
|
|
78
|
+
return this._value;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
_textify() {
|
|
82
|
+
if ( this._text != null && /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/u.test( this._text ) ) {
|
|
83
|
+
return this._text.replace( /\.0+$/u, '' ).replace( /(\.\d*?)0+$/u, '$1' ).replace( /\.$/u, '' );
|
|
84
|
+
}
|
|
85
|
+
return String( this._value );
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = {
|
|
90
|
+
BigNum,
|
|
91
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const PI = Math.PI;
|
|
4
|
+
|
|
5
|
+
function normalizeNumberArgs( values ) {
|
|
6
|
+
if ( values.length === 1 && Array.isArray( values[0] ) ) {
|
|
7
|
+
return values[0];
|
|
8
|
+
}
|
|
9
|
+
return values;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const ZMath = {
|
|
13
|
+
pi: PI,
|
|
14
|
+
sin( value ) { return Math.sin( Number( value ?? 0 ) ); },
|
|
15
|
+
cos( value ) { return Math.cos( Number( value ?? 0 ) ); },
|
|
16
|
+
tan( value ) { return Math.tan( Number( value ?? 0 ) ); },
|
|
17
|
+
asin( value ) { return Math.asin( Number( value ?? 0 ) ); },
|
|
18
|
+
acos( value ) { return Math.acos( Number( value ?? 0 ) ); },
|
|
19
|
+
atan( value ) { return Math.atan( Number( value ?? 0 ) ); },
|
|
20
|
+
atan2( y, x ) { return Math.atan2( Number( y ?? 0 ), Number( x ?? 0 ) ); },
|
|
21
|
+
pow( base, exp ) { return Math.pow( Number( base ?? 0 ), Number( exp ?? 0 ) ); },
|
|
22
|
+
exp( value ) { return Math.exp( Number( value ?? 0 ) ); },
|
|
23
|
+
log( value ) { return Math.log( Number( value ?? 0 ) ); },
|
|
24
|
+
log10( value ) { return Math.log10( Number( value ?? 0 ) ); },
|
|
25
|
+
min( ...values ) { return Math.min( ...normalizeNumberArgs( values ).map( Number ) ); },
|
|
26
|
+
max( ...values ) { return Math.max( ...normalizeNumberArgs( values ).map( Number ) ); },
|
|
27
|
+
sum( ...values ) { return normalizeNumberArgs( values ).map( Number ).reduce( ( acc, v ) => acc + v, 0 ); },
|
|
28
|
+
clamp( value, low, high ) {
|
|
29
|
+
return Math.min( Number( high ?? 0 ), Math.max( Number( low ?? 0 ), Number( value ?? 0 ) ) );
|
|
30
|
+
},
|
|
31
|
+
hypot( ...values ) { return Math.hypot( ...values.map( Number ) ); },
|
|
32
|
+
deg2rad( degrees ) { return Number( degrees ?? 0 ) * ( PI / 180 ); },
|
|
33
|
+
rad2deg( radians ) { return Number( radians ?? 0 ) * ( 180 / PI ); },
|
|
34
|
+
rand() { return Math.random(); },
|
|
35
|
+
hex2dec( value ) { return convertBase( value, 16, 10 ); },
|
|
36
|
+
hex2oct( value ) { return convertBase( value, 16, 8 ); },
|
|
37
|
+
hex2bin( value ) { return convertBase( value, 16, 2 ); },
|
|
38
|
+
dec2hex( value ) { return convertBase( value, 10, 16 ); },
|
|
39
|
+
dec2oct( value ) { return convertBase( value, 10, 8 ); },
|
|
40
|
+
dec2bin( value ) { return convertBase( value, 10, 2 ); },
|
|
41
|
+
oct2hex( value ) { return convertBase( value, 8, 16 ); },
|
|
42
|
+
oct2dec( value ) { return convertBase( value, 8, 10 ); },
|
|
43
|
+
oct2bin( value ) { return convertBase( value, 8, 2 ); },
|
|
44
|
+
bin2hex( value ) { return convertBase( value, 2, 16 ); },
|
|
45
|
+
bin2dec( value ) { return convertBase( value, 2, 10 ); },
|
|
46
|
+
bin2oct( value ) { return convertBase( value, 2, 8 ); },
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
function normalizeDigits( value, base ) {
|
|
50
|
+
let text = String( value ?? '' ).trim().toLowerCase();
|
|
51
|
+
if ( base === 16 ) {
|
|
52
|
+
text = text.replace( /^0x/u, '' );
|
|
53
|
+
}
|
|
54
|
+
else if ( base === 8 ) {
|
|
55
|
+
text = text.replace( /^0o/u, '' );
|
|
56
|
+
}
|
|
57
|
+
else if ( base === 2 ) {
|
|
58
|
+
text = text.replace( /^0b/u, '' );
|
|
59
|
+
}
|
|
60
|
+
return text;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function convertBase( value, fromBase, toBase ) {
|
|
64
|
+
const text = normalizeDigits( value, fromBase );
|
|
65
|
+
if ( text === '' ) {
|
|
66
|
+
return '0';
|
|
67
|
+
}
|
|
68
|
+
const num = Number.parseInt( text, fromBase );
|
|
69
|
+
if ( Number.isNaN( num ) ) {
|
|
70
|
+
return '0';
|
|
71
|
+
}
|
|
72
|
+
return num.toString( toBase );
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = {
|
|
76
|
+
Math: ZMath,
|
|
77
|
+
pi: PI,
|
|
78
|
+
π: PI,
|
|
79
|
+
};
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require( 'node:child_process' );
|
|
4
|
+
const dns = require( 'node:dns' );
|
|
5
|
+
const { Task, traceBlockingOperation } = require( '../task' );
|
|
6
|
+
|
|
7
|
+
let runtimePolicy = {};
|
|
8
|
+
|
|
9
|
+
const SUPPORTED = new Set( [
|
|
10
|
+
'A',
|
|
11
|
+
'AAAA',
|
|
12
|
+
'CNAME',
|
|
13
|
+
'MX',
|
|
14
|
+
'NS',
|
|
15
|
+
'PTR',
|
|
16
|
+
'SRV',
|
|
17
|
+
'TXT',
|
|
18
|
+
] );
|
|
19
|
+
|
|
20
|
+
function __zuzu_set_runtime_policy( policy = {} ) {
|
|
21
|
+
runtimePolicy = policy || {};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function _requireDns() {
|
|
25
|
+
if ( runtimePolicy.deny_net || runtimePolicy.host_name === 'browser' ) {
|
|
26
|
+
throw new Error( 'DNSException: std/net/dns is unsupported in this runtime' );
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function _type( value = 'A' ) {
|
|
31
|
+
const type = String( value ?? 'A' ).toUpperCase();
|
|
32
|
+
if ( !SUPPORTED.has( type ) ) {
|
|
33
|
+
throw new Error( `DNSException: unsupported DNS record type '${type}'` );
|
|
34
|
+
}
|
|
35
|
+
return type;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function _family( value = 'any' ) {
|
|
39
|
+
const family = String( value ?? 'any' ).toLowerCase();
|
|
40
|
+
if ( ![ 'any', 'ipv4', 'ipv6' ].includes( family ) ) {
|
|
41
|
+
throw new Error( `DNSException: unsupported address family '${family}'` );
|
|
42
|
+
}
|
|
43
|
+
return family;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function _noData( err ) {
|
|
47
|
+
return err && [ 'ENODATA', 'ENOTFOUND', 'ENODOMAIN' ].includes( err.code );
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function _expectArity( name, count, min, max ) {
|
|
51
|
+
if ( count >= min && count <= max ) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const range = min === max ? String( min ) : `${min} or ${max}`;
|
|
55
|
+
throw new Error( `DNSException: ${name} expects ${range} arguments` );
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function _record( type, name, item ) {
|
|
59
|
+
const out = {
|
|
60
|
+
type,
|
|
61
|
+
name: String( name ?? '' ),
|
|
62
|
+
value: null,
|
|
63
|
+
ttl: null,
|
|
64
|
+
};
|
|
65
|
+
if ( type === 'A' || type === 'AAAA' ) {
|
|
66
|
+
out.address = typeof item === 'string' ? item : String( item.address ?? '' );
|
|
67
|
+
out.value = out.address;
|
|
68
|
+
if ( item && typeof item === 'object' && item.ttl != null ) {
|
|
69
|
+
out.ttl = Number( item.ttl );
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else if ( type === 'CNAME' || type === 'NS' || type === 'PTR' ) {
|
|
73
|
+
out.target = String( item ?? '' );
|
|
74
|
+
out.value = out.target;
|
|
75
|
+
}
|
|
76
|
+
else if ( type === 'MX' ) {
|
|
77
|
+
out.exchange = String( item.exchange ?? '' );
|
|
78
|
+
out.preference = Number( item.priority ?? item.preference ?? 0 );
|
|
79
|
+
out.value = out.exchange;
|
|
80
|
+
}
|
|
81
|
+
else if ( type === 'TXT' ) {
|
|
82
|
+
const strings = Array.isArray( item ) ? item.map( String ) : [ String( item ?? '' ) ];
|
|
83
|
+
out.strings = strings;
|
|
84
|
+
out.text = strings.join( '' );
|
|
85
|
+
out.value = out.text;
|
|
86
|
+
}
|
|
87
|
+
else if ( type === 'SRV' ) {
|
|
88
|
+
out.target = String( item.name ?? item.target ?? '' );
|
|
89
|
+
out.port = Number( item.port ?? 0 );
|
|
90
|
+
out.priority = Number( item.priority ?? 0 );
|
|
91
|
+
out.weight = Number( item.weight ?? 0 );
|
|
92
|
+
out.value = out.target;
|
|
93
|
+
}
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function _lookupAsync( name, recordType = 'A' ) {
|
|
98
|
+
_requireDns();
|
|
99
|
+
const type = _type( recordType );
|
|
100
|
+
const query = String( name ?? '' );
|
|
101
|
+
try {
|
|
102
|
+
let records;
|
|
103
|
+
if ( type === 'A' ) {
|
|
104
|
+
records = await dns.promises.resolve4( query, { ttl: true } );
|
|
105
|
+
}
|
|
106
|
+
else if ( type === 'AAAA' ) {
|
|
107
|
+
records = await dns.promises.resolve6( query, { ttl: true } );
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
records = await dns.promises.resolve( query, type );
|
|
111
|
+
}
|
|
112
|
+
return records.map( (item) => _record( type, query, item ) );
|
|
113
|
+
}
|
|
114
|
+
catch ( err ) {
|
|
115
|
+
if ( _noData( err ) ) {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
throw new Error( `DNSException: ${err.message || err.code || err}` );
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function _addressesAsync( name, family = 'any' ) {
|
|
123
|
+
_requireDns();
|
|
124
|
+
const selected = _family( family );
|
|
125
|
+
const query = String( name ?? '' );
|
|
126
|
+
const familyNumber = selected === 'ipv4' ? 4 : selected === 'ipv6' ? 6 : 0;
|
|
127
|
+
try {
|
|
128
|
+
const records = await dns.promises.lookup( query, {
|
|
129
|
+
all: true,
|
|
130
|
+
family: familyNumber,
|
|
131
|
+
} );
|
|
132
|
+
return records.map( (item) => item.address );
|
|
133
|
+
}
|
|
134
|
+
catch ( err ) {
|
|
135
|
+
if ( _noData( err ) ) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
throw new Error( `DNSException: ${err.message || err.code || err}` );
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function _reverseAsync( address ) {
|
|
143
|
+
_requireDns();
|
|
144
|
+
try {
|
|
145
|
+
return await dns.promises.reverse( String( address ?? '' ) );
|
|
146
|
+
}
|
|
147
|
+
catch ( err ) {
|
|
148
|
+
if ( _noData( err ) ) {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
throw new Error( `DNSException: ${err.message || err.code || err}` );
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function _nodeChildOptions() {
|
|
156
|
+
const options = {
|
|
157
|
+
encoding: 'utf8',
|
|
158
|
+
};
|
|
159
|
+
if ( runtimePolicy.host_name === 'electron' ) {
|
|
160
|
+
options.env = {
|
|
161
|
+
...process.env,
|
|
162
|
+
ELECTRON_RUN_AS_NODE: '1',
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
return options;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function _emptyResponseError( child ) {
|
|
169
|
+
const detail = String( child.stderr || '' ).trim()
|
|
170
|
+
|| (
|
|
171
|
+
Number.isInteger( child.status )
|
|
172
|
+
? `exit ${child.status}`
|
|
173
|
+
: ''
|
|
174
|
+
)
|
|
175
|
+
|| (
|
|
176
|
+
child.signal
|
|
177
|
+
? `signal ${child.signal}`
|
|
178
|
+
: ''
|
|
179
|
+
)
|
|
180
|
+
|| 'empty resolver response';
|
|
181
|
+
return `empty resolver response (${detail})`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function _syncRun( op, args ) {
|
|
185
|
+
_requireDns();
|
|
186
|
+
const source = `
|
|
187
|
+
const dns = require( 'node:dns' );
|
|
188
|
+
const payload = JSON.parse( process.argv[1] );
|
|
189
|
+
const noData = ( err ) => err && [ 'ENODATA', 'ENOTFOUND', 'ENODOMAIN' ].includes( err.code );
|
|
190
|
+
const record = ${_record.toString()};
|
|
191
|
+
(async () => {
|
|
192
|
+
try {
|
|
193
|
+
let result;
|
|
194
|
+
if ( payload.op === 'lookup' ) {
|
|
195
|
+
if ( payload.args[1] === 'A' ) {
|
|
196
|
+
result = ( await dns.promises.resolve4( payload.args[0], { ttl: true } ) )
|
|
197
|
+
.map( ( item ) => record( 'A', payload.args[0], item ) );
|
|
198
|
+
}
|
|
199
|
+
else if ( payload.args[1] === 'AAAA' ) {
|
|
200
|
+
result = ( await dns.promises.resolve6( payload.args[0], { ttl: true } ) )
|
|
201
|
+
.map( ( item ) => record( 'AAAA', payload.args[0], item ) );
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
result = ( await dns.promises.resolve( payload.args[0], payload.args[1] ) )
|
|
205
|
+
.map( ( item ) => record( payload.args[1], payload.args[0], item ) );
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else if ( payload.op === 'addresses' ) {
|
|
209
|
+
const family = payload.args[1] === 'ipv4' ? 4 : payload.args[1] === 'ipv6' ? 6 : 0;
|
|
210
|
+
result = ( await dns.promises.lookup( payload.args[0], { all: true, family } ) )
|
|
211
|
+
.map( ( item ) => item.address );
|
|
212
|
+
}
|
|
213
|
+
else if ( payload.op === 'reverse' ) {
|
|
214
|
+
result = await dns.promises.reverse( payload.args[0] );
|
|
215
|
+
}
|
|
216
|
+
process.stdout.write( JSON.stringify( { ok: true, result } ) );
|
|
217
|
+
}
|
|
218
|
+
catch ( err ) {
|
|
219
|
+
if ( noData( err ) ) {
|
|
220
|
+
process.stdout.write( JSON.stringify( { ok: true, result: [] } ) );
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
process.stdout.write( JSON.stringify( {
|
|
224
|
+
ok: false,
|
|
225
|
+
error: err && ( err.message || err.code ) ? err.message || err.code : String( err ),
|
|
226
|
+
} ) );
|
|
227
|
+
}
|
|
228
|
+
})().catch( ( err ) => {
|
|
229
|
+
process.stdout.write( JSON.stringify( { ok: false, error: String( err ) } ) );
|
|
230
|
+
} );
|
|
231
|
+
`;
|
|
232
|
+
const payload = JSON.stringify( { op, args } );
|
|
233
|
+
const child = spawnSync( process.execPath, [ '-e', source, payload ], {
|
|
234
|
+
..._nodeChildOptions(),
|
|
235
|
+
});
|
|
236
|
+
if ( child.error ) {
|
|
237
|
+
throw new Error( `DNSException: ${child.error.message}` );
|
|
238
|
+
}
|
|
239
|
+
let parsed;
|
|
240
|
+
try {
|
|
241
|
+
parsed = JSON.parse(
|
|
242
|
+
child.stdout || JSON.stringify( {
|
|
243
|
+
ok: false,
|
|
244
|
+
error: _emptyResponseError( child ),
|
|
245
|
+
} )
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
catch ( err ) {
|
|
249
|
+
throw new Error(
|
|
250
|
+
`DNSException: invalid resolver response: ${err.message}`
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
if ( !parsed.ok ) {
|
|
254
|
+
throw new Error( `DNSException: ${parsed.error}` );
|
|
255
|
+
}
|
|
256
|
+
return parsed.result;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function lookup( name, recordType = 'A' ) {
|
|
260
|
+
_expectArity( 'lookup()', arguments.length, 1, 2 );
|
|
261
|
+
traceBlockingOperation( 'std/net/dns lookup' );
|
|
262
|
+
return _syncRun( 'lookup', [ String( name ?? '' ), _type( recordType ) ] );
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function lookup_async( name, recordType = 'A' ) {
|
|
266
|
+
_expectArity( 'lookup_async()', arguments.length, 1, 2 );
|
|
267
|
+
return new Task( () => _lookupAsync( name, recordType ), {
|
|
268
|
+
name: 'dns.lookup_async',
|
|
269
|
+
} );
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function addresses( name, family = 'any' ) {
|
|
273
|
+
_expectArity( 'addresses()', arguments.length, 1, 2 );
|
|
274
|
+
traceBlockingOperation( 'std/net/dns addresses' );
|
|
275
|
+
return _syncRun( 'addresses', [ String( name ?? '' ), _family( family ) ] );
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function addresses_async( name, family = 'any' ) {
|
|
279
|
+
_expectArity( 'addresses_async()', arguments.length, 1, 2 );
|
|
280
|
+
return new Task( () => _addressesAsync( name, family ), {
|
|
281
|
+
name: 'dns.addresses_async',
|
|
282
|
+
} );
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function reverse( address ) {
|
|
286
|
+
_expectArity( 'reverse()', arguments.length, 1, 1 );
|
|
287
|
+
traceBlockingOperation( 'std/net/dns reverse' );
|
|
288
|
+
return _syncRun( 'reverse', [ String( address ?? '' ) ] );
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function reverse_async( address ) {
|
|
292
|
+
_expectArity( 'reverse_async()', arguments.length, 1, 1 );
|
|
293
|
+
return new Task( () => _reverseAsync( address ), {
|
|
294
|
+
name: 'dns.reverse_async',
|
|
295
|
+
} );
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
module.exports = {
|
|
299
|
+
__zuzu_set_runtime_policy,
|
|
300
|
+
lookup,
|
|
301
|
+
lookup_async,
|
|
302
|
+
addresses,
|
|
303
|
+
addresses_async,
|
|
304
|
+
reverse,
|
|
305
|
+
reverse_async,
|
|
306
|
+
};
|