@jsenv/core 25.4.4 → 25.5.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 (26) hide show
  1. package/dist/build_manifest.js +2 -2
  2. package/dist/toolbar/asset-manifest.json +5 -5
  3. package/dist/toolbar/assets/{compilation.css_e37c747b.map → compilation.css_7421bd55.map} +3 -3
  4. package/dist/toolbar/assets/settings.css_942b5a9e.map +12 -0
  5. package/dist/toolbar/assets/{toolbar.main.css_269d7ce2.map → toolbar.main.css_b7d8bec1.map} +4 -4
  6. package/dist/toolbar/{toolbar.main_279b3a68.js.map → toolbar.main_2c56a4e0.js.map} +24 -12
  7. package/dist/toolbar/{toolbar_0a91ca3b.html → toolbar_9a52325b.html} +97 -63
  8. package/dist/toolbar_injector/asset-manifest.json +2 -2
  9. package/dist/toolbar_injector/{toolbar_injector_34f6ad8e.js → toolbar_injector_1e193101.js} +2 -2
  10. package/dist/toolbar_injector/{toolbar_injector_34f6ad8e.js.map → toolbar_injector_1e193101.js.map} +2 -2
  11. package/package.json +5 -3
  12. package/src/buildProject.js +9 -6
  13. package/src/executeTestPlan.js +20 -19
  14. package/src/internal/compiling/jsenv_directory/compile_context.js +4 -3
  15. package/src/internal/compiling/jsenv_directory/jsenv_directory.js +1 -1
  16. package/src/internal/dev_server/toolbar/compilation/compilation.css +3 -2
  17. package/src/internal/dev_server/toolbar/compilation/toolbar.compilation.js +19 -19
  18. package/src/internal/dev_server/toolbar/notification/toolbar.notification.js +66 -37
  19. package/src/internal/dev_server/toolbar/settings/settings.css +1 -2
  20. package/src/internal/dev_server/toolbar/toolbar.html +9 -5
  21. package/src/internal/dev_server/toolbar/toolbar.main.js +5 -3
  22. package/src/internal/dev_server/toolbar/util/iframe_to_parent_href.js +10 -0
  23. package/src/internal/executing/executePlan.js +450 -60
  24. package/src/internal/runtime_support/runtime_support.js +1 -1
  25. package/dist/toolbar/assets/settings.css_61548139.map +0 -12
  26. package/src/internal/executing/executeConcurrently.js +0 -440
@@ -96,8 +96,9 @@
96
96
  }
97
97
  .browser_support_text[data-warning],
98
98
  .files_compilation_text[data-warning] {
99
- background: orange;
100
- color: black;
99
+ color: #cb5909;
100
+ margin-bottom: 5px;
101
+ display: block;
101
102
  }
102
103
  button:focus,
103
104
  a:focus,
@@ -283,8 +284,7 @@ Because for some element we set the focus outline on a div which would not match
283
284
  position: relative;
284
285
  }
285
286
  #settings-button[data-warning] svg {
286
- fill: orange;
287
- stroke: darkorange;
287
+ fill: #cb5909;
288
288
  }
289
289
  #settings-button[data-warning] svg:hover {
290
290
  fill: darkorange !important;
@@ -790,7 +790,7 @@ html[data-toolbar-visible] #toolbar-trigger {
790
790
  color: inherit;
791
791
  }
792
792
 
793
- /*# sourceMappingURL=assets/toolbar.main.css_269d7ce2.map */</style>
793
+ /*# sourceMappingURL=assets/toolbar.main.css_b7d8bec1.map */</style>
794
794
  <script id="jsenv_inject_systemjs">/*
795
795
  * SJS 6.11.0
796
796
  * Minimal SystemJS Build
@@ -1821,7 +1821,7 @@ html[data-toolbar-visible] #toolbar-trigger {
1821
1821
  <div class="category-subtitle">
1822
1822
  Send system notification when execution fails or is fixed.
1823
1823
  <div class="notification-text">
1824
- <a data-when="notif_permission:no" class="request_notification_permission" href="javascript:void(0);">Enable notification</a>
1824
+ <a data-when="notif_granted:no" class="request_notification_permission" href="javascript:void(0);">Enable notification</a>
1825
1825
  </div>
1826
1826
  </div>
1827
1827
  </div>
@@ -1929,8 +1929,11 @@ html[data-toolbar-visible] #toolbar-trigger {
1929
1929
  </div>
1930
1930
  <button id="settings-button" class="toolbar-icon-wrapper">
1931
1931
  <div data-when="has_warning:yes">
1932
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 511.999 511.999" width="24px" height="24px" class="iconToolbar">
1933
- <path d="M506.43 421.536 291.573 49.394c-15.814-27.391-55.327-27.401-71.147 0L5.568 421.536c-15.814 27.391 3.934 61.616 35.574 61.616h429.714c31.629.001 51.394-34.214 35.574-61.616zm-231.609-36.502c0 10.394-8.427 18.821-18.821 18.821s-18.821-8.427-18.821-18.821v-11.239c0-10.394 8.427-18.821 18.821-18.821s18.821 8.427 18.821 18.821v11.239zm0-73.332c0 10.394-8.427 18.821-18.821 18.821s-18.821-8.427-18.821-18.821v-107.89c0-10.394 8.427-18.821 18.821-18.821s18.821 8.427 18.821 18.821v107.89z"></path>
1932
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 45.818 45.818" width="20px" height="20px" class="iconToolbar" style="transform: rotate(180deg)">
1933
+ <path d="M22.909,0C10.258,0,0,10.257,0,22.908c0,12.652,10.258,22.91,22.909,22.91s22.909-10.258,22.909-22.91
1934
+ C45.818,10.257,35.561,0,22.909,0z M26.411,35.417c0,1.921-1.573,3.478-3.492,3.478c-1.92,0-3.492-1.557-3.492-3.478V20.201
1935
+ c0-1.92,1.572-3.477,3.492-3.477c1.919,0,3.492,1.556,3.492,3.477V35.417z M22.909,13.851c-2.119,0-3.837-1.718-3.837-3.836
1936
+ c0-2.12,1.718-3.836,3.837-3.836c2.118,0,3.837,1.716,3.837,3.836C26.746,12.133,25.027,13.851,22.909,13.851z"></path>
1934
1937
  </svg>
1935
1938
  </div>
1936
1939
  <div data-when="has_warning:no">
@@ -2426,6 +2429,19 @@ html[data-toolbar-visible] #toolbar-trigger {
2426
2429
  document.documentElement.setAttribute("data-last-interaction", "keyboard");
2427
2430
  });
2428
2431
 
2432
+ var setLinkHrefForParentWindow = function setLinkHrefForParentWindow(a, href) {
2433
+ a.href = href;
2434
+
2435
+ a.onclick = function (e) {
2436
+ if (e.ctrlKey || e.metaKey) {
2437
+ return;
2438
+ }
2439
+
2440
+ e.preventDefault();
2441
+ window.parent.location.href = href;
2442
+ };
2443
+ };
2444
+
2429
2445
  var createPreference = function createPreference(name) {
2430
2446
  return {
2431
2447
  has: function has() {
@@ -2671,56 +2687,88 @@ html[data-toolbar-visible] #toolbar-trigger {
2671
2687
  var arrayOfOpenedNotifications = [];
2672
2688
 
2673
2689
  var renderToolbarNotification = function renderToolbarNotification() {
2674
- var notifCheckbox = document.querySelector("#toggle-notifs");
2675
-
2676
2690
  if (!notificationAvailable) {
2677
- var notifSetting = document.querySelector(".settings-notification");
2678
- notifSetting.setAttribute("data-disabled", "true");
2679
- notifSetting.setAttribute("title", "Notification not available in the browser");
2680
- notifCheckbox.disabled = true;
2691
+ applyNotificationNotAvailableEffects();
2681
2692
  return;
2682
2693
  }
2683
2694
 
2684
- var updatePermission = function updatePermission() {
2685
- if (Notification.permission === "denied") {
2686
- var _notifSetting = document.querySelector(".settings-notification");
2695
+ updatePermission();
2696
+ };
2687
2697
 
2688
- _notifSetting.setAttribute("data-disabled", "true");
2698
+ var updatePermission = function updatePermission() {
2699
+ var notifPermission = Notification.permission;
2689
2700
 
2690
- _notifSetting.setAttribute("title", "Notification denied");
2701
+ if (notifPermission === "default") {
2702
+ applyNotificationDefaultEffects();
2703
+ return;
2704
+ }
2691
2705
 
2692
- notifCheckbox.disabled = true;
2693
- return;
2694
- }
2706
+ if (notifPermission === "denied") {
2707
+ applyNotificationDeniedEffects();
2708
+ return;
2709
+ }
2695
2710
 
2696
- notifCheckbox.checked = getNotificationPreference();
2711
+ if (notifPermission === "granted") {
2712
+ applyNotificationGrantedEffects();
2713
+ return;
2714
+ }
2715
+ };
2697
2716
 
2698
- notifCheckbox.onchange = function () {
2699
- setNotificationPreference(notifCheckbox.checked);
2717
+ var notifCheckbox = document.querySelector("#toggle-notifs");
2700
2718
 
2701
- if (!notifCheckbox.checked) {
2702
- // slice because arrayOfOpenedNotifications can be mutated while looping
2703
- arrayOfOpenedNotifications.slice().forEach(function (notification) {
2704
- notification.close();
2705
- });
2706
- }
2707
- };
2719
+ var applyNotificationNotAvailableEffects = function applyNotificationNotAvailableEffects() {
2720
+ var notifSetting = document.querySelector(".settings-notification");
2721
+ notifSetting.setAttribute("data-disabled", "true");
2722
+ notifSetting.setAttribute("title", "Notification not available in the browser");
2723
+ notifCheckbox.disabled = true;
2724
+ };
2708
2725
 
2709
- var notifPermission = Notification.permission;
2710
- enableVariant(document.querySelector(".notification-text"), {
2711
- notif_permission: notifPermission === "granted" ? "yes" : "no"
2712
- });
2726
+ var applyNotificationDefaultEffects = function applyNotificationDefaultEffects() {
2727
+ applyNotificationNOTGrantedEffects();
2728
+ var notifSetting = document.querySelector(".settings-notification");
2729
+ notifSetting.removeAttribute("data-disabled");
2730
+ notifSetting.removeAttribute("title");
2731
+ };
2713
2732
 
2714
- if (notifPermission === "default") {
2715
- document.querySelector("a.request_notification_permission").onclick = function () {
2716
- requestPermission().then(function () {
2717
- updatePermission();
2718
- });
2719
- };
2733
+ var applyNotificationDeniedEffects = function applyNotificationDeniedEffects() {
2734
+ applyNotificationNOTGrantedEffects();
2735
+ var notifSetting = document.querySelector(".settings-notification");
2736
+ notifSetting.setAttribute("data-disabled", "true");
2737
+ notifSetting.setAttribute("title", "Notification denied");
2738
+ };
2739
+
2740
+ var applyNotificationGrantedEffects = function applyNotificationGrantedEffects() {
2741
+ enableVariant(document.querySelector(".notification-text"), {
2742
+ notif_granted: "yes"
2743
+ });
2744
+ notifCheckbox.disabled = false;
2745
+ notifCheckbox.checked = getNotificationPreference();
2746
+
2747
+ notifCheckbox.onchange = function () {
2748
+ setNotificationPreference(notifCheckbox.checked);
2749
+
2750
+ if (!notifCheckbox.checked) {
2751
+ // slice because arrayOfOpenedNotifications can be mutated while looping
2752
+ arrayOfOpenedNotifications.slice().forEach(function (notification) {
2753
+ notification.close();
2754
+ });
2720
2755
  }
2721
2756
  };
2757
+ };
2722
2758
 
2723
- updatePermission();
2759
+ var applyNotificationNOTGrantedEffects = function applyNotificationNOTGrantedEffects() {
2760
+ enableVariant(document.querySelector(".notification-text"), {
2761
+ notif_granted: "no"
2762
+ });
2763
+ notifCheckbox.disabled = true;
2764
+ notifCheckbox.checked = false;
2765
+
2766
+ document.querySelector("a.request_notification_permission").onclick = function () {
2767
+ requestPermission().then(function () {
2768
+ setNotificationPreference(true);
2769
+ updatePermission();
2770
+ });
2771
+ };
2724
2772
  };
2725
2773
 
2726
2774
  var notifyExecutionResult = function notifyExecutionResult(executedFileRelativeUrl, execution, previousExecution) {
@@ -4426,21 +4474,10 @@ html[data-toolbar-visible] #toolbar-trigger {
4426
4474
  document.querySelector(".files_compilation_text").innerHTML = "Files shown are compiled for ".concat(runtimeReport.name, "@").concat(runtimeReport.version);
4427
4475
  }
4428
4476
 
4429
- filesCompilationRootNode.querySelector("a.link_to_source_files").onclick = function () {
4430
- window.parent.location.href = "/".concat(compileGroup.fileRelativeUrl);
4431
- };
4432
-
4433
- filesCompilationRootNode.querySelector("a.link_to_compiled_files").onclick = function () {
4434
- window.parent.location.href = "/".concat(jsenvDirectoryRelativeUrl).concat(expectedCompiledId, "/").concat(compileGroup.fileRelativeUrl);
4435
- };
4436
-
4437
- filesCompilationRootNode.querySelector("a.link_to_compilation_forced_files").onclick = function () {
4438
- window.parent.location.href = "/".concat(jsenvDirectoryRelativeUrl, "force/").concat(compileGroup.fileRelativeUrl);
4439
- };
4440
-
4441
- filesCompilationRootNode.querySelector("a.link_to_appropriate_files").onclick = function () {
4442
- window.parent.location.href = "/".concat(jsenvDirectoryRelativeUrl).concat(expectedCompiledId, "/").concat(compileGroup.fileRelativeUrl);
4443
- };
4477
+ setLinkHrefForParentWindow(filesCompilationRootNode.querySelector("a.link_to_source_files"), "/".concat(compileGroup.fileRelativeUrl));
4478
+ setLinkHrefForParentWindow(filesCompilationRootNode.querySelector("a.link_to_compiled_files"), "/".concat(jsenvDirectoryRelativeUrl).concat(expectedCompiledId, "/").concat(compileGroup.fileRelativeUrl));
4479
+ setLinkHrefForParentWindow(filesCompilationRootNode.querySelector("a.link_to_compilation_forced_files"), "/".concat(jsenvDirectoryRelativeUrl, "force/").concat(compileGroup.fileRelativeUrl));
4480
+ setLinkHrefForParentWindow(filesCompilationRootNode.querySelector("a.link_to_appropriate_files"), "/".concat(jsenvDirectoryRelativeUrl).concat(expectedCompiledId, "/").concat(compileGroup.fileRelativeUrl));
4444
4481
 
4445
4482
  if (hasWarning) {
4446
4483
  enableWarningStyle();
@@ -4739,10 +4776,7 @@ html[data-toolbar-visible] #toolbar-trigger {
4739
4776
  });
4740
4777
  }
4741
4778
 
4742
- document.querySelector(".toolbar-icon-wrapper").onclick = function () {
4743
- window.parent.location.href = "/";
4744
- };
4745
-
4779
+ setLinkHrefForParentWindow(document.querySelector(".toolbar-icon-wrapper"), "/");
4746
4780
  renderToolbarNotification();
4747
4781
  makeToolbarResponsive();
4748
4782
  renderToolbarSettings();
@@ -4935,7 +4969,7 @@ html[data-toolbar-visible] #toolbar-trigger {
4935
4969
  };
4936
4970
  });
4937
4971
 
4938
- //# sourceMappingURL=toolbar.main_279b3a68.js.map</script>
4972
+ //# sourceMappingURL=toolbar.main_2c56a4e0.js.map</script>
4939
4973
 
4940
4974
 
4941
4975
  </body></html>
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "assets/jsenv-logo.svg": "assets/jsenv-logo_188b9ca6.svg",
3
- "toolbar_injector.js": "toolbar_injector_34f6ad8e.js",
4
- "toolbar_injector.js.map": "toolbar_injector_34f6ad8e.js.map"
3
+ "toolbar_injector.js": "toolbar_injector_1e193101.js",
4
+ "toolbar_injector.js.map": "toolbar_injector_1e193101.js.map"
5
5
  }
@@ -746,7 +746,7 @@
746
746
  return then ? value.then(then) : value;
747
747
  }
748
748
 
749
- var TOOLBAR_BUILD_RELATIVE_URL = "dist/toolbar/toolbar_0a91ca3b.html";
749
+ var TOOLBAR_BUILD_RELATIVE_URL = "dist/toolbar/toolbar_9a52325b.html";
750
750
 
751
751
  function _call(body, then, direct) {
752
752
  if (direct) {
@@ -973,4 +973,4 @@
973
973
 
974
974
  })();
975
975
 
976
- //# sourceMappingURL=toolbar_injector_34f6ad8e.js.map
976
+ //# sourceMappingURL=toolbar_injector_1e193101.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
- "file": "toolbar_injector_34f6ad8e.js",
3
+ "file": "toolbar_injector_1e193101.js",
4
4
  "sources": [
5
5
  "../../helpers/babel/typeof/typeof.js",
6
6
  "../../helpers/babel/defineProperty/defineProperty.js",
@@ -25,7 +25,7 @@
25
25
  "import { fetchUrl } from \"./fetch_browser.js\"\n\nexport const fetchJson = async (url, options = {}) => {\n const response = await fetchUrl(url, options)\n const object = await response.json()\n return object\n}\n",
26
26
  "import { fetchJson } from \"../../browser_utils/fetchJson.js\"\n\nexport const fetchExploringJson = async ({ signal } = {}) => {\n try {\n const exploringInfo = await fetchJson(\"/.jsenv/exploring.json\", {\n signal,\n })\n return exploringInfo\n } catch (e) {\n if (signal && signal.aborted && e.name === \"AbortError\") {\n throw e\n }\n throw new Error(\n `Cannot communicate with exploring server due to a network error\n--- error stack ---\n${e.stack}`,\n )\n }\n}\n",
27
27
  "export const updateIframeOverflowOnParentWindow = () => {\n if (!window.parent) {\n // can happen while parent iframe reloads\n return\n }\n\n const aTooltipIsOpened =\n document.querySelector(\"[data-tooltip-visible]\") ||\n document.querySelector(\"[data-tooltip-auto-visible]\")\n const settingsAreOpened = document.querySelector(\"#settings[data-active]\")\n\n if (aTooltipIsOpened || settingsAreOpened) {\n enableIframeOverflowOnParentWindow()\n } else {\n disableIframeOverflowOnParentWindow()\n }\n}\n\nlet iframeOverflowEnabled = false\nconst enableIframeOverflowOnParentWindow = () => {\n if (iframeOverflowEnabled) return\n iframeOverflowEnabled = true\n\n const iframe = getToolbarIframe()\n const transitionDuration = iframe.style.transitionDuration\n setStyles(iframe, { \"height\": \"100%\", \"transition-duration\": \"0ms\" })\n if (transitionDuration) {\n setTimeout(() => {\n setStyles(iframe, { \"transition-duration\": transitionDuration })\n })\n }\n}\n\nconst disableIframeOverflowOnParentWindow = () => {\n if (!iframeOverflowEnabled) return\n iframeOverflowEnabled = false\n\n const iframe = getToolbarIframe()\n const transitionDuration = iframe.style.transitionDuration\n setStyles(iframe, { \"height\": \"40px\", \"transition-duration\": \"0ms\" })\n if (transitionDuration) {\n setTimeout(() => {\n setStyles(iframe, { \"transition-duration\": transitionDuration })\n })\n }\n}\n\nexport const getToolbarIframe = () => {\n const iframes = Array.from(window.parent.document.querySelectorAll(\"iframe\"))\n return iframes.find((iframe) => iframe.contentWindow === window)\n}\n\nexport const forceHideElement = (element) => {\n element.setAttribute(\"data-force-hide\", \"\")\n}\n\nexport const removeForceHideElement = (element) => {\n element.removeAttribute(\"data-force-hide\")\n}\n\nexport const setStyles = (element, styles) => {\n const elementStyle = element.style\n const restoreStyles = Object.keys(styles).map((styleName) => {\n let restore\n if (styleName in elementStyle) {\n const currentStyle = elementStyle[styleName]\n restore = () => {\n elementStyle[styleName] = currentStyle\n }\n } else {\n restore = () => {\n delete elementStyle[styleName]\n }\n }\n\n elementStyle[styleName] = styles[styleName]\n\n return restore\n })\n return () => {\n restoreStyles.forEach((restore) => restore())\n }\n}\n\nexport const setAttributes = (element, attributes) => {\n Object.keys(attributes).forEach((name) => {\n element.setAttribute(name, attributes[name])\n })\n}\n\nexport const getDocumentScroll = () => {\n return {\n x: document.documentElement.scrollLeft,\n y: document.documentElement.scrollTop,\n }\n}\n\nexport const toolbarSectionIsActive = (element) => {\n return element.hasAttribute(\"data-active\")\n}\n\nexport const activateToolbarSection = (element) => {\n element.setAttribute(\"data-active\", \"\")\n}\n\nexport const deactivateToolbarSection = (element) => {\n element.removeAttribute(\"data-active\")\n}\n",
28
- "import { fetchExploringJson } from \"@jsenv/core/src/internal/dev_server/exploring/fetchExploringJson.js\"\nimport { setAttributes, setStyles } from \"./util/dom.js\"\n\n// eslint-disable-next-line no-undef\nconst TOOLBAR_BUILD_RELATIVE_URL = \"dist/toolbar/toolbar_0a91ca3b.html\"\nconst jsenvLogoSvgUrl = new URL(\"./jsenv-logo.svg\", import.meta.url)\n\nconst injectToolbar = async () => {\n await new Promise((resolve) => {\n if (window.requestIdleCallback) {\n window.requestIdleCallback(resolve, { timeout: 400 })\n } else {\n window.requestAnimationFrame(resolve)\n }\n })\n const exploringJSON = await fetchExploringJson()\n const placeholder = getToolbarPlaceholder()\n\n const iframe = document.createElement(\"iframe\")\n setAttributes(iframe, {\n tabindex: -1,\n // sandbox: \"allow-forms allow-modals allow-pointer-lock allow-popups allow-presentation allow-same-origin allow-scripts allow-top-navigation-by-user-activation\",\n // allow: \"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; microphone; midi; payment; vr\",\n allowtransparency: true,\n })\n setStyles(iframe, {\n \"position\": \"fixed\",\n \"zIndex\": 1000,\n \"bottom\": 0,\n \"left\": 0,\n \"width\": \"100%\",\n \"height\": 0,\n /* ensure toolbar children are not focusable when hidden */\n \"visibility\": \"hidden\",\n \"transition-duration\": \"300ms\",\n \"transition-property\": \"height, visibility\",\n \"border\": \"none\",\n })\n const iframeLoadedPromise = iframeToLoadedPromise(iframe)\n const jsenvCoreDirectoryServerUrl = new URL(\n exploringJSON.jsenvCoreDirectoryRelativeUrl,\n document.location.origin,\n ).href\n const jsenvToolbarHtmlServerUrl = new URL(\n TOOLBAR_BUILD_RELATIVE_URL,\n jsenvCoreDirectoryServerUrl,\n )\n // set iframe src BEFORE putting it into the DOM (prevent firefox adding an history entry)\n iframe.setAttribute(\"src\", jsenvToolbarHtmlServerUrl)\n placeholder.parentNode.replaceChild(iframe, placeholder)\n\n addToolbarEventCallback(iframe, \"toolbar_ready\", () => {\n sendCommandToToolbar(iframe, \"renderToolbar\", { exploringJSON })\n })\n\n await iframeLoadedPromise\n iframe.removeAttribute(\"tabindex\")\n\n const div = document.createElement(\"div\")\n div.innerHTML = `\n<div id=\"jsenv-toolbar-trigger\">\n <svg id=\"jsenv-toolbar-trigger-icon\">\n <use xlink:href=\"${jsenvLogoSvgUrl}#jsenv-logo\"></use>\n </svg>\n <style>\n #jsenv-toolbar-trigger {\n display: block;\n overflow: hidden;\n position: fixed;\n z-index: 1000;\n bottom: -32px;\n right: 20px;\n height: 40px;\n width: 40px;\n padding: 0;\n margin: 0;\n border-radius: 5px 5px 0 0;\n border: 1px solid rgba(0, 0, 0, 0.33);\n border-bottom: none;\n box-shadow: 0px 0px 6px 2px rgba(0, 0, 0, 0.46);\n background: transparent;\n text-align: center;\n transition: 600ms;\n }\n\n #jsenv-toolbar-trigger:hover {\n cursor: pointer;\n }\n\n #jsenv-toolbar-trigger[data-expanded] {\n bottom: 0;\n }\n\n #jsenv-toolbar-trigger-icon {\n width: 35px;\n height: 35px;\n opacity: 0;\n transition: 600ms;\n }\n\n #jsenv-toolbar-trigger[data-expanded] #jsenv-toolbar-trigger-icon {\n opacity: 1;\n }\n </style>\n</div>`\n const toolbarTrigger = div.firstElementChild\n iframe.parentNode.appendChild(toolbarTrigger)\n\n let timer\n toolbarTrigger.onmouseenter = () => {\n toolbarTrigger.setAttribute(\"data-animate\", \"\")\n timer = setTimeout(expandToolbarTrigger, 500)\n }\n toolbarTrigger.onmouseleave = () => {\n clearTimeout(timer)\n collapseToolbarTrigger()\n }\n toolbarTrigger.onfocus = () => {\n toolbarTrigger.removeAttribute(\"data-animate\")\n expandToolbarTrigger()\n }\n toolbarTrigger.onblur = () => {\n toolbarTrigger.removeAttribute(\"data-animate\")\n clearTimeout(timer)\n collapseToolbarTrigger()\n }\n toolbarTrigger.onclick = () => {\n sendCommandToToolbar(iframe, \"showToolbar\")\n }\n\n const showToolbarTrigger = () => {\n toolbarTrigger.style.display = \"block\"\n }\n\n const hideToolbarTrigger = () => {\n toolbarTrigger.style.display = \"none\"\n }\n\n const expandToolbarTrigger = () => {\n toolbarTrigger.setAttribute(\"data-expanded\", \"\")\n }\n\n const collapseToolbarTrigger = () => {\n toolbarTrigger.removeAttribute(\"data-expanded\", \"\")\n }\n\n hideToolbarTrigger()\n addToolbarEventCallback(iframe, \"toolbar-visibility-change\", (visible) => {\n if (visible) {\n hideToolbarTrigger()\n } else {\n showToolbarTrigger()\n }\n })\n\n return iframe\n}\n\nconst addToolbarEventCallback = (iframe, eventName, callback) => {\n const messageEventCallback = (messageEvent) => {\n const { data } = messageEvent\n if (typeof data !== \"object\") {\n return\n }\n const { __jsenv__ } = data\n if (!__jsenv__) {\n return\n }\n if (__jsenv__.event !== eventName) {\n return\n }\n callback(__jsenv__.data)\n }\n\n window.addEventListener(\"message\", messageEventCallback, false)\n return () => {\n window.removeEventListener(\"message\", messageEventCallback, false)\n }\n}\n\nconst sendCommandToToolbar = (iframe, command, ...args) => {\n iframe.contentWindow.postMessage(\n {\n __jsenv__: {\n command,\n args,\n },\n },\n window.origin,\n )\n}\n\nconst getToolbarPlaceholder = () => {\n const placeholder = queryPlaceholder()\n if (placeholder) {\n if (document.body.contains(placeholder)) {\n return placeholder\n }\n // otherwise iframe would not be visible because in <head>\n console.warn(\n \"element with [data-jsenv-toolbar-placeholder] must be inside document.body\",\n )\n return createTooolbarPlaceholder()\n }\n return createTooolbarPlaceholder()\n}\n\nconst queryPlaceholder = () => {\n return document.querySelector(\"[data-jsenv-toolbar-placeholder]\")\n}\n\nconst createTooolbarPlaceholder = () => {\n const placeholder = document.createElement(\"span\")\n document.body.appendChild(placeholder)\n return placeholder\n}\n\nconst iframeToLoadedPromise = (iframe) => {\n return new Promise((resolve) => {\n const onload = () => {\n iframe.removeEventListener(\"load\", onload, true)\n resolve()\n }\n iframe.addEventListener(\"load\", onload, true)\n })\n}\n\nif (document.readyState === \"complete\") {\n injectToolbar()\n} else {\n window.addEventListener(\"load\", injectToolbar)\n // document.addEventListener(\"readystatechange\", () => {\n // if (document.readyState === \"complete\") {\n // injectToolbar()\n // }\n // })\n}\n"
28
+ "import { fetchExploringJson } from \"@jsenv/core/src/internal/dev_server/exploring/fetchExploringJson.js\"\nimport { setAttributes, setStyles } from \"./util/dom.js\"\n\n// eslint-disable-next-line no-undef\nconst TOOLBAR_BUILD_RELATIVE_URL = \"dist/toolbar/toolbar_9a52325b.html\"\nconst jsenvLogoSvgUrl = new URL(\"./jsenv-logo.svg\", import.meta.url)\n\nconst injectToolbar = async () => {\n await new Promise((resolve) => {\n if (window.requestIdleCallback) {\n window.requestIdleCallback(resolve, { timeout: 400 })\n } else {\n window.requestAnimationFrame(resolve)\n }\n })\n const exploringJSON = await fetchExploringJson()\n const placeholder = getToolbarPlaceholder()\n\n const iframe = document.createElement(\"iframe\")\n setAttributes(iframe, {\n tabindex: -1,\n // sandbox: \"allow-forms allow-modals allow-pointer-lock allow-popups allow-presentation allow-same-origin allow-scripts allow-top-navigation-by-user-activation\",\n // allow: \"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; microphone; midi; payment; vr\",\n allowtransparency: true,\n })\n setStyles(iframe, {\n \"position\": \"fixed\",\n \"zIndex\": 1000,\n \"bottom\": 0,\n \"left\": 0,\n \"width\": \"100%\",\n \"height\": 0,\n /* ensure toolbar children are not focusable when hidden */\n \"visibility\": \"hidden\",\n \"transition-duration\": \"300ms\",\n \"transition-property\": \"height, visibility\",\n \"border\": \"none\",\n })\n const iframeLoadedPromise = iframeToLoadedPromise(iframe)\n const jsenvCoreDirectoryServerUrl = new URL(\n exploringJSON.jsenvCoreDirectoryRelativeUrl,\n document.location.origin,\n ).href\n const jsenvToolbarHtmlServerUrl = new URL(\n TOOLBAR_BUILD_RELATIVE_URL,\n jsenvCoreDirectoryServerUrl,\n )\n // set iframe src BEFORE putting it into the DOM (prevent firefox adding an history entry)\n iframe.setAttribute(\"src\", jsenvToolbarHtmlServerUrl)\n placeholder.parentNode.replaceChild(iframe, placeholder)\n\n addToolbarEventCallback(iframe, \"toolbar_ready\", () => {\n sendCommandToToolbar(iframe, \"renderToolbar\", { exploringJSON })\n })\n\n await iframeLoadedPromise\n iframe.removeAttribute(\"tabindex\")\n\n const div = document.createElement(\"div\")\n div.innerHTML = `\n<div id=\"jsenv-toolbar-trigger\">\n <svg id=\"jsenv-toolbar-trigger-icon\">\n <use xlink:href=\"${jsenvLogoSvgUrl}#jsenv-logo\"></use>\n </svg>\n <style>\n #jsenv-toolbar-trigger {\n display: block;\n overflow: hidden;\n position: fixed;\n z-index: 1000;\n bottom: -32px;\n right: 20px;\n height: 40px;\n width: 40px;\n padding: 0;\n margin: 0;\n border-radius: 5px 5px 0 0;\n border: 1px solid rgba(0, 0, 0, 0.33);\n border-bottom: none;\n box-shadow: 0px 0px 6px 2px rgba(0, 0, 0, 0.46);\n background: transparent;\n text-align: center;\n transition: 600ms;\n }\n\n #jsenv-toolbar-trigger:hover {\n cursor: pointer;\n }\n\n #jsenv-toolbar-trigger[data-expanded] {\n bottom: 0;\n }\n\n #jsenv-toolbar-trigger-icon {\n width: 35px;\n height: 35px;\n opacity: 0;\n transition: 600ms;\n }\n\n #jsenv-toolbar-trigger[data-expanded] #jsenv-toolbar-trigger-icon {\n opacity: 1;\n }\n </style>\n</div>`\n const toolbarTrigger = div.firstElementChild\n iframe.parentNode.appendChild(toolbarTrigger)\n\n let timer\n toolbarTrigger.onmouseenter = () => {\n toolbarTrigger.setAttribute(\"data-animate\", \"\")\n timer = setTimeout(expandToolbarTrigger, 500)\n }\n toolbarTrigger.onmouseleave = () => {\n clearTimeout(timer)\n collapseToolbarTrigger()\n }\n toolbarTrigger.onfocus = () => {\n toolbarTrigger.removeAttribute(\"data-animate\")\n expandToolbarTrigger()\n }\n toolbarTrigger.onblur = () => {\n toolbarTrigger.removeAttribute(\"data-animate\")\n clearTimeout(timer)\n collapseToolbarTrigger()\n }\n toolbarTrigger.onclick = () => {\n sendCommandToToolbar(iframe, \"showToolbar\")\n }\n\n const showToolbarTrigger = () => {\n toolbarTrigger.style.display = \"block\"\n }\n\n const hideToolbarTrigger = () => {\n toolbarTrigger.style.display = \"none\"\n }\n\n const expandToolbarTrigger = () => {\n toolbarTrigger.setAttribute(\"data-expanded\", \"\")\n }\n\n const collapseToolbarTrigger = () => {\n toolbarTrigger.removeAttribute(\"data-expanded\", \"\")\n }\n\n hideToolbarTrigger()\n addToolbarEventCallback(iframe, \"toolbar-visibility-change\", (visible) => {\n if (visible) {\n hideToolbarTrigger()\n } else {\n showToolbarTrigger()\n }\n })\n\n return iframe\n}\n\nconst addToolbarEventCallback = (iframe, eventName, callback) => {\n const messageEventCallback = (messageEvent) => {\n const { data } = messageEvent\n if (typeof data !== \"object\") {\n return\n }\n const { __jsenv__ } = data\n if (!__jsenv__) {\n return\n }\n if (__jsenv__.event !== eventName) {\n return\n }\n callback(__jsenv__.data)\n }\n\n window.addEventListener(\"message\", messageEventCallback, false)\n return () => {\n window.removeEventListener(\"message\", messageEventCallback, false)\n }\n}\n\nconst sendCommandToToolbar = (iframe, command, ...args) => {\n iframe.contentWindow.postMessage(\n {\n __jsenv__: {\n command,\n args,\n },\n },\n window.origin,\n )\n}\n\nconst getToolbarPlaceholder = () => {\n const placeholder = queryPlaceholder()\n if (placeholder) {\n if (document.body.contains(placeholder)) {\n return placeholder\n }\n // otherwise iframe would not be visible because in <head>\n console.warn(\n \"element with [data-jsenv-toolbar-placeholder] must be inside document.body\",\n )\n return createTooolbarPlaceholder()\n }\n return createTooolbarPlaceholder()\n}\n\nconst queryPlaceholder = () => {\n return document.querySelector(\"[data-jsenv-toolbar-placeholder]\")\n}\n\nconst createTooolbarPlaceholder = () => {\n const placeholder = document.createElement(\"span\")\n document.body.appendChild(placeholder)\n return placeholder\n}\n\nconst iframeToLoadedPromise = (iframe) => {\n return new Promise((resolve) => {\n const onload = () => {\n iframe.removeEventListener(\"load\", onload, true)\n resolve()\n }\n iframe.addEventListener(\"load\", onload, true)\n })\n}\n\nif (document.readyState === \"complete\") {\n injectToolbar()\n} else {\n window.addEventListener(\"load\", injectToolbar)\n // document.addEventListener(\"readystatechange\", () => {\n // if (document.readyState === \"complete\") {\n // injectToolbar()\n // }\n // })\n}\n"
29
29
  ],
30
30
  "names": [
31
31
  "nativeTypeOf",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "25.4.4",
3
+ "version": "25.5.0",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -11,7 +11,8 @@
11
11
  "node": ">=16.13.0"
12
12
  },
13
13
  "publishConfig": {
14
- "access": "public"
14
+ "access": "public",
15
+ "registry": "https://registry.npmjs.org"
15
16
  },
16
17
  "type": "module",
17
18
  "exports": {
@@ -101,6 +102,7 @@
101
102
  "rollup-plugin-node-globals": "1.4.0",
102
103
  "rollup-plugin-polyfill-node": "0.8.0",
103
104
  "source-map": "0.7.3",
105
+ "strip-ansi": "7.0.1",
104
106
  "systemjs": "6.11.0",
105
107
  "terser": "5.10.0",
106
108
  "v8-to-istanbul": "8.1.0",
@@ -141,4 +143,4 @@
141
143
  "redux": "4.1.2",
142
144
  "rollup-plugin-import-assert": "1.1.1"
143
145
  }
144
- }
146
+ }
@@ -19,13 +19,16 @@ import {
19
19
 
20
20
  /**
21
21
  * Generate optimized version of source files into a directory
22
- * @param {string|url} projectDirectoryUrl Root directory of the project
23
- * @param {string|url} buildDirectoryRelativeUrl Directory where optimized files are written
24
- * @param {object} entryPoints Describe entry point paths and control their names in the build directory
25
- * @param {"esmodule" | "systemjs" | "commonjs" | "global"} format Code generated will use this module format
26
- * @param {object} runtimeSupport Code generated will be compatible with these runtimes
27
- * @param {boolean} [minify=false] Minify file content in the build directory (HTML, CSS, JS, JSON, SVG)
22
+ * @param {Object} buildProjectParameters
23
+ * @param {string|url} buildProjectParameters.projectDirectoryUrl Root directory of the project
24
+ * @param {string|url} buildProjectParameters.buildDirectoryRelativeUrl Directory where optimized files are written
25
+ * @param {object} buildProjectParameters.entryPoints Describe entry point paths and control their names in the build directory
26
+ * @param {"esmodule" | "systemjs" | "commonjs" | "global"} buildProjectParameters.format Code generated will use this module format
27
+ * @param {object} buildProjectParameters.runtimeSupport Code generated will be compatible with these runtimes
28
+ * @param {boolean} [buildProjectParameters.minify=false] Minify file content in the build directory (HTML, CSS, JS, JSON, SVG)
29
+ * @return {Object} An object containing the result of building files
28
30
  */
31
+
29
32
  export const buildProject = async ({
30
33
  signal = new AbortController().signal,
31
34
  handleSIGINT = true,
@@ -21,14 +21,19 @@ import { jsenvCoverageConfig } from "./jsenvCoverageConfig.js"
21
21
 
22
22
  /**
23
23
  * Execute a list of files and log how it goes
24
- * @param {object} testPlan Configure files to execute and their runtimes (browsers/node)
25
- * @param {string|url} projectDirectoryUrl Root directory of the project
26
- * @param {number} [maxExecutionsInParallel=1] Maximum amount of execution in parallel
27
- * @param {number} [defaultMsAllocatedPerExecution=30000] Milliseconds after which execution is aborted and considered as failed by timeout
28
- * @param {number} [cooldownBetweenExecutions=0] Millisecond to wait between each execution
29
- * @param {boolean} [logMemoryHeapUsage=false] Add memory heap usage during logs
30
- * @param {boolean} [coverage=false] Controls if coverage is collected during files executions
31
- * @param {boolean} [coverageV8ConflictWarning=true] Warn when coverage from 2 executions cannot be merged
24
+ * @param {Object} testPlanParameters
25
+ * @param {string|url} testPlanParameters.projectDirectoryUrl Root directory of the project
26
+ * @param {Object} testPlanParameters.testPlan Object associating patterns leading to files to runtimes where they should be executed
27
+ * @param {boolean} [testPlanParameters.completedExecutionLogAbbreviation=false] Abbreviate completed execution information to shorten terminal output
28
+ * @param {boolean} [testPlanParameters.completedExecutionLogMerging=false] Merge completed execution logs to shorten terminal output
29
+ * @param {number} [testPlanParameters.maxExecutionsInParallel=1] Maximum amount of execution in parallel
30
+ * @param {number} [testPlanParameters.defaultMsAllocatedPerExecution=30000] Milliseconds after which execution is aborted and considered as failed by timeout
31
+ * @param {boolean} [testPlanParameters.failFast=false] Fails immediatly when a test execution fails
32
+ * @param {number} [testPlanParameters.cooldownBetweenExecutions=0] Millisecond to wait between each execution
33
+ * @param {boolean} [testPlanParameters.logMemoryHeapUsage=false] Add memory heap usage during logs
34
+ * @param {boolean} [testPlanParameters.coverage=false] Controls if coverage is collected during files executions
35
+ * @param {boolean} [testPlanParameters.coverageV8ConflictWarning=true] Warn when coverage from 2 executions cannot be merged
36
+ * @return {Object} An object containing the result of all file executions
32
37
  */
33
38
  export const executeTestPlan = async ({
34
39
  signal = new AbortController().signal,
@@ -44,15 +49,17 @@ export const executeTestPlan = async ({
44
49
 
45
50
  testPlan,
46
51
 
52
+ logSummary = true,
47
53
  logMemoryHeapUsage = false,
54
+ logFileRelativeUrl = ".jsenv/test_plan_debug.txt",
48
55
  completedExecutionLogAbbreviation = false,
49
56
  completedExecutionLogMerging = false,
50
- logSummary = true,
51
57
  updateProcessExitCode = true,
52
58
  windowsProcessExitFix = true,
53
59
 
54
60
  maxExecutionsInParallel = 1,
55
61
  defaultMsAllocatedPerExecution = 30000,
62
+ failFast = false,
56
63
  // stopAfterExecute: true to ensure runtime is stopped once executed
57
64
  // because we have what we wants: execution is completed and
58
65
  // we have associated coverage and capturedConsole
@@ -99,14 +106,11 @@ export const executeTestPlan = async ({
99
106
  jsenvDirectoryClean,
100
107
  }) => {
101
108
  const logger = createLogger({ logLevel })
102
-
103
109
  projectDirectoryUrl = assertProjectDirectoryUrl({ projectDirectoryUrl })
104
110
  await assertProjectDirectoryExists({ projectDirectoryUrl })
105
-
106
111
  if (typeof testPlan !== "object") {
107
112
  throw new Error(`testPlan must be an object, got ${testPlan}`)
108
113
  }
109
-
110
114
  if (coverage) {
111
115
  if (typeof coverageConfig !== "object") {
112
116
  throw new TypeError(
@@ -151,7 +155,6 @@ export const executeTestPlan = async ({
151
155
  }
152
156
  }
153
157
  }
154
-
155
158
  const result = await executePlan(testPlan, {
156
159
  signal,
157
160
  handleSIGINT,
@@ -167,13 +170,15 @@ export const executeTestPlan = async ({
167
170
  importResolutionMethod,
168
171
  importDefaultExtension,
169
172
 
173
+ logSummary,
170
174
  logMemoryHeapUsage,
175
+ logFileRelativeUrl,
171
176
  completedExecutionLogMerging,
172
177
  completedExecutionLogAbbreviation,
173
- logSummary,
174
178
 
175
- defaultMsAllocatedPerExecution,
176
179
  maxExecutionsInParallel,
180
+ defaultMsAllocatedPerExecution,
181
+ failFast,
177
182
  stopAfterExecute,
178
183
  cooldownBetweenExecutions,
179
184
  gcBetweenExecutions,
@@ -201,11 +206,9 @@ export const executeTestPlan = async ({
201
206
  importMapInWebWorkers,
202
207
  customCompilers,
203
208
  })
204
-
205
209
  if (updateProcessExitCode && !executionIsPassed(result)) {
206
210
  process.exitCode = 1
207
211
  }
208
-
209
212
  const planCoverage = result.planCoverage
210
213
  // planCoverage can be null when execution is aborted
211
214
  if (planCoverage) {
@@ -256,7 +259,6 @@ export const executeTestPlan = async ({
256
259
  }
257
260
  await Promise.all(promises)
258
261
  }
259
-
260
262
  // Sometimes on windows test plan scripts never ends
261
263
  // I suspect it's some node process keeping the process alive
262
264
  // because not properly killed for some reason.
@@ -267,7 +269,6 @@ export const executeTestPlan = async ({
267
269
  process.exit()
268
270
  }, 2000).unref()
269
271
  }
270
-
271
272
  return {
272
273
  testPlanAborted: result.aborted,
273
274
  testPlanSummary: result.planSummary,
@@ -61,8 +61,9 @@ const readJsenvCoreVersionFromPackageFile = async () => {
61
61
  "./package.json",
62
62
  jsenvCoreDirectoryUrl,
63
63
  )
64
- const jsenvCoreVersion = await readFile(jsenvCorePackageFileUrl, {
64
+ const jsenvCorePackage = await readFile(jsenvCorePackageFileUrl, {
65
65
  as: "json",
66
- }).version
67
- return jsenvCoreVersion
66
+ })
67
+ const version = jsenvCorePackage.version
68
+ return version
68
69
  }
@@ -84,7 +84,7 @@ export const setupJsenvDirectory = async ({
84
84
  const { runtimes } = compileDirectory
85
85
  if (!runtimes.includes(runtime)) {
86
86
  runtimes.push(runtime)
87
- await writeMetaFile()
87
+ writeMetaFile()
88
88
  }
89
89
  return existingCompileId
90
90
  }
@@ -17,6 +17,7 @@
17
17
 
18
18
  .browser_support_text[data-warning],
19
19
  .files_compilation_text[data-warning] {
20
- background: orange;
21
- color: black;
20
+ color: #cb5909;
21
+ margin-bottom: 5px;
22
+ display: block;
22
23
  }
@@ -1,4 +1,5 @@
1
1
  import { scanBrowserRuntimeFeatures } from "../../../features/browser_feature_detection/browser_feature_detection.js"
2
+ import { setLinkHrefForParentWindow } from "../util/iframe_to_parent_href.js"
2
3
  import { removeForceHideElement } from "../util/dom.js"
3
4
  import { enableVariant } from "../variant/variant.js"
4
5
  import {
@@ -101,25 +102,24 @@ export const renderCompilationInToolbar = ({ compileGroup }) => {
101
102
  ".files_compilation_text",
102
103
  ).innerHTML = `Files shown are compiled for ${runtimeReport.name}@${runtimeReport.version}`
103
104
  }
104
- filesCompilationRootNode.querySelector("a.link_to_source_files").onclick =
105
- () => {
106
- window.parent.location.href = `/${compileGroup.fileRelativeUrl}`
107
- }
108
- filesCompilationRootNode.querySelector(
109
- "a.link_to_compiled_files",
110
- ).onclick = () => {
111
- window.parent.location.href = `/${jsenvDirectoryRelativeUrl}${expectedCompiledId}/${compileGroup.fileRelativeUrl}`
112
- }
113
- filesCompilationRootNode.querySelector(
114
- "a.link_to_compilation_forced_files",
115
- ).onclick = () => {
116
- window.parent.location.href = `/${jsenvDirectoryRelativeUrl}force/${compileGroup.fileRelativeUrl}`
117
- }
118
- filesCompilationRootNode.querySelector(
119
- "a.link_to_appropriate_files",
120
- ).onclick = () => {
121
- window.parent.location.href = `/${jsenvDirectoryRelativeUrl}${expectedCompiledId}/${compileGroup.fileRelativeUrl}`
122
- }
105
+ setLinkHrefForParentWindow(
106
+ filesCompilationRootNode.querySelector("a.link_to_source_files"),
107
+ `/${compileGroup.fileRelativeUrl}`,
108
+ )
109
+ setLinkHrefForParentWindow(
110
+ filesCompilationRootNode.querySelector("a.link_to_compiled_files"),
111
+ `/${jsenvDirectoryRelativeUrl}${expectedCompiledId}/${compileGroup.fileRelativeUrl}`,
112
+ )
113
+ setLinkHrefForParentWindow(
114
+ filesCompilationRootNode.querySelector(
115
+ "a.link_to_compilation_forced_files",
116
+ ),
117
+ `/${jsenvDirectoryRelativeUrl}force/${compileGroup.fileRelativeUrl}`,
118
+ )
119
+ setLinkHrefForParentWindow(
120
+ filesCompilationRootNode.querySelector("a.link_to_appropriate_files"),
121
+ `/${jsenvDirectoryRelativeUrl}${expectedCompiledId}/${compileGroup.fileRelativeUrl}`,
122
+ )
123
123
 
124
124
  if (hasWarning) {
125
125
  enableWarningStyle()