@jsenv/core 38.1.1 → 38.2.1
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 +3 -7
- package/dist/babel_helpers/dispose/dispose.js +45 -0
- package/dist/babel_helpers/regeneratorRuntime/regeneratorRuntime.js +2 -6
- package/dist/babel_helpers/using/using.js +23 -0
- package/dist/js/ws.js +60 -33
- package/dist/jsenv_core.js +124 -214
- package/package.json +15 -16
- package/src/main.js +3 -0
- package/src/plugins/global_scenarios/jsenv_plugin_global_scenarios.js +9 -6
- package/src/plugins/injections/internal/inject_globals.js +59 -0
- package/src/plugins/injections/jsenv_plugin_injections.js +101 -0
- package/src/plugins/plugins.js +1 -1
- package/src/plugins/reference_analysis/js/jsenv_plugin_js_reference_analysis.js +17 -0
package/README.md
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
# @jsenv/core [](https://www.npmjs.com/package/@jsenv/core)
|
|
2
2
|
|
|
3
|
-
Jsenv is a tool to develop test and build projects using JavaScript.
|
|
3
|
+
Jsenv is a tool to develop test and build projects using JavaScript.
|
|
4
|
+
Jsenv is simple, easy to understand and well documented.
|
|
4
5
|
|
|
5
|
-
[Documentation
|
|
6
|
-
|
|
7
|
-
See also
|
|
8
|
-
|
|
9
|
-
- [Documentation for contributors](./docs/contributors/README.md)
|
|
10
|
-
- [Documentation for maintainers](./docs/maintainers/README.md)
|
|
6
|
+
[Documentation](<https://github.com/jsenv/core/wiki/A)-Introduction>)
|
|
11
7
|
|
|
12
8
|
<!-- # Installation
|
|
13
9
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/* @minVersion 7.22.0 */
|
|
2
|
+
function dispose_SuppressedError(suppressed, error) {
|
|
3
|
+
if (typeof SuppressedError !== "undefined") {
|
|
4
|
+
// eslint-disable-next-line no-undef
|
|
5
|
+
dispose_SuppressedError = SuppressedError;
|
|
6
|
+
} else {
|
|
7
|
+
dispose_SuppressedError = function SuppressedError(suppressed, error) {
|
|
8
|
+
this.suppressed = suppressed;
|
|
9
|
+
this.error = error;
|
|
10
|
+
this.stack = new Error().stack;
|
|
11
|
+
};
|
|
12
|
+
dispose_SuppressedError.prototype = Object.create(Error.prototype, {
|
|
13
|
+
constructor: {
|
|
14
|
+
value: dispose_SuppressedError,
|
|
15
|
+
writable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return new dispose_SuppressedError(suppressed, error);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default function _dispose(stack, error, hasError) {
|
|
24
|
+
function next() {
|
|
25
|
+
while (stack.length > 0) {
|
|
26
|
+
try {
|
|
27
|
+
var r = stack.pop();
|
|
28
|
+
var p = r.d.call(r.v);
|
|
29
|
+
if (r.a) return Promise.resolve(p).then(next, err);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
return err(e);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (hasError) throw error;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function err(e) {
|
|
38
|
+
error = hasError ? new dispose_SuppressedError(e, error) : e;
|
|
39
|
+
hasError = true;
|
|
40
|
+
|
|
41
|
+
return next();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return next();
|
|
45
|
+
}
|
|
@@ -483,7 +483,7 @@ export default function _regeneratorRuntime() {
|
|
|
483
483
|
};
|
|
484
484
|
};
|
|
485
485
|
function values(iterable) {
|
|
486
|
-
if (iterable) {
|
|
486
|
+
if (iterable || iterable === "") {
|
|
487
487
|
var iteratorMethod = iterable[iteratorSymbol];
|
|
488
488
|
if (iteratorMethod) {
|
|
489
489
|
return iteratorMethod.call(iterable);
|
|
@@ -508,11 +508,7 @@ export default function _regeneratorRuntime() {
|
|
|
508
508
|
return (next.next = next);
|
|
509
509
|
}
|
|
510
510
|
}
|
|
511
|
-
|
|
512
|
-
// Return an iterator with no values.
|
|
513
|
-
return {
|
|
514
|
-
next: doneResult,
|
|
515
|
-
};
|
|
511
|
+
throw new TypeError(typeof iterable + " is not iterable");
|
|
516
512
|
}
|
|
517
513
|
exports.values = values;
|
|
518
514
|
function doneResult() {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/* @minVersion 7.22.0 */
|
|
2
|
+
|
|
3
|
+
export default function _using(stack, value, isAwait) {
|
|
4
|
+
if (value === null || value === void 0) return value;
|
|
5
|
+
if (typeof value !== "object") {
|
|
6
|
+
throw new TypeError(
|
|
7
|
+
"using declarations can only be used with objects, null, or undefined."
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
// core-js-pure uses Symbol.for for polyfilling well-known symbols
|
|
11
|
+
if (isAwait) {
|
|
12
|
+
var dispose =
|
|
13
|
+
value[Symbol.asyncDispose || Symbol.for("Symbol.asyncDispose")];
|
|
14
|
+
}
|
|
15
|
+
if (dispose === null || dispose === void 0) {
|
|
16
|
+
dispose = value[Symbol.dispose || Symbol.for("Symbol.dispose")];
|
|
17
|
+
}
|
|
18
|
+
if (typeof dispose !== "function") {
|
|
19
|
+
throw new TypeError(`Property [Symbol.dispose] is not a function.`);
|
|
20
|
+
}
|
|
21
|
+
stack.push({ v: value, d: dispose, a: isAwait });
|
|
22
|
+
return value;
|
|
23
|
+
}
|
package/dist/js/ws.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import require$$0 from "stream";
|
|
2
2
|
import require$$0$3 from "events";
|
|
3
3
|
import require$$2 from "http";
|
|
4
|
-
import require$$1 from "
|
|
5
|
-
import require$$3 from "net";
|
|
6
|
-
import require$$4 from "tls";
|
|
7
|
-
import require$$5 from "crypto";
|
|
4
|
+
import require$$1 from "crypto";
|
|
8
5
|
import require$$0$1 from "zlib";
|
|
9
6
|
import require$$0$2 from "buffer";
|
|
7
|
+
import require$$1$1 from "https";
|
|
8
|
+
import require$$3 from "net";
|
|
9
|
+
import require$$4 from "tls";
|
|
10
10
|
import require$$7 from "url";
|
|
11
11
|
|
|
12
12
|
function getDefaultExportFromCjs (x) {
|
|
@@ -876,12 +876,15 @@ const { concat, toArrayBuffer, unmask } = bufferUtilExports;
|
|
|
876
876
|
const { isValidStatusCode: isValidStatusCode$1, isValidUTF8 } = validationExports;
|
|
877
877
|
|
|
878
878
|
const FastBuffer = Buffer[Symbol.species];
|
|
879
|
+
const promise = Promise.resolve();
|
|
880
|
+
|
|
879
881
|
const GET_INFO = 0;
|
|
880
882
|
const GET_PAYLOAD_LENGTH_16 = 1;
|
|
881
883
|
const GET_PAYLOAD_LENGTH_64 = 2;
|
|
882
884
|
const GET_MASK = 3;
|
|
883
885
|
const GET_DATA = 4;
|
|
884
886
|
const INFLATING = 5;
|
|
887
|
+
const WAIT_MICROTASK = 6;
|
|
885
888
|
|
|
886
889
|
/**
|
|
887
890
|
* HyBi Receiver implementation.
|
|
@@ -1020,9 +1023,23 @@ let Receiver$1 = class Receiver extends Writable {
|
|
|
1020
1023
|
case GET_DATA:
|
|
1021
1024
|
err = this.getData(cb);
|
|
1022
1025
|
break;
|
|
1026
|
+
case INFLATING:
|
|
1027
|
+
this._loop = false;
|
|
1028
|
+
return;
|
|
1023
1029
|
default:
|
|
1024
|
-
//
|
|
1030
|
+
//
|
|
1031
|
+
// `WAIT_MICROTASK`.
|
|
1032
|
+
//
|
|
1025
1033
|
this._loop = false;
|
|
1034
|
+
|
|
1035
|
+
//
|
|
1036
|
+
// `queueMicrotask()` is not available in Node.js < 11 and is no
|
|
1037
|
+
// better anyway.
|
|
1038
|
+
//
|
|
1039
|
+
promise.then(() => {
|
|
1040
|
+
this._state = GET_INFO;
|
|
1041
|
+
this.startLoop(cb);
|
|
1042
|
+
});
|
|
1026
1043
|
return;
|
|
1027
1044
|
}
|
|
1028
1045
|
} while (this._loop);
|
|
@@ -1405,7 +1422,7 @@ let Receiver$1 = class Receiver extends Writable {
|
|
|
1405
1422
|
}
|
|
1406
1423
|
}
|
|
1407
1424
|
|
|
1408
|
-
this._state =
|
|
1425
|
+
this._state = WAIT_MICROTASK;
|
|
1409
1426
|
}
|
|
1410
1427
|
|
|
1411
1428
|
/**
|
|
@@ -1422,6 +1439,8 @@ let Receiver$1 = class Receiver extends Writable {
|
|
|
1422
1439
|
if (data.length === 0) {
|
|
1423
1440
|
this.emit('conclude', 1005, EMPTY_BUFFER$2);
|
|
1424
1441
|
this.end();
|
|
1442
|
+
|
|
1443
|
+
this._state = GET_INFO;
|
|
1425
1444
|
} else {
|
|
1426
1445
|
const code = data.readUInt16BE(0);
|
|
1427
1446
|
|
|
@@ -1453,14 +1472,16 @@ let Receiver$1 = class Receiver extends Writable {
|
|
|
1453
1472
|
|
|
1454
1473
|
this.emit('conclude', code, buf);
|
|
1455
1474
|
this.end();
|
|
1475
|
+
|
|
1476
|
+
this._state = GET_INFO;
|
|
1456
1477
|
}
|
|
1457
1478
|
} else if (this._opcode === 0x09) {
|
|
1458
1479
|
this.emit('ping', data);
|
|
1480
|
+
this._state = WAIT_MICROTASK;
|
|
1459
1481
|
} else {
|
|
1460
1482
|
this.emit('pong', data);
|
|
1483
|
+
this._state = WAIT_MICROTASK;
|
|
1461
1484
|
}
|
|
1462
|
-
|
|
1463
|
-
this._state = GET_INFO;
|
|
1464
1485
|
}
|
|
1465
1486
|
};
|
|
1466
1487
|
|
|
@@ -1489,8 +1510,8 @@ function error(ErrorCtor, message, prefix, statusCode, errorCode) {
|
|
|
1489
1510
|
return err;
|
|
1490
1511
|
}
|
|
1491
1512
|
|
|
1492
|
-
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^
|
|
1493
|
-
const { randomFillSync } = require$$
|
|
1513
|
+
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex" }] */
|
|
1514
|
+
const { randomFillSync } = require$$1;
|
|
1494
1515
|
|
|
1495
1516
|
const PerMessageDeflate$2 = permessageDeflate;
|
|
1496
1517
|
const { EMPTY_BUFFER: EMPTY_BUFFER$1 } = constants;
|
|
@@ -1507,7 +1528,7 @@ let Sender$1 = class Sender {
|
|
|
1507
1528
|
/**
|
|
1508
1529
|
* Creates a Sender instance.
|
|
1509
1530
|
*
|
|
1510
|
-
* @param {
|
|
1531
|
+
* @param {Duplex} socket The connection socket
|
|
1511
1532
|
* @param {Object} [extensions] An object containing the negotiated extensions
|
|
1512
1533
|
* @param {Function} [generateMask] The function used to generate the masking
|
|
1513
1534
|
* key
|
|
@@ -2456,14 +2477,14 @@ function format$1(extensions) {
|
|
|
2456
2477
|
|
|
2457
2478
|
var extension$1 = { format: format$1, parse: parse$2 };
|
|
2458
2479
|
|
|
2459
|
-
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Readable$" }] */
|
|
2480
|
+
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex|Readable$" }] */
|
|
2460
2481
|
|
|
2461
2482
|
const EventEmitter$1 = require$$0$3;
|
|
2462
|
-
const https = require$$1;
|
|
2483
|
+
const https = require$$1$1;
|
|
2463
2484
|
const http$1 = require$$2;
|
|
2464
2485
|
const net = require$$3;
|
|
2465
2486
|
const tls = require$$4;
|
|
2466
|
-
const { randomBytes, createHash: createHash$1 } = require$$
|
|
2487
|
+
const { randomBytes, createHash: createHash$1 } = require$$1;
|
|
2467
2488
|
const { URL } = require$$7;
|
|
2468
2489
|
|
|
2469
2490
|
const PerMessageDeflate$1 = permessageDeflate;
|
|
@@ -2644,8 +2665,7 @@ let WebSocket$1 = class WebSocket extends EventEmitter$1 {
|
|
|
2644
2665
|
/**
|
|
2645
2666
|
* Set up the socket and the internal resources.
|
|
2646
2667
|
*
|
|
2647
|
-
* @param {
|
|
2648
|
-
* server and client
|
|
2668
|
+
* @param {Duplex} socket The network socket between the server and client
|
|
2649
2669
|
* @param {Buffer} head The first packet of the upgraded stream
|
|
2650
2670
|
* @param {Object} options Options object
|
|
2651
2671
|
* @param {Function} [options.generateMask] The function used to generate the
|
|
@@ -2678,8 +2698,11 @@ let WebSocket$1 = class WebSocket extends EventEmitter$1 {
|
|
|
2678
2698
|
receiver.on('ping', receiverOnPing);
|
|
2679
2699
|
receiver.on('pong', receiverOnPong);
|
|
2680
2700
|
|
|
2681
|
-
|
|
2682
|
-
socket
|
|
2701
|
+
//
|
|
2702
|
+
// These methods may not be available if `socket` is just a `Duplex`.
|
|
2703
|
+
//
|
|
2704
|
+
if (socket.setTimeout) socket.setTimeout(0);
|
|
2705
|
+
if (socket.setNoDelay) socket.setNoDelay();
|
|
2683
2706
|
|
|
2684
2707
|
if (head.length > 0) socket.unshift(head);
|
|
2685
2708
|
|
|
@@ -3122,24 +3145,30 @@ function initAsClient(websocket, address, protocols, options) {
|
|
|
3122
3145
|
|
|
3123
3146
|
if (address instanceof URL) {
|
|
3124
3147
|
parsedUrl = address;
|
|
3125
|
-
websocket._url = address.href;
|
|
3126
3148
|
} else {
|
|
3127
3149
|
try {
|
|
3128
3150
|
parsedUrl = new URL(address);
|
|
3129
3151
|
} catch (e) {
|
|
3130
3152
|
throw new SyntaxError(`Invalid URL: ${address}`);
|
|
3131
3153
|
}
|
|
3154
|
+
}
|
|
3132
3155
|
|
|
3133
|
-
|
|
3156
|
+
if (parsedUrl.protocol === 'http:') {
|
|
3157
|
+
parsedUrl.protocol = 'ws:';
|
|
3158
|
+
} else if (parsedUrl.protocol === 'https:') {
|
|
3159
|
+
parsedUrl.protocol = 'wss:';
|
|
3134
3160
|
}
|
|
3135
3161
|
|
|
3162
|
+
websocket._url = parsedUrl.href;
|
|
3163
|
+
|
|
3136
3164
|
const isSecure = parsedUrl.protocol === 'wss:';
|
|
3137
3165
|
const isIpcUrl = parsedUrl.protocol === 'ws+unix:';
|
|
3138
3166
|
let invalidUrlMessage;
|
|
3139
3167
|
|
|
3140
3168
|
if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {
|
|
3141
3169
|
invalidUrlMessage =
|
|
3142
|
-
'The URL\'s protocol must be one of "ws:", "wss:",
|
|
3170
|
+
'The URL\'s protocol must be one of "ws:", "wss:", ' +
|
|
3171
|
+
'"http:", "https", or "ws+unix:"';
|
|
3143
3172
|
} else if (isIpcUrl && !parsedUrl.pathname) {
|
|
3144
3173
|
invalidUrlMessage = "The URL's pathname is empty";
|
|
3145
3174
|
} else if (parsedUrl.hash) {
|
|
@@ -3673,7 +3702,7 @@ function resume(stream) {
|
|
|
3673
3702
|
}
|
|
3674
3703
|
|
|
3675
3704
|
/**
|
|
3676
|
-
* The listener of the
|
|
3705
|
+
* The listener of the socket `'close'` event.
|
|
3677
3706
|
*
|
|
3678
3707
|
* @private
|
|
3679
3708
|
*/
|
|
@@ -3724,7 +3753,7 @@ function socketOnClose() {
|
|
|
3724
3753
|
}
|
|
3725
3754
|
|
|
3726
3755
|
/**
|
|
3727
|
-
* The listener of the
|
|
3756
|
+
* The listener of the socket `'data'` event.
|
|
3728
3757
|
*
|
|
3729
3758
|
* @param {Buffer} chunk A chunk of data
|
|
3730
3759
|
* @private
|
|
@@ -3736,7 +3765,7 @@ function socketOnData(chunk) {
|
|
|
3736
3765
|
}
|
|
3737
3766
|
|
|
3738
3767
|
/**
|
|
3739
|
-
* The listener of the
|
|
3768
|
+
* The listener of the socket `'end'` event.
|
|
3740
3769
|
*
|
|
3741
3770
|
* @private
|
|
3742
3771
|
*/
|
|
@@ -3749,7 +3778,7 @@ function socketOnEnd() {
|
|
|
3749
3778
|
}
|
|
3750
3779
|
|
|
3751
3780
|
/**
|
|
3752
|
-
* The listener of the
|
|
3781
|
+
* The listener of the socket `'error'` event.
|
|
3753
3782
|
*
|
|
3754
3783
|
* @private
|
|
3755
3784
|
*/
|
|
@@ -3826,11 +3855,11 @@ function parse(header) {
|
|
|
3826
3855
|
|
|
3827
3856
|
var subprotocol$1 = { parse };
|
|
3828
3857
|
|
|
3829
|
-
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^
|
|
3858
|
+
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$" }] */
|
|
3830
3859
|
|
|
3831
3860
|
const EventEmitter = require$$0$3;
|
|
3832
3861
|
const http = require$$2;
|
|
3833
|
-
const { createHash } = require$$
|
|
3862
|
+
const { createHash } = require$$1;
|
|
3834
3863
|
|
|
3835
3864
|
const extension = extension$1;
|
|
3836
3865
|
const PerMessageDeflate = permessageDeflate;
|
|
@@ -4044,8 +4073,7 @@ class WebSocketServer extends EventEmitter {
|
|
|
4044
4073
|
* Handle a HTTP Upgrade request.
|
|
4045
4074
|
*
|
|
4046
4075
|
* @param {http.IncomingMessage} req The request object
|
|
4047
|
-
* @param {
|
|
4048
|
-
* server and client
|
|
4076
|
+
* @param {Duplex} socket The network socket between the server and client
|
|
4049
4077
|
* @param {Buffer} head The first packet of the upgraded stream
|
|
4050
4078
|
* @param {Function} cb Callback
|
|
4051
4079
|
* @public
|
|
@@ -4169,8 +4197,7 @@ class WebSocketServer extends EventEmitter {
|
|
|
4169
4197
|
* @param {String} key The value of the `Sec-WebSocket-Key` header
|
|
4170
4198
|
* @param {Set} protocols The subprotocols
|
|
4171
4199
|
* @param {http.IncomingMessage} req The request object
|
|
4172
|
-
* @param {
|
|
4173
|
-
* server and client
|
|
4200
|
+
* @param {Duplex} socket The network socket between the server and client
|
|
4174
4201
|
* @param {Buffer} head The first packet of the upgraded stream
|
|
4175
4202
|
* @param {Function} cb Callback
|
|
4176
4203
|
* @throws {Error} If called more than once with the same socket
|
|
@@ -4300,7 +4327,7 @@ function socketOnError() {
|
|
|
4300
4327
|
/**
|
|
4301
4328
|
* Close the connection when preconditions are not fulfilled.
|
|
4302
4329
|
*
|
|
4303
|
-
* @param {
|
|
4330
|
+
* @param {Duplex} socket The socket of the upgrade request
|
|
4304
4331
|
* @param {Number} code The HTTP response status code
|
|
4305
4332
|
* @param {String} [message] The HTTP response body
|
|
4306
4333
|
* @param {Object} [headers] Additional HTTP response headers
|
|
@@ -4341,7 +4368,7 @@ function abortHandshake(socket, code, message, headers) {
|
|
|
4341
4368
|
*
|
|
4342
4369
|
* @param {WebSocketServer} server The WebSocket server
|
|
4343
4370
|
* @param {http.IncomingMessage} req The request object
|
|
4344
|
-
* @param {
|
|
4371
|
+
* @param {Duplex} socket The socket of the upgrade request
|
|
4345
4372
|
* @param {Number} code The HTTP response status code
|
|
4346
4373
|
* @param {String} message The HTTP response body
|
|
4347
4374
|
* @private
|
package/dist/jsenv_core.js
CHANGED
|
@@ -10579,9 +10579,13 @@ const jsenvPluginJsModuleFallbackOnWorkers = () => {
|
|
|
10579
10579
|
name: `jsenv:js_module_fallback_on_${subtype}`,
|
|
10580
10580
|
appliesDuring: "*",
|
|
10581
10581
|
init: (context) => {
|
|
10582
|
+
if (Object.keys(context.runtimeCompat).toString() === "node") {
|
|
10583
|
+
return false;
|
|
10584
|
+
}
|
|
10582
10585
|
if (context.isSupportedOnCurrentClients(`${subtype}_type_module`)) {
|
|
10583
10586
|
return false;
|
|
10584
10587
|
}
|
|
10588
|
+
|
|
10585
10589
|
return true;
|
|
10586
10590
|
},
|
|
10587
10591
|
redirectReference: {
|
|
@@ -14797,214 +14801,6 @@ const createRepartitionMessage = ({ html, css, js, json, other, total }) => {
|
|
|
14797
14801
|
- `)}`;
|
|
14798
14802
|
};
|
|
14799
14803
|
|
|
14800
|
-
const placeholderSymbol = Symbol.for("jsenv_placeholder");
|
|
14801
|
-
const PLACEHOLDER = {
|
|
14802
|
-
optional: (value) => {
|
|
14803
|
-
return { [placeholderSymbol]: "optional", value };
|
|
14804
|
-
},
|
|
14805
|
-
};
|
|
14806
|
-
|
|
14807
|
-
const replacePlaceholders = (content, replacements, urlInfo) => {
|
|
14808
|
-
const magicSource = createMagicSource(content);
|
|
14809
|
-
for (const key of Object.keys(replacements)) {
|
|
14810
|
-
let index = content.indexOf(key);
|
|
14811
|
-
const replacement = replacements[key];
|
|
14812
|
-
let isOptional;
|
|
14813
|
-
let value;
|
|
14814
|
-
if (replacement && replacement[placeholderSymbol]) {
|
|
14815
|
-
const valueBehindSymbol = replacement[placeholderSymbol];
|
|
14816
|
-
isOptional = valueBehindSymbol === "optional";
|
|
14817
|
-
value = replacement.value;
|
|
14818
|
-
} else {
|
|
14819
|
-
value = replacement;
|
|
14820
|
-
}
|
|
14821
|
-
if (index === -1) {
|
|
14822
|
-
if (!isOptional) {
|
|
14823
|
-
urlInfo.context.logger.warn(
|
|
14824
|
-
`placeholder "${key}" not found in ${urlInfo.url}.
|
|
14825
|
-
--- suggestion a ---
|
|
14826
|
-
Add "${key}" in that file.
|
|
14827
|
-
--- suggestion b ---
|
|
14828
|
-
Fix eventual typo in "${key}"?
|
|
14829
|
-
--- suggestion c ---
|
|
14830
|
-
Mark injection as optional using PLACEHOLDER.optional()
|
|
14831
|
-
|
|
14832
|
-
import { PLACEHOLDER } from "@jsenv/core"
|
|
14833
|
-
|
|
14834
|
-
return {
|
|
14835
|
-
"${key}": PLACEHOLDER.optional(${JSON.stringify(value)})
|
|
14836
|
-
}`,
|
|
14837
|
-
);
|
|
14838
|
-
}
|
|
14839
|
-
continue;
|
|
14840
|
-
}
|
|
14841
|
-
|
|
14842
|
-
while (index !== -1) {
|
|
14843
|
-
const start = index;
|
|
14844
|
-
const end = index + key.length;
|
|
14845
|
-
magicSource.replace({
|
|
14846
|
-
start,
|
|
14847
|
-
end,
|
|
14848
|
-
replacement:
|
|
14849
|
-
urlInfo.type === "js_classic" ||
|
|
14850
|
-
urlInfo.type === "js_module" ||
|
|
14851
|
-
urlInfo.type === "html"
|
|
14852
|
-
? JSON.stringify(value, null, " ")
|
|
14853
|
-
: value,
|
|
14854
|
-
});
|
|
14855
|
-
index = content.indexOf(key, end);
|
|
14856
|
-
}
|
|
14857
|
-
}
|
|
14858
|
-
return magicSource.toContentAndSourcemap();
|
|
14859
|
-
};
|
|
14860
|
-
|
|
14861
|
-
const injectGlobals = (content, globals, urlInfo) => {
|
|
14862
|
-
if (urlInfo.type === "html") {
|
|
14863
|
-
return globalInjectorOnHtml(content, globals);
|
|
14864
|
-
}
|
|
14865
|
-
if (urlInfo.type === "js_classic" || urlInfo.type === "js_module") {
|
|
14866
|
-
return globalsInjectorOnJs(content, globals, urlInfo);
|
|
14867
|
-
}
|
|
14868
|
-
throw new Error(`cannot inject globals into "${urlInfo.type}"`);
|
|
14869
|
-
};
|
|
14870
|
-
|
|
14871
|
-
const globalInjectorOnHtml = (content, globals) => {
|
|
14872
|
-
// ideally we would inject an importmap but browser support is too low
|
|
14873
|
-
// (even worse for worker/service worker)
|
|
14874
|
-
// so for now we inject code into entry points
|
|
14875
|
-
const htmlAst = parseHtmlString(content, {
|
|
14876
|
-
storeOriginalPositions: false,
|
|
14877
|
-
});
|
|
14878
|
-
const clientCode = generateClientCodeForGlobals(globals, {
|
|
14879
|
-
isWebWorker: false,
|
|
14880
|
-
});
|
|
14881
|
-
injectHtmlNodeAsEarlyAsPossible(
|
|
14882
|
-
htmlAst,
|
|
14883
|
-
createHtmlNode({
|
|
14884
|
-
tagName: "script",
|
|
14885
|
-
textContent: clientCode,
|
|
14886
|
-
}),
|
|
14887
|
-
"jsenv:inject_globals",
|
|
14888
|
-
);
|
|
14889
|
-
return stringifyHtmlAst(htmlAst);
|
|
14890
|
-
};
|
|
14891
|
-
|
|
14892
|
-
const globalsInjectorOnJs = (content, globals, urlInfo) => {
|
|
14893
|
-
const clientCode = generateClientCodeForGlobals(globals, {
|
|
14894
|
-
isWebWorker:
|
|
14895
|
-
urlInfo.subtype === "worker" ||
|
|
14896
|
-
urlInfo.subtype === "service_worker" ||
|
|
14897
|
-
urlInfo.subtype === "shared_worker",
|
|
14898
|
-
});
|
|
14899
|
-
const magicSource = createMagicSource(content);
|
|
14900
|
-
magicSource.prepend(clientCode);
|
|
14901
|
-
return magicSource.toContentAndSourcemap();
|
|
14902
|
-
};
|
|
14903
|
-
|
|
14904
|
-
const generateClientCodeForGlobals = (globals, { isWebWorker = false }) => {
|
|
14905
|
-
const globalName = isWebWorker ? "self" : "window";
|
|
14906
|
-
return `Object.assign(${globalName}, ${JSON.stringify(
|
|
14907
|
-
globals,
|
|
14908
|
-
null,
|
|
14909
|
-
" ",
|
|
14910
|
-
)});`;
|
|
14911
|
-
};
|
|
14912
|
-
|
|
14913
|
-
const jsenvPluginInjections = (rawAssociations) => {
|
|
14914
|
-
let resolvedAssociations;
|
|
14915
|
-
|
|
14916
|
-
return {
|
|
14917
|
-
name: "jsenv:injections",
|
|
14918
|
-
appliesDuring: "*",
|
|
14919
|
-
init: (context) => {
|
|
14920
|
-
resolvedAssociations = URL_META.resolveAssociations(
|
|
14921
|
-
{ injectionsGetter: rawAssociations },
|
|
14922
|
-
context.rootDirectoryUrl,
|
|
14923
|
-
);
|
|
14924
|
-
},
|
|
14925
|
-
transformUrlContent: async (urlInfo) => {
|
|
14926
|
-
const { injectionsGetter } = URL_META.applyAssociations({
|
|
14927
|
-
url: asUrlWithoutSearch(urlInfo.url),
|
|
14928
|
-
associations: resolvedAssociations,
|
|
14929
|
-
});
|
|
14930
|
-
if (!injectionsGetter) {
|
|
14931
|
-
return null;
|
|
14932
|
-
}
|
|
14933
|
-
if (typeof injectionsGetter !== "function") {
|
|
14934
|
-
throw new TypeError("injectionsGetter must be a function");
|
|
14935
|
-
}
|
|
14936
|
-
const injections = await injectionsGetter(urlInfo);
|
|
14937
|
-
if (!injections) {
|
|
14938
|
-
return null;
|
|
14939
|
-
}
|
|
14940
|
-
const keys = Object.keys(injections);
|
|
14941
|
-
if (keys.length === 0) {
|
|
14942
|
-
return null;
|
|
14943
|
-
}
|
|
14944
|
-
let someGlobal = false;
|
|
14945
|
-
let someReplacement = false;
|
|
14946
|
-
const globals = {};
|
|
14947
|
-
const replacements = {};
|
|
14948
|
-
for (const key of keys) {
|
|
14949
|
-
const { type, name, value } = createInjection(injections[key], key);
|
|
14950
|
-
if (type === "global") {
|
|
14951
|
-
globals[name] = value;
|
|
14952
|
-
someGlobal = true;
|
|
14953
|
-
} else {
|
|
14954
|
-
replacements[name] = value;
|
|
14955
|
-
someReplacement = true;
|
|
14956
|
-
}
|
|
14957
|
-
}
|
|
14958
|
-
|
|
14959
|
-
if (!someGlobal && !someReplacement) {
|
|
14960
|
-
return null;
|
|
14961
|
-
}
|
|
14962
|
-
|
|
14963
|
-
let content = urlInfo.content;
|
|
14964
|
-
let sourcemap;
|
|
14965
|
-
if (someGlobal) {
|
|
14966
|
-
const globalInjectionResult = injectGlobals(content, globals, urlInfo);
|
|
14967
|
-
content = globalInjectionResult.content;
|
|
14968
|
-
sourcemap = globalInjectionResult.sourcemap;
|
|
14969
|
-
}
|
|
14970
|
-
if (someReplacement) {
|
|
14971
|
-
const replacementResult = replacePlaceholders(
|
|
14972
|
-
content,
|
|
14973
|
-
replacements,
|
|
14974
|
-
urlInfo,
|
|
14975
|
-
);
|
|
14976
|
-
content = replacementResult.content;
|
|
14977
|
-
sourcemap = sourcemap
|
|
14978
|
-
? composeTwoSourcemaps(sourcemap, replacementResult.sourcemap)
|
|
14979
|
-
: replacementResult.sourcemap;
|
|
14980
|
-
}
|
|
14981
|
-
return {
|
|
14982
|
-
content,
|
|
14983
|
-
sourcemap,
|
|
14984
|
-
};
|
|
14985
|
-
},
|
|
14986
|
-
};
|
|
14987
|
-
};
|
|
14988
|
-
|
|
14989
|
-
const wellKnowGlobalNames = ["window", "global", "globalThis", "self"];
|
|
14990
|
-
const createInjection = (value, key) => {
|
|
14991
|
-
for (const wellKnowGlobalName of wellKnowGlobalNames) {
|
|
14992
|
-
const prefix = `${wellKnowGlobalName}.`;
|
|
14993
|
-
if (key.startsWith(prefix)) {
|
|
14994
|
-
return {
|
|
14995
|
-
type: "global",
|
|
14996
|
-
name: key.slice(prefix.length),
|
|
14997
|
-
value,
|
|
14998
|
-
};
|
|
14999
|
-
}
|
|
15000
|
-
}
|
|
15001
|
-
return {
|
|
15002
|
-
type: "replacement",
|
|
15003
|
-
name: key,
|
|
15004
|
-
value,
|
|
15005
|
-
};
|
|
15006
|
-
};
|
|
15007
|
-
|
|
15008
14804
|
const jsenvPluginReferenceExpectedTypes = () => {
|
|
15009
14805
|
const redirectJsReference = (reference) => {
|
|
15010
14806
|
const urlObject = new URL(reference.url);
|
|
@@ -15690,6 +15486,8 @@ const parseAndTransformJsReferences = async (
|
|
|
15690
15486
|
const magicSource = createMagicSource(urlInfo.content);
|
|
15691
15487
|
const parallelActions = [];
|
|
15692
15488
|
const sequentialActions = [];
|
|
15489
|
+
const isNodeJs =
|
|
15490
|
+
Object.keys(urlInfo.context.runtimeCompat).toString() === "node";
|
|
15693
15491
|
|
|
15694
15492
|
const onInlineReference = (inlineReferenceInfo) => {
|
|
15695
15493
|
const inlineUrl = getUrlForContentInsideJs(inlineReferenceInfo, {
|
|
@@ -15737,6 +15535,19 @@ const parseAndTransformJsReferences = async (
|
|
|
15737
15535
|
) {
|
|
15738
15536
|
urlInfo.data.usesImport = true;
|
|
15739
15537
|
}
|
|
15538
|
+
if (
|
|
15539
|
+
isNodeJs &&
|
|
15540
|
+
externalReferenceInfo.type === "js_url" &&
|
|
15541
|
+
externalReferenceInfo.expectedSubtype === "worker" &&
|
|
15542
|
+
externalReferenceInfo.expectedType === "js_classic" &&
|
|
15543
|
+
// TODO: it's true also if closest package.json
|
|
15544
|
+
// is type: module
|
|
15545
|
+
urlToExtension$1(
|
|
15546
|
+
new URL(externalReferenceInfo.specifier, urlInfo.url).href,
|
|
15547
|
+
) === ".mjs"
|
|
15548
|
+
) {
|
|
15549
|
+
externalReferenceInfo.expectedType = "js_module";
|
|
15550
|
+
}
|
|
15740
15551
|
const reference = urlInfo.dependencies.found({
|
|
15741
15552
|
type: externalReferenceInfo.type,
|
|
15742
15553
|
subtype: externalReferenceInfo.subtype,
|
|
@@ -15779,6 +15590,7 @@ const parseAndTransformJsReferences = async (
|
|
|
15779
15590
|
isJsModule: urlInfo.type === "js_module",
|
|
15780
15591
|
isWebWorker: isWebWorkerUrlInfo(urlInfo),
|
|
15781
15592
|
inlineContent,
|
|
15593
|
+
isNodeJs,
|
|
15782
15594
|
});
|
|
15783
15595
|
for (const jsReferenceInfo of jsReferenceInfos) {
|
|
15784
15596
|
if (jsReferenceInfo.isInline) {
|
|
@@ -18353,6 +18165,104 @@ const jsenvPluginProtocolHttp = () => {
|
|
|
18353
18165
|
};
|
|
18354
18166
|
};
|
|
18355
18167
|
|
|
18168
|
+
const jsenvPluginInjections = (rawAssociations) => {
|
|
18169
|
+
let resolvedAssociations;
|
|
18170
|
+
|
|
18171
|
+
return {
|
|
18172
|
+
name: "jsenv:injections",
|
|
18173
|
+
appliesDuring: "*",
|
|
18174
|
+
init: (context) => {
|
|
18175
|
+
resolvedAssociations = URL_META.resolveAssociations(
|
|
18176
|
+
{ injectionsGetter: rawAssociations },
|
|
18177
|
+
context.rootDirectoryUrl,
|
|
18178
|
+
);
|
|
18179
|
+
},
|
|
18180
|
+
transformUrlContent: async (urlInfo) => {
|
|
18181
|
+
const { injectionsGetter } = URL_META.applyAssociations({
|
|
18182
|
+
url: asUrlWithoutSearch(urlInfo.url),
|
|
18183
|
+
associations: resolvedAssociations,
|
|
18184
|
+
});
|
|
18185
|
+
if (!injectionsGetter) {
|
|
18186
|
+
return null;
|
|
18187
|
+
}
|
|
18188
|
+
if (typeof injectionsGetter !== "function") {
|
|
18189
|
+
throw new TypeError("injectionsGetter must be a function");
|
|
18190
|
+
}
|
|
18191
|
+
const injections = await injectionsGetter(urlInfo);
|
|
18192
|
+
if (!injections) {
|
|
18193
|
+
return null;
|
|
18194
|
+
}
|
|
18195
|
+
const keys = Object.keys(injections);
|
|
18196
|
+
if (keys.length === 0) {
|
|
18197
|
+
return null;
|
|
18198
|
+
}
|
|
18199
|
+
return replacePlaceholders(urlInfo.content, injections, urlInfo);
|
|
18200
|
+
},
|
|
18201
|
+
};
|
|
18202
|
+
};
|
|
18203
|
+
|
|
18204
|
+
const injectionSymbol = Symbol.for("jsenv_injection");
|
|
18205
|
+
const INJECTIONS = {
|
|
18206
|
+
optional: (value) => {
|
|
18207
|
+
return { [injectionSymbol]: "optional", value };
|
|
18208
|
+
},
|
|
18209
|
+
};
|
|
18210
|
+
|
|
18211
|
+
// we export this because it is imported by jsenv_plugin_placeholder.js and unit test
|
|
18212
|
+
const replacePlaceholders = (content, replacements, urlInfo) => {
|
|
18213
|
+
const magicSource = createMagicSource(content);
|
|
18214
|
+
for (const key of Object.keys(replacements)) {
|
|
18215
|
+
let index = content.indexOf(key);
|
|
18216
|
+
const replacement = replacements[key];
|
|
18217
|
+
let isOptional;
|
|
18218
|
+
let value;
|
|
18219
|
+
if (replacement && replacement[injectionSymbol]) {
|
|
18220
|
+
const valueBehindSymbol = replacement[injectionSymbol];
|
|
18221
|
+
isOptional = valueBehindSymbol === "optional";
|
|
18222
|
+
value = replacement.value;
|
|
18223
|
+
} else {
|
|
18224
|
+
value = replacement;
|
|
18225
|
+
}
|
|
18226
|
+
if (index === -1) {
|
|
18227
|
+
if (!isOptional) {
|
|
18228
|
+
urlInfo.context.logger.warn(
|
|
18229
|
+
`placeholder "${key}" not found in ${urlInfo.url}.
|
|
18230
|
+
--- suggestion a ---
|
|
18231
|
+
Add "${key}" in that file.
|
|
18232
|
+
--- suggestion b ---
|
|
18233
|
+
Fix eventual typo in "${key}"?
|
|
18234
|
+
--- suggestion c ---
|
|
18235
|
+
Mark injection as optional using INJECTIONS.optional()
|
|
18236
|
+
|
|
18237
|
+
import { INJECTIONS } from "@jsenv/core";
|
|
18238
|
+
|
|
18239
|
+
return {
|
|
18240
|
+
"${key}": INJECTIONS.optional(${JSON.stringify(value)}),
|
|
18241
|
+
}`,
|
|
18242
|
+
);
|
|
18243
|
+
}
|
|
18244
|
+
continue;
|
|
18245
|
+
}
|
|
18246
|
+
|
|
18247
|
+
while (index !== -1) {
|
|
18248
|
+
const start = index;
|
|
18249
|
+
const end = index + key.length;
|
|
18250
|
+
magicSource.replace({
|
|
18251
|
+
start,
|
|
18252
|
+
end,
|
|
18253
|
+
replacement:
|
|
18254
|
+
urlInfo.type === "js_classic" ||
|
|
18255
|
+
urlInfo.type === "js_module" ||
|
|
18256
|
+
urlInfo.type === "html"
|
|
18257
|
+
? JSON.stringify(value, null, " ")
|
|
18258
|
+
: value,
|
|
18259
|
+
});
|
|
18260
|
+
index = content.indexOf(key, end);
|
|
18261
|
+
}
|
|
18262
|
+
}
|
|
18263
|
+
return magicSource.toContentAndSourcemap();
|
|
18264
|
+
};
|
|
18265
|
+
|
|
18356
18266
|
const jsenvPluginInliningAsDataUrl = () => {
|
|
18357
18267
|
return {
|
|
18358
18268
|
name: "jsenv:inlining_as_data_url",
|
|
@@ -18885,9 +18795,9 @@ const babelPluginMetadataImportMetaScenarios = () => {
|
|
|
18885
18795
|
|
|
18886
18796
|
/*
|
|
18887
18797
|
* Source code can contain the following
|
|
18888
|
-
* -
|
|
18889
|
-
* -
|
|
18890
|
-
*
|
|
18798
|
+
* - __DEV__
|
|
18799
|
+
* - __BUILD__
|
|
18800
|
+
* That will be replaced with true/false
|
|
18891
18801
|
*/
|
|
18892
18802
|
|
|
18893
18803
|
|
|
@@ -18896,8 +18806,8 @@ const jsenvPluginGlobalScenarios = () => {
|
|
|
18896
18806
|
return replacePlaceholders(
|
|
18897
18807
|
urlInfo.content,
|
|
18898
18808
|
{
|
|
18899
|
-
__DEV__:
|
|
18900
|
-
__BUILD__:
|
|
18809
|
+
__DEV__: INJECTIONS.optional(urlInfo.context.dev),
|
|
18810
|
+
__BUILD__: INJECTIONS.optional(urlInfo.context.build),
|
|
18901
18811
|
},
|
|
18902
18812
|
urlInfo,
|
|
18903
18813
|
);
|
|
@@ -22982,4 +22892,4 @@ const createBuildFilesService = ({ buildDirectoryUrl, buildMainFilePath }) => {
|
|
|
22982
22892
|
|
|
22983
22893
|
const SECONDS_IN_30_DAYS = 60 * 60 * 24 * 30;
|
|
22984
22894
|
|
|
22985
|
-
export { build, startBuildServer, startDevServer };
|
|
22895
|
+
export { INJECTIONS, build, startBuildServer, startDevServer };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "38.
|
|
3
|
+
"version": "38.2.1",
|
|
4
4
|
"description": "Tool to develop, test and build js projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -61,27 +61,26 @@
|
|
|
61
61
|
"dependencies": {
|
|
62
62
|
"@financial-times/polyfill-useragent-normaliser": "1.10.2",
|
|
63
63
|
"@jsenv/abort": "4.2.4",
|
|
64
|
-
"@jsenv/ast": "5.1.
|
|
64
|
+
"@jsenv/ast": "5.1.3",
|
|
65
65
|
"@jsenv/filesystem": "4.2.6",
|
|
66
66
|
"@jsenv/importmap": "1.2.1",
|
|
67
67
|
"@jsenv/integrity": "0.0.1",
|
|
68
68
|
"@jsenv/log": "3.4.0",
|
|
69
69
|
"@jsenv/node-esm-resolution": "1.0.1",
|
|
70
|
-
"@jsenv/js-module-fallback": "1.3.
|
|
70
|
+
"@jsenv/js-module-fallback": "1.3.4",
|
|
71
71
|
"@jsenv/runtime-compat": "1.2.0",
|
|
72
|
-
"@jsenv/server": "15.1.
|
|
73
|
-
"@jsenv/sourcemap": "1.2.
|
|
74
|
-
"@jsenv/plugin-
|
|
75
|
-
"@jsenv/plugin-
|
|
76
|
-
"@jsenv/plugin-
|
|
77
|
-
"@jsenv/plugin-
|
|
78
|
-
"@jsenv/plugin-supervisor": "1.3.2",
|
|
72
|
+
"@jsenv/server": "15.1.1",
|
|
73
|
+
"@jsenv/sourcemap": "1.2.2",
|
|
74
|
+
"@jsenv/plugin-bundling": "2.5.3",
|
|
75
|
+
"@jsenv/plugin-minification": "1.5.1",
|
|
76
|
+
"@jsenv/plugin-transpilation": "1.3.3",
|
|
77
|
+
"@jsenv/plugin-supervisor": "1.3.3",
|
|
79
78
|
"@jsenv/url-meta": "8.1.0",
|
|
80
79
|
"@jsenv/urls": "2.2.1",
|
|
81
80
|
"@jsenv/utils": "2.0.1"
|
|
82
81
|
},
|
|
83
82
|
"devDependencies": {
|
|
84
|
-
"@babel/eslint-parser": "7.22.
|
|
83
|
+
"@babel/eslint-parser": "7.22.15",
|
|
85
84
|
"@babel/plugin-syntax-import-assertions": "7.22.5",
|
|
86
85
|
"babel-plugin-transform-async-to-promises": "0.8.18",
|
|
87
86
|
"@jsenv/assert": "./packages/independent/assert/",
|
|
@@ -93,12 +92,12 @@
|
|
|
93
92
|
"@jsenv/performance-impact": "4.1.1",
|
|
94
93
|
"@jsenv/plugin-as-js-classic": "./packages/related/plugin-as-js-classic/",
|
|
95
94
|
"@jsenv/test": "./packages/related/test/",
|
|
96
|
-
"eslint": "8.
|
|
95
|
+
"eslint": "8.49.0",
|
|
97
96
|
"eslint-plugin-html": "7.1.0",
|
|
98
|
-
"eslint-plugin-import": "2.28.
|
|
99
|
-
"eslint-plugin-react": "7.33.
|
|
97
|
+
"eslint-plugin-import": "2.28.1",
|
|
98
|
+
"eslint-plugin-react": "7.33.2",
|
|
100
99
|
"open": "9.1.0",
|
|
101
|
-
"playwright": "1.
|
|
102
|
-
"prettier": "3.0.
|
|
100
|
+
"playwright": "1.37.1",
|
|
101
|
+
"prettier": "3.0.3"
|
|
103
102
|
}
|
|
104
103
|
}
|
package/src/main.js
CHANGED
|
@@ -3,3 +3,6 @@ export { startDevServer } from "./dev/start_dev_server.js";
|
|
|
3
3
|
// build
|
|
4
4
|
export { build } from "./build/build.js";
|
|
5
5
|
export { startBuildServer } from "./build/start_build_server.js";
|
|
6
|
+
|
|
7
|
+
// others
|
|
8
|
+
export { INJECTIONS } from "./plugins/injections/jsenv_plugin_injections.js";
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Source code can contain the following
|
|
3
|
-
* -
|
|
4
|
-
* -
|
|
5
|
-
*
|
|
3
|
+
* - __DEV__
|
|
4
|
+
* - __BUILD__
|
|
5
|
+
* That will be replaced with true/false
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
replacePlaceholders,
|
|
10
|
+
INJECTIONS,
|
|
11
|
+
} from "../injections/jsenv_plugin_injections.js";
|
|
9
12
|
|
|
10
13
|
export const jsenvPluginGlobalScenarios = () => {
|
|
11
14
|
const transformIfNeeded = (urlInfo) => {
|
|
12
15
|
return replacePlaceholders(
|
|
13
16
|
urlInfo.content,
|
|
14
17
|
{
|
|
15
|
-
__DEV__:
|
|
16
|
-
__BUILD__:
|
|
18
|
+
__DEV__: INJECTIONS.optional(urlInfo.context.dev),
|
|
19
|
+
__BUILD__: INJECTIONS.optional(urlInfo.context.build),
|
|
17
20
|
},
|
|
18
21
|
urlInfo,
|
|
19
22
|
);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createMagicSource } from "@jsenv/sourcemap";
|
|
2
|
+
import {
|
|
3
|
+
parseHtmlString,
|
|
4
|
+
injectHtmlNodeAsEarlyAsPossible,
|
|
5
|
+
createHtmlNode,
|
|
6
|
+
stringifyHtmlAst,
|
|
7
|
+
} from "@jsenv/ast";
|
|
8
|
+
|
|
9
|
+
export const injectGlobals = (content, globals, urlInfo) => {
|
|
10
|
+
if (urlInfo.type === "html") {
|
|
11
|
+
return globalInjectorOnHtml(content, globals, urlInfo);
|
|
12
|
+
}
|
|
13
|
+
if (urlInfo.type === "js_classic" || urlInfo.type === "js_module") {
|
|
14
|
+
return globalsInjectorOnJs(content, globals, urlInfo);
|
|
15
|
+
}
|
|
16
|
+
throw new Error(`cannot inject globals into "${urlInfo.type}"`);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const globalInjectorOnHtml = (content, globals) => {
|
|
20
|
+
// ideally we would inject an importmap but browser support is too low
|
|
21
|
+
// (even worse for worker/service worker)
|
|
22
|
+
// so for now we inject code into entry points
|
|
23
|
+
const htmlAst = parseHtmlString(content, {
|
|
24
|
+
storeOriginalPositions: false,
|
|
25
|
+
});
|
|
26
|
+
const clientCode = generateClientCodeForGlobals(globals, {
|
|
27
|
+
isWebWorker: false,
|
|
28
|
+
});
|
|
29
|
+
injectHtmlNodeAsEarlyAsPossible(
|
|
30
|
+
htmlAst,
|
|
31
|
+
createHtmlNode({
|
|
32
|
+
tagName: "script",
|
|
33
|
+
textContent: clientCode,
|
|
34
|
+
}),
|
|
35
|
+
"jsenv:inject_globals",
|
|
36
|
+
);
|
|
37
|
+
return stringifyHtmlAst(htmlAst);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const globalsInjectorOnJs = (content, globals, urlInfo) => {
|
|
41
|
+
const clientCode = generateClientCodeForGlobals(globals, {
|
|
42
|
+
isWebWorker:
|
|
43
|
+
urlInfo.subtype === "worker" ||
|
|
44
|
+
urlInfo.subtype === "service_worker" ||
|
|
45
|
+
urlInfo.subtype === "shared_worker",
|
|
46
|
+
});
|
|
47
|
+
const magicSource = createMagicSource(content);
|
|
48
|
+
magicSource.prepend(clientCode);
|
|
49
|
+
return magicSource.toContentAndSourcemap();
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const generateClientCodeForGlobals = (globals, { isWebWorker = false }) => {
|
|
53
|
+
const globalName = isWebWorker ? "self" : "window";
|
|
54
|
+
return `Object.assign(${globalName}, ${JSON.stringify(
|
|
55
|
+
globals,
|
|
56
|
+
null,
|
|
57
|
+
" ",
|
|
58
|
+
)});`;
|
|
59
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { URL_META } from "@jsenv/url-meta";
|
|
2
|
+
import { asUrlWithoutSearch } from "@jsenv/urls";
|
|
3
|
+
import { createMagicSource } from "@jsenv/sourcemap";
|
|
4
|
+
|
|
5
|
+
export const jsenvPluginInjections = (rawAssociations) => {
|
|
6
|
+
let resolvedAssociations;
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
name: "jsenv:injections",
|
|
10
|
+
appliesDuring: "*",
|
|
11
|
+
init: (context) => {
|
|
12
|
+
resolvedAssociations = URL_META.resolveAssociations(
|
|
13
|
+
{ injectionsGetter: rawAssociations },
|
|
14
|
+
context.rootDirectoryUrl,
|
|
15
|
+
);
|
|
16
|
+
},
|
|
17
|
+
transformUrlContent: async (urlInfo) => {
|
|
18
|
+
const { injectionsGetter } = URL_META.applyAssociations({
|
|
19
|
+
url: asUrlWithoutSearch(urlInfo.url),
|
|
20
|
+
associations: resolvedAssociations,
|
|
21
|
+
});
|
|
22
|
+
if (!injectionsGetter) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
if (typeof injectionsGetter !== "function") {
|
|
26
|
+
throw new TypeError("injectionsGetter must be a function");
|
|
27
|
+
}
|
|
28
|
+
const injections = await injectionsGetter(urlInfo);
|
|
29
|
+
if (!injections) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
const keys = Object.keys(injections);
|
|
33
|
+
if (keys.length === 0) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return replacePlaceholders(urlInfo.content, injections, urlInfo);
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const injectionSymbol = Symbol.for("jsenv_injection");
|
|
42
|
+
export const INJECTIONS = {
|
|
43
|
+
optional: (value) => {
|
|
44
|
+
return { [injectionSymbol]: "optional", value };
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// we export this because it is imported by jsenv_plugin_placeholder.js and unit test
|
|
49
|
+
export const replacePlaceholders = (content, replacements, urlInfo) => {
|
|
50
|
+
const magicSource = createMagicSource(content);
|
|
51
|
+
for (const key of Object.keys(replacements)) {
|
|
52
|
+
let index = content.indexOf(key);
|
|
53
|
+
const replacement = replacements[key];
|
|
54
|
+
let isOptional;
|
|
55
|
+
let value;
|
|
56
|
+
if (replacement && replacement[injectionSymbol]) {
|
|
57
|
+
const valueBehindSymbol = replacement[injectionSymbol];
|
|
58
|
+
isOptional = valueBehindSymbol === "optional";
|
|
59
|
+
value = replacement.value;
|
|
60
|
+
} else {
|
|
61
|
+
value = replacement;
|
|
62
|
+
}
|
|
63
|
+
if (index === -1) {
|
|
64
|
+
if (!isOptional) {
|
|
65
|
+
urlInfo.context.logger.warn(
|
|
66
|
+
`placeholder "${key}" not found in ${urlInfo.url}.
|
|
67
|
+
--- suggestion a ---
|
|
68
|
+
Add "${key}" in that file.
|
|
69
|
+
--- suggestion b ---
|
|
70
|
+
Fix eventual typo in "${key}"?
|
|
71
|
+
--- suggestion c ---
|
|
72
|
+
Mark injection as optional using INJECTIONS.optional()
|
|
73
|
+
|
|
74
|
+
import { INJECTIONS } from "@jsenv/core";
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
"${key}": INJECTIONS.optional(${JSON.stringify(value)}),
|
|
78
|
+
}`,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
while (index !== -1) {
|
|
85
|
+
const start = index;
|
|
86
|
+
const end = index + key.length;
|
|
87
|
+
magicSource.replace({
|
|
88
|
+
start,
|
|
89
|
+
end,
|
|
90
|
+
replacement:
|
|
91
|
+
urlInfo.type === "js_classic" ||
|
|
92
|
+
urlInfo.type === "js_module" ||
|
|
93
|
+
urlInfo.type === "html"
|
|
94
|
+
? JSON.stringify(value, null, " ")
|
|
95
|
+
: value,
|
|
96
|
+
});
|
|
97
|
+
index = content.indexOf(key, end);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return magicSource.toContentAndSourcemap();
|
|
101
|
+
};
|
package/src/plugins/plugins.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { jsenvPluginSupervisor } from "@jsenv/plugin-supervisor";
|
|
2
|
-
import { jsenvPluginInjections } from "@jsenv/plugin-injections";
|
|
3
2
|
import { jsenvPluginTranspilation } from "@jsenv/plugin-transpilation";
|
|
4
3
|
|
|
5
4
|
import { jsenvPluginReferenceAnalysis } from "./reference_analysis/jsenv_plugin_reference_analysis.js";
|
|
@@ -9,6 +8,7 @@ import { jsenvPluginWebResolution } from "./resolution_web/jsenv_plugin_web_reso
|
|
|
9
8
|
import { jsenvPluginVersionSearchParam } from "./version_search_param/jsenv_plugin_version_search_param.js";
|
|
10
9
|
import { jsenvPluginProtocolFile } from "./protocol_file/jsenv_plugin_protocol_file.js";
|
|
11
10
|
import { jsenvPluginProtocolHttp } from "./protocol_http/jsenv_plugin_protocol_http.js";
|
|
11
|
+
import { jsenvPluginInjections } from "./injections/jsenv_plugin_injections.js";
|
|
12
12
|
import { jsenvPluginInlining } from "./inlining/jsenv_plugin_inlining.js";
|
|
13
13
|
import { jsenvPluginCommonJsGlobals } from "./commonjs_globals/jsenv_plugin_commonjs_globals.js";
|
|
14
14
|
import { jsenvPluginImportMetaScenarios } from "./import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createMagicSource } from "@jsenv/sourcemap";
|
|
2
2
|
import { parseJsUrls, getUrlForContentInsideJs } from "@jsenv/ast";
|
|
3
|
+
import { urlToExtension } from "@jsenv/urls";
|
|
3
4
|
import { JS_QUOTES } from "@jsenv/utils/src/string/js_quotes.js";
|
|
4
5
|
|
|
5
6
|
import { isWebWorkerUrlInfo } from "@jsenv/core/src/kitchen/web_workers.js";
|
|
@@ -34,6 +35,8 @@ const parseAndTransformJsReferences = async (
|
|
|
34
35
|
const magicSource = createMagicSource(urlInfo.content);
|
|
35
36
|
const parallelActions = [];
|
|
36
37
|
const sequentialActions = [];
|
|
38
|
+
const isNodeJs =
|
|
39
|
+
Object.keys(urlInfo.context.runtimeCompat).toString() === "node";
|
|
37
40
|
|
|
38
41
|
const onInlineReference = (inlineReferenceInfo) => {
|
|
39
42
|
const inlineUrl = getUrlForContentInsideJs(inlineReferenceInfo, {
|
|
@@ -81,6 +84,19 @@ const parseAndTransformJsReferences = async (
|
|
|
81
84
|
) {
|
|
82
85
|
urlInfo.data.usesImport = true;
|
|
83
86
|
}
|
|
87
|
+
if (
|
|
88
|
+
isNodeJs &&
|
|
89
|
+
externalReferenceInfo.type === "js_url" &&
|
|
90
|
+
externalReferenceInfo.expectedSubtype === "worker" &&
|
|
91
|
+
externalReferenceInfo.expectedType === "js_classic" &&
|
|
92
|
+
// TODO: it's true also if closest package.json
|
|
93
|
+
// is type: module
|
|
94
|
+
urlToExtension(
|
|
95
|
+
new URL(externalReferenceInfo.specifier, urlInfo.url).href,
|
|
96
|
+
) === ".mjs"
|
|
97
|
+
) {
|
|
98
|
+
externalReferenceInfo.expectedType = "js_module";
|
|
99
|
+
}
|
|
84
100
|
const reference = urlInfo.dependencies.found({
|
|
85
101
|
type: externalReferenceInfo.type,
|
|
86
102
|
subtype: externalReferenceInfo.subtype,
|
|
@@ -123,6 +139,7 @@ const parseAndTransformJsReferences = async (
|
|
|
123
139
|
isJsModule: urlInfo.type === "js_module",
|
|
124
140
|
isWebWorker: isWebWorkerUrlInfo(urlInfo),
|
|
125
141
|
inlineContent,
|
|
142
|
+
isNodeJs,
|
|
126
143
|
});
|
|
127
144
|
for (const jsReferenceInfo of jsReferenceInfos) {
|
|
128
145
|
if (jsReferenceInfo.isInline) {
|