@jsenv/core 40.8.4 → 40.9.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.
@@ -68,6 +68,7 @@ export const startDevServer = async ({
68
68
  http2 = false,
69
69
  logLevel = EXECUTED_BY_TEST_PLAN ? "warn" : "info",
70
70
  serverLogLevel = "warn",
71
+ serverRouterLogLevel = "warn",
71
72
  services = [],
72
73
 
73
74
  signal = new AbortController().signal,
@@ -676,6 +677,7 @@ export const startDevServer = async ({
676
677
  stopOnInternalError: false,
677
678
  keepProcessAlive,
678
679
  logLevel: serverLogLevel,
680
+ routerLogLevel: serverRouterLogLevel,
679
681
  startLog: false,
680
682
 
681
683
  https,
@@ -12,6 +12,7 @@ import {
12
12
  defineNonEnumerableProperties,
13
13
  } from "./errors.js";
14
14
  import { assertFetchedContentCompliance } from "./fetched_content_compliance.js";
15
+ import { FILE_AND_SERVER_URLS_CONVERTER } from "./file_and_server_urls_converter.js";
15
16
  import {
16
17
  determineFileUrlForOutDirectory,
17
18
  determineSourcemapFileUrl,
@@ -107,6 +108,10 @@ export const createKitchen = ({
107
108
  isSupportedOnCurrentClients: memoizeIsSupported(clientRuntimeCompat),
108
109
  isSupportedOnFutureClients: memoizeIsSupported(runtimeCompat),
109
110
  isPlaceholderInjection,
111
+ asServerUrl: (fileUrl) =>
112
+ FILE_AND_SERVER_URLS_CONVERTER.asServerUrl(fileUrl, rootDirectoryUrl),
113
+ asFileUrl: (serverUrl) =>
114
+ FILE_AND_SERVER_URLS_CONVERTER.asFileUrl(serverUrl, rootDirectoryUrl),
110
115
  INJECTIONS,
111
116
  getPluginMeta: null,
112
117
  sourcemaps,
@@ -0,0 +1,49 @@
1
+ export const initDropToOpen = ({ rootDirectoryUrl }) => {
2
+ const dataTransferCandidates = [
3
+ (dataTransfer) => {
4
+ if (!dataTransfer.types.includes("resourceurls")) {
5
+ return null;
6
+ }
7
+ return () => {
8
+ const data = dataTransfer.getData("resourceurls");
9
+ const urls = JSON.parse(data);
10
+ if (!Array.isArray(urls) || urls.length === 0) {
11
+ return;
12
+ }
13
+ const [url] = urls;
14
+ const fileUrl = new URL(url).href;
15
+ let serverUrl;
16
+
17
+ if (fileUrl.startsWith(rootDirectoryUrl)) {
18
+ const serverRelativeUrl = fileUrl.slice(rootDirectoryUrl.length);
19
+ serverUrl = `/${serverRelativeUrl}`;
20
+ } else {
21
+ serverUrl = `/@fs/${fileUrl}`;
22
+ }
23
+ window.location.href = serverUrl;
24
+ };
25
+ },
26
+ ];
27
+
28
+ document.addEventListener("dragover", (event) => {
29
+ for (const candidate of dataTransferCandidates) {
30
+ const dataTransferHandler = candidate(event.dataTransfer);
31
+ if (dataTransferHandler) {
32
+ event.preventDefault();
33
+ return;
34
+ }
35
+ }
36
+ });
37
+ document.addEventListener("drop", (event) => {
38
+ let handler;
39
+ for (const candidate of dataTransferCandidates) {
40
+ const dataTransferHandler = candidate(event.dataTransfer);
41
+ if (dataTransferHandler) {
42
+ handler = dataTransferHandler;
43
+ break;
44
+ }
45
+ }
46
+ event.preventDefault();
47
+ handler();
48
+ });
49
+ };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * HTML page server by jsenv dev server will listen for drop events
3
+ * and redirect the browser to the dropped file location.
4
+ *
5
+ * Works only for VSCode right now (because it sets "resourceurls" dataTransfer type).
6
+ *
7
+ */
8
+
9
+ import { injectJsenvScript, parseHtml, stringifyHtmlAst } from "@jsenv/ast";
10
+
11
+ export const jsenvPluginDropToOpen = () => {
12
+ const clientFileUrl = import.meta.resolve("./client/drop_to_open.js");
13
+ return {
14
+ name: "jsenv:drop_to_open",
15
+ appliesDuring: "dev",
16
+ transformUrlContent: {
17
+ html: (urlInfo) => {
18
+ const htmlAst = parseHtml({
19
+ html: urlInfo.content,
20
+ url: urlInfo.url,
21
+ });
22
+ const clientFileReference = urlInfo.dependencies.inject({
23
+ type: "script",
24
+ subtype: "js_module",
25
+ expectedType: "js_module",
26
+ specifier: clientFileUrl,
27
+ });
28
+ injectJsenvScript(htmlAst, {
29
+ type: "module",
30
+ src: clientFileReference.generatedSpecifier,
31
+ initCall: {
32
+ callee: "initDropToOpen",
33
+ params: {
34
+ rootDirectoryUrl: urlInfo.context.rootDirectoryUrl,
35
+ },
36
+ },
37
+ pluginName: "jsenv:drop_to_open",
38
+ });
39
+ return stringifyHtmlAst(htmlAst);
40
+ },
41
+ },
42
+ };
43
+ };
@@ -1,12 +1,15 @@
1
1
  export const installImportMetaCss = (importMeta) => {
2
2
  let cssText = "";
3
- let stylesheet = new CSSStyleSheet();
3
+ let stylesheet = new CSSStyleSheet({ baseUrl: importMeta.url });
4
4
  let adopted = false;
5
5
 
6
6
  const css = {
7
7
  toString: () => cssText,
8
8
  update: (value) => {
9
9
  cssText = value;
10
+ cssText += `
11
+ /* sourceURL=${importMeta.url} */
12
+ /* inlined from ${importMeta.url} */`;
10
13
  stylesheet.replaceSync(cssText);
11
14
  },
12
15
  inject: () => {
@@ -23,6 +23,7 @@ import { jsenvPluginAutoreload } from "./autoreload/jsenv_plugin_autoreload.js";
23
23
  import { jsenvPluginCacheControl } from "./cache_control/jsenv_plugin_cache_control.js";
24
24
  // other
25
25
  import { jsenvPluginRibbon } from "./ribbon/jsenv_plugin_ribbon.js";
26
+ import { jsenvPluginDropToOpen } from "./drop_to_open/jsenv_plugin_drop_to_open.js";
26
27
  import { jsenvPluginCleanHTML } from "./clean_html/jsenv_plugin_clean_html.js";
27
28
  import { jsenvPluginChromeDevtoolsJson } from "./chrome_devtools_json/jsenv_plugin_chrome_devtools_json.js";
28
29
  import { jsenvPluginAutoreloadOnServerRestart } from "./autoreload_on_server_restart/jsenv_plugin_autoreload_on_server_restart.js";
@@ -146,6 +147,7 @@ export const getCorePlugins = ({
146
147
  : []),
147
148
  ...(cacheControl ? [jsenvPluginCacheControl(cacheControl)] : []),
148
149
  ...(ribbon ? [jsenvPluginRibbon({ rootDirectoryUrl, ...ribbon })] : []),
150
+ jsenvPluginDropToOpen(),
149
151
  jsenvPluginCleanHTML(),
150
152
  jsenvPluginChromeDevtoolsJson(),
151
153
  ...(packageSideEffects
@@ -101,9 +101,11 @@ a.nav_item_text {
101
101
  margin: 10px 15px 10px 15px;
102
102
  list-style-type: none;
103
103
  border-radius: 3px;
104
+ display: flex;
105
+ flex-direction: column;
104
106
  }
105
107
  .directory_content_item {
106
- display: flex;
108
+ display: inline-flex;
107
109
  position: relative;
108
110
  padding: 10px 15px 10px 15px;
109
111
  font-size: 15px;
@@ -112,7 +114,9 @@ a.nav_item_text {
112
114
  align-items: center;
113
115
  }
114
116
  .directory_content_item_link {
115
- display: flex;
117
+ display: inline-flex;
118
+ min-width: 0;
119
+ max-width: 100%;
116
120
  flex: 1;
117
121
  gap: 10px;
118
122
  align-items: center;
@@ -123,12 +127,15 @@ a.nav_item_text {
123
127
  aspect-ratio: 1/1;
124
128
  display: flex;
125
129
  color: #f1f1f1;
130
+ flex-shrink: 0;
126
131
  }
127
132
  .directory_content_item_icon img {
128
133
  width: 100%;
129
134
  }
130
135
  .directory_content_item_text {
131
- display: flex;
136
+ display: inline-flex;
137
+ flex-grow: 1;
138
+ align-items: center;
132
139
  }
133
140
  .directory_content_item:last-child {
134
141
  border-bottom: none;
@@ -63,11 +63,13 @@ const ErrorMessage = () => {
63
63
  errorText = (
64
64
  <>
65
65
  <strong>File not found:</strong>&nbsp;
66
- <code>
67
- <span className="file_path_good">{filePathExisting}</span>
68
- <span className="file_path_bad">{filePathNotFound}</span>
69
- </code>{" "}
70
- does not exist on the server.
66
+ <Overflow>
67
+ <code>
68
+ <span className="file_path_good">{filePathExisting}</span>
69
+ <span className="file_path_bad">{filePathNotFound}</span>
70
+ </code>{" "}
71
+ does not exist on the server.
72
+ </Overflow>
71
73
  </>
72
74
  );
73
75
  errorSuggestion = (
@@ -90,6 +92,19 @@ const ErrorMessage = () => {
90
92
  );
91
93
  };
92
94
 
95
+ const Overflow = ({ children, afterContent }) => {
96
+ return (
97
+ <div style="display: flex; flex-wrap: wrap; overflow: hidden; width: 100%; box-sizing: border-box; white-space: nowrap; text-overflow: ellipsis;">
98
+ <div style="display: flex; flex-grow: 1; width: 0;">
99
+ <div style="overflow: hidden; max-width: 100%; text-overflow: ellipsis;">
100
+ {children}
101
+ </div>
102
+ {afterContent}
103
+ </div>
104
+ </div>
105
+ );
106
+ };
107
+
93
108
  const Breadcrumb = ({ items }) => {
94
109
  return (
95
110
  <h1 className="nav">
@@ -170,7 +185,7 @@ const DirectoryContent = ({ items }) => {
170
185
  isDirectory={directoryItem.url.endsWith("/")}
171
186
  isMainFile={directoryItem.isMainFile}
172
187
  >
173
- {directoryItem.urlRelativeToCurrentDirectory}
188
+ {decodeURI(directoryItem.urlRelativeToCurrentDirectory)}
174
189
  </DirectoryContentItem>
175
190
  );
176
191
  })}
@@ -201,15 +216,17 @@ const DirectoryContentItem = ({ url, isDirectory, isMainFile, children }) => {
201
216
  }
202
217
  />
203
218
  </span>
204
- {children}
205
- {isDirectory ? (
206
- <>
207
- <span style="flex:1"></span>
208
- <span className="directory_content_item_arrow">
209
- <RightArrowSvg />
210
- </span>
211
- </>
212
- ) : null}
219
+ <span className="directory_content_item_text">
220
+ <Overflow>{children}</Overflow>
221
+ {isDirectory ? (
222
+ <>
223
+ <span style="flex:1"></span>
224
+ <span className="directory_content_item_arrow">
225
+ <RightArrowSvg />
226
+ </span>
227
+ </>
228
+ ) : null}
229
+ </span>
213
230
  </a>
214
231
  </li>
215
232
  );
@@ -37,7 +37,7 @@ import {
37
37
  } from "@jsenv/urls";
38
38
  import { existsSync, lstatSync, readdirSync } from "node:fs";
39
39
  import { getDirectoryWatchPatterns } from "../../helpers/watch_source_files.js";
40
- import { FILE_AND_SERVER_URLS_CONVERTER } from "./file_and_server_urls_converter.js";
40
+ import { FILE_AND_SERVER_URLS_CONVERTER } from "../../kitchen/file_and_server_urls_converter.js";
41
41
 
42
42
  const htmlFileUrlForDirectory = import.meta.resolve(
43
43
  "./client/directory_listing.html",
@@ -2,7 +2,7 @@ import { readEntryStatSync } from "@jsenv/filesystem";
2
2
  import { ensurePathnameTrailingSlash } from "@jsenv/urls";
3
3
  import { CONTENT_TYPE } from "@jsenv/utils/src/content_type/content_type.js";
4
4
  import { readFileSync, readdirSync } from "node:fs";
5
- import { FILE_AND_SERVER_URLS_CONVERTER } from "./file_and_server_urls_converter.js";
5
+ import { FILE_AND_SERVER_URLS_CONVERTER } from "../../kitchen/file_and_server_urls_converter.js";
6
6
  import { jsenvPluginDirectoryListing } from "./jsenv_plugin_directory_listing.js";
7
7
  import { jsenvPluginFsRedirection } from "./jsenv_plugin_fs_redirection.js";
8
8