@jsenv/core 40.12.12 → 40.12.14

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.
@@ -132,14 +132,14 @@ export const createKitchen = ({
132
132
  },
133
133
  graph: null,
134
134
  urlInfoTransformer: null,
135
- pluginController: null,
135
+ jsenvPluginsController: null,
136
136
  };
137
137
  const kitchenContext = kitchen.context;
138
138
  kitchenContext.kitchen = kitchen;
139
139
 
140
- let pluginController;
141
- kitchen.setPluginController = (value) => {
142
- pluginController = kitchen.pluginController = value;
140
+ let jsenvPluginsController;
141
+ kitchen.setJsenvPluginsController = (value) => {
142
+ jsenvPluginsController = kitchen.jsenvPluginsController = value;
143
143
  };
144
144
 
145
145
  const graph = createUrlGraph({
@@ -148,7 +148,11 @@ export const createKitchen = ({
148
148
  kitchen,
149
149
  });
150
150
  graph.urlInfoCreatedEventEmitter.on((urlInfoCreated) => {
151
- pluginController.callHooks("urlInfoCreated", urlInfoCreated, () => {});
151
+ jsenvPluginsController.callHooks(
152
+ "urlInfoCreated",
153
+ urlInfoCreated,
154
+ () => {},
155
+ );
152
156
  });
153
157
  kitchen.graph = graph;
154
158
 
@@ -322,7 +326,7 @@ export const createKitchen = ({
322
326
  setReferenceUrl(reference.url);
323
327
  break resolve;
324
328
  }
325
- const resolvedUrl = pluginController.callHooksUntil(
329
+ const resolvedUrl = jsenvPluginsController.callHooksUntil(
326
330
  "resolveReference",
327
331
  reference,
328
332
  );
@@ -336,7 +340,7 @@ export const createKitchen = ({
336
340
  setReferenceUrl(normalizedUrl);
337
341
  if (reference.debug) {
338
342
  logger.debug(`url resolved by "${
339
- pluginController.getLastPluginUsed().name
343
+ jsenvPluginsController.getLastPluginUsed().name
340
344
  }"
341
345
  ${ANSI.color(reference.specifier, ANSI.GREY)} ->
342
346
  ${ANSI.color(reference.url, ANSI.YELLOW)}
@@ -350,7 +354,7 @@ ${ANSI.color(reference.url, ANSI.YELLOW)}
350
354
  // - side_effect_file references injected in entry points or at the top of files
351
355
  break redirect;
352
356
  }
353
- pluginController.callHooks(
357
+ jsenvPluginsController.callHooks(
354
358
  "redirectReference",
355
359
  reference,
356
360
  (returnValue, plugin, setReference) => {
@@ -395,7 +399,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
395
399
  return reference;
396
400
  } catch (error) {
397
401
  throw createResolveUrlError({
398
- pluginController,
402
+ jsenvPluginsController,
399
403
  reference,
400
404
  error,
401
405
  });
@@ -422,7 +426,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
422
426
  // But do not represent an other resource, it is considered as
423
427
  // the same resource under the hood
424
428
  const searchParamTransformationMap = new Map();
425
- pluginController.callHooks(
429
+ jsenvPluginsController.callHooks(
426
430
  "transformReferenceSearchParams",
427
431
  reference,
428
432
  (returnValue) => {
@@ -450,7 +454,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
450
454
  }
451
455
  }
452
456
  format: {
453
- const returnValue = pluginController.callHooksUntil(
457
+ const returnValue = jsenvPluginsController.callHooksUntil(
454
458
  "formatReference",
455
459
  reference,
456
460
  );
@@ -471,7 +475,10 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
471
475
  const fetchUrlContent = async (urlInfo) => {
472
476
  try {
473
477
  const fetchUrlContentReturnValue =
474
- await pluginController.callAsyncHooksUntil("fetchUrlContent", urlInfo);
478
+ await jsenvPluginsController.callAsyncHooksUntil(
479
+ "fetchUrlContent",
480
+ urlInfo,
481
+ );
475
482
  if (!fetchUrlContentReturnValue) {
476
483
  logger.warn(
477
484
  createDetailedMessage(
@@ -570,7 +577,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
570
577
  });
571
578
  } catch (error) {
572
579
  throw createFetchUrlContentError({
573
- pluginController,
580
+ jsenvPluginsController,
574
581
  urlInfo,
575
582
  error,
576
583
  });
@@ -580,7 +587,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
580
587
 
581
588
  const transformUrlContent = async (urlInfo) => {
582
589
  try {
583
- await pluginController.callAsyncHooks(
590
+ await jsenvPluginsController.callAsyncHooks(
584
591
  "transformUrlContent",
585
592
  urlInfo,
586
593
  (transformReturnValue) => {
@@ -592,7 +599,7 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
592
599
  );
593
600
  } catch (error) {
594
601
  const transformError = createTransformUrlContentError({
595
- pluginController,
602
+ jsenvPluginsController,
596
603
  urlInfo,
597
604
  error,
598
605
  });
@@ -604,14 +611,15 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
604
611
  const finalizeUrlContent = async (urlInfo) => {
605
612
  try {
606
613
  await urlInfo.applyContentTransformationCallbacks();
607
- const finalizeReturnValue = await pluginController.callAsyncHooksUntil(
608
- "finalizeUrlContent",
609
- urlInfo,
610
- );
614
+ const finalizeReturnValue =
615
+ await jsenvPluginsController.callAsyncHooksUntil(
616
+ "finalizeUrlContent",
617
+ urlInfo,
618
+ );
611
619
  urlInfoTransformer.endTransformations(urlInfo, finalizeReturnValue);
612
620
  } catch (error) {
613
621
  throw createFinalizeUrlContentError({
614
- pluginController,
622
+ jsenvPluginsController,
615
623
  urlInfo,
616
624
  error,
617
625
  });
@@ -692,7 +700,7 @@ ${urlInfo.firstReference.trace.message}`;
692
700
  }
693
701
 
694
702
  // "cooked" hook
695
- pluginController.callHooks("cooked", urlInfo, (cookedReturnValue) => {
703
+ jsenvPluginsController.callHooks("cooked", urlInfo, (cookedReturnValue) => {
696
704
  if (typeof cookedReturnValue === "function") {
697
705
  const removeCallback = urlInfo.graph.urlInfoDereferencedEventEmitter.on(
698
706
  (urlInfoDereferenced, lastReferenceFromOther) => {
@@ -333,7 +333,7 @@ export const jsenvPluginAutoreloadServer = ({
333
333
  );
334
334
  },
335
335
  },
336
- devServerRoutes: [
336
+ serverRoutes: [
337
337
  {
338
338
  endpoint: "GET /.internal/graph.json",
339
339
  description:
@@ -2,7 +2,7 @@ import { injectJsenvScript, parseHtml, stringifyHtmlAst } from "@jsenv/ast";
2
2
 
3
3
  export const jsenvPluginAutoreloadOnServerRestart = () => {
4
4
  const autoreloadOnRestartClientFileUrl = import.meta
5
- .resolve("@jsenv/server/src/services/autoreload_on_server_restart/client/autoreload_on_server_restart.js");
5
+ .resolve("@jsenv/server/src/plugins/autoreload_on_server_restart/client/autoreload_on_server_restart.js");
6
6
 
7
7
  return {
8
8
  name: "jsenv:autoreload_on_server_restart",
@@ -25,7 +25,7 @@ export const jsenvPluginChromeDevtoolsJson = () => {
25
25
  return {
26
26
  name: "jsenv_plugin_chrome_devtools_json",
27
27
  appliesDuring: "dev",
28
- devServerRoutes: [
28
+ serverRoutes: [
29
29
  {
30
30
  endpoint: "GET /.well-known/appspecific/com.chrome.devtools.json",
31
31
  declarationSource: import.meta.url,
@@ -1,20 +1,49 @@
1
1
  export const installImportMetaCssBuild = (importMeta) => {
2
- const stylesheet = new CSSStyleSheet({ baseUrl: importMeta.url });
2
+ const IMPORT_META_CSS_BUILD = "jsenv_import_meta_css_build";
3
3
 
4
- let called = false;
5
- // eslint-disable-next-line accessor-pairs
4
+ if (importMeta.css === IMPORT_META_CSS_BUILD) {
5
+ return;
6
+ }
7
+
8
+ const stylesheetMap = new Map();
9
+ const adopt = (url, value) => {
10
+ const stylesheet = new CSSStyleSheet({ baseUrl: importMeta.url });
11
+ stylesheet.replaceSync(value);
12
+ stylesheetMap.set(url, stylesheet);
13
+ document.adoptedStyleSheets = [...document.adoptedStyleSheets, stylesheet];
14
+ };
15
+ const update = (url, value) => {
16
+ stylesheetMap.get(url).replaceSync(value);
17
+ };
18
+ const remove = (url) => {
19
+ const stylesheet = stylesheetMap.get(url);
20
+ document.adoptedStyleSheets = document.adoptedStyleSheets.filter(
21
+ (s) => s !== stylesheet,
22
+ );
23
+ stylesheetMap.delete(url);
24
+ };
25
+
26
+ const currentCssSourceMap = new Map();
6
27
  Object.defineProperty(importMeta, "css", {
7
28
  configurable: true,
8
- set(value) {
9
- if (called) {
10
- throw new Error("import.meta.css setter can only be called once");
29
+ get() {
30
+ return IMPORT_META_CSS_BUILD;
31
+ },
32
+ set([value, url]) {
33
+ if (value === undefined) {
34
+ if (stylesheetMap.has(url)) {
35
+ remove(url);
36
+ currentCssSourceMap.delete(url);
37
+ }
38
+ return;
39
+ }
40
+ if (!stylesheetMap.has(url)) {
41
+ adopt(url, value);
42
+ currentCssSourceMap.set(url, value);
43
+ } else if (currentCssSourceMap.get(url) !== value) {
44
+ update(url, value);
45
+ currentCssSourceMap.set(url, value);
11
46
  }
12
- called = true;
13
- stylesheet.replaceSync(value);
14
- document.adoptedStyleSheets = [
15
- ...document.adoptedStyleSheets,
16
- stylesheet,
17
- ];
18
47
  },
19
48
  });
20
49
  };
@@ -1,46 +1,58 @@
1
1
  export const installImportMetaCssDev = (importMeta) => {
2
- let cssText = "";
3
- let stylesheet = new CSSStyleSheet({ baseUrl: importMeta.url });
4
- let adopted = false;
2
+ const IMPORT_META_CSS_DEV = "jsenv_import_meta_css_dev";
5
3
 
6
- const css = {
7
- toString: () => cssText,
8
- update: (value) => {
9
- cssText = value;
10
- cssText += `
4
+ // useless today but browser might catch up to display it in devtools
5
+ const addUrlInfo = (cssText) => {
6
+ let cssTextWithUrlInfo = cssText;
7
+ cssTextWithUrlInfo += `
11
8
  /* sourceURL=${importMeta.url} */
12
9
  /* inlined from ${importMeta.url} */`;
13
- stylesheet.replaceSync(cssText);
14
- },
15
- inject: () => {
16
- if (!adopted) {
17
- document.adoptedStyleSheets = [
18
- ...document.adoptedStyleSheets,
19
- stylesheet,
20
- ];
21
- adopted = true;
22
- }
23
- },
24
- remove: () => {
25
- if (adopted) {
26
- document.adoptedStyleSheets = document.adoptedStyleSheets.filter(
27
- (s) => s !== stylesheet,
28
- );
29
- adopted = false;
30
- }
31
- },
10
+ return cssTextWithUrlInfo;
11
+ };
12
+
13
+ let stylesheet;
14
+ const adopt = (value) => {
15
+ stylesheet = new CSSStyleSheet({ baseUrl: importMeta.url });
16
+ stylesheet.replaceSync(addUrlInfo(value));
17
+ document.adoptedStyleSheets = [...document.adoptedStyleSheets, stylesheet];
18
+ };
19
+ const update = (value) => {
20
+ stylesheet.replaceSync(addUrlInfo(value));
21
+ };
22
+ const remove = () => {
23
+ document.adoptedStyleSheets = document.adoptedStyleSheets.filter(
24
+ (s) => s !== stylesheet,
25
+ );
32
26
  };
33
27
 
28
+ let currentCssSource;
34
29
  Object.defineProperty(importMeta, "css", {
35
30
  configurable: true,
36
31
  get() {
37
- return css;
32
+ return IMPORT_META_CSS_DEV;
38
33
  },
39
34
  set(value) {
40
- css.update(value);
41
- css.inject();
35
+ if (value === undefined) {
36
+ if (stylesheet) {
37
+ remove();
38
+ stylesheet = undefined;
39
+ currentCssSource = undefined;
40
+ }
41
+ return;
42
+ }
43
+ if (!stylesheet) {
44
+ adopt(value);
45
+ currentCssSource = value;
46
+ } else if (currentCssSource !== value) {
47
+ update(value);
48
+ currentCssSource = value;
49
+ }
42
50
  },
43
51
  });
44
52
 
45
- return css.remove;
53
+ return () => {
54
+ remove();
55
+ stylesheet = undefined;
56
+ currentCssSource = undefined;
57
+ };
46
58
  };
@@ -36,11 +36,7 @@ export const jsenvPluginImportMetaCss = () => {
36
36
  appliesDuring: "*",
37
37
  transformUrlContent: {
38
38
  js_module: async (urlInfo) => {
39
- if (
40
- !urlInfo.content.includes("import.meta.css") ||
41
- // there is already our installImportMetaCssBuild in the file
42
- urlInfo.content.includes("installImportMetaCssBuild")
43
- ) {
39
+ if (!urlInfo.content.includes("import.meta.css")) {
44
40
  return null;
45
41
  }
46
42
  const { metadata } = await applyBabelPlugins({
@@ -54,22 +50,70 @@ export const jsenvPluginImportMetaCss = () => {
54
50
  if (!usesImportMetaCss) {
55
51
  return null;
56
52
  }
53
+ if (urlInfo.context.build) {
54
+ const rootDirectoryUrl = urlInfo.context.rootDirectoryUrl;
55
+ const relativeUrl = urlInfo.originalUrl.slice(
56
+ rootDirectoryUrl.length - 1,
57
+ );
58
+ const { code } = await applyBabelPlugins({
59
+ babelPlugins: [
60
+ [babelPluginRewriteImportMetaCssAssignment, { relativeUrl }],
61
+ ],
62
+ input: urlInfo.content,
63
+ inputIsJsModule: true,
64
+ inputUrl: urlInfo.originalUrl,
65
+ outputUrl: urlInfo.generatedUrl,
66
+ });
67
+ return injectImportMetaCss(urlInfo, {
68
+ content: code,
69
+ importFrom: importMetaCssBuildClientFileUrl,
70
+ importName: "installImportMetaCssBuild",
71
+ importAs: "__installImportMetaCssBuild__",
72
+ });
73
+ }
57
74
  return injectImportMetaCss(urlInfo, {
58
- importFrom: urlInfo.context.build
59
- ? importMetaCssBuildClientFileUrl
60
- : importMetaCssDevClientFileUrl,
61
- importName: urlInfo.context.build
62
- ? "installImportMetaCssBuild"
63
- : "installImportMetaCssDev",
64
- importAs: urlInfo.context.build
65
- ? "__installImportMetaCssBuild__"
66
- : "__installImportMetaCssDev__",
75
+ content: urlInfo.content,
76
+ importFrom: importMetaCssDevClientFileUrl,
77
+ importName: "installImportMetaCssDev",
78
+ importAs: "__installImportMetaCssDev__",
79
+ hot: true,
67
80
  });
68
81
  },
69
82
  },
70
83
  };
71
84
  };
72
85
 
86
+ const babelPluginRewriteImportMetaCssAssignment = (
87
+ { types: t },
88
+ { relativeUrl },
89
+ ) => {
90
+ return {
91
+ name: "rewrite-import-meta-css-assignment",
92
+ visitor: {
93
+ AssignmentExpression(path) {
94
+ const { left, right } = path.node;
95
+ if (left.type !== "MemberExpression") {
96
+ return;
97
+ }
98
+ const { object, property } = left;
99
+ if (object.type !== "MetaProperty") {
100
+ return;
101
+ }
102
+ if (object.meta.name !== "import" || object.property.name !== "meta") {
103
+ return;
104
+ }
105
+ if (property.name !== "css") {
106
+ return;
107
+ }
108
+ path.node.right = t.arrayExpression([
109
+ right,
110
+ t.stringLiteral(relativeUrl),
111
+ ]);
112
+ },
113
+ },
114
+ };
115
+ };
116
+
73
117
  const babelPluginMetadataUsesImportMetaCss = () => {
74
118
  return {
75
119
  name: "metadata-uses-import-meta-css",
@@ -101,7 +145,10 @@ const babelPluginMetadataUsesImportMetaCss = () => {
101
145
  };
102
146
  };
103
147
 
104
- const injectImportMetaCss = (urlInfo, { importFrom, importName, importAs }) => {
148
+ const injectImportMetaCss = (
149
+ urlInfo,
150
+ { content, importFrom, importName, importAs, hot },
151
+ ) => {
105
152
  const importMetaCssClientFileReference = urlInfo.dependencies.inject({
106
153
  parentUrl: urlInfo.url,
107
154
  type: "js_import",
@@ -117,7 +164,9 @@ const injectImportMetaCss = (urlInfo, { importFrom, importName, importAs }) => {
117
164
  importBeforeFrom = `{ ${importName} } }`;
118
165
  importVariableName = importName;
119
166
  }
120
- let prelude = `import ${importBeforeFrom} from ${importMetaCssClientFileReference.generatedSpecifier};
167
+
168
+ const prelude = hot
169
+ ? `import ${importBeforeFrom} from ${importMetaCssClientFileReference.generatedSpecifier};
121
170
 
122
171
  const remove = ${importVariableName}(import.meta);
123
172
  if (import.meta.hot) {
@@ -126,9 +175,13 @@ if (import.meta.hot) {
126
175
  });
127
176
  }
128
177
 
178
+ `
179
+ : `import ${importBeforeFrom} from ${importMetaCssClientFileReference.generatedSpecifier};
180
+
181
+ ${importVariableName}(import.meta);
182
+
129
183
  `;
130
184
 
131
- let content = urlInfo.content;
132
185
  return {
133
186
  content: `${prelude.replace(/\n/g, "")}${content}`,
134
187
  };
@@ -0,0 +1,197 @@
1
+ import { createPluginsController } from "@jsenv/server/src/plugins_controller.js";
2
+
3
+ import { jsenvPluginHtmlSyntaxErrorFallback } from "./html_syntax_error_fallback/jsenv_plugin_html_syntax_error_fallback.js";
4
+
5
+ export const createJsenvPluginStore = async (plugins) => {
6
+ const allServerRoutes = [];
7
+ const allServerPlugins = [];
8
+ const pluginArray = [];
9
+
10
+ const pluginPromises = [];
11
+ const addPlugin = async (plugin) => {
12
+ if (plugin && typeof plugin.then === "function") {
13
+ pluginPromises.push(plugin);
14
+ const value = await plugin;
15
+ addPlugin(value);
16
+ return;
17
+ }
18
+ if (Array.isArray(plugin)) {
19
+ for (const subplugin of plugin) {
20
+ addPlugin(subplugin);
21
+ }
22
+ return;
23
+ }
24
+ if (plugin === null || typeof plugin !== "object") {
25
+ throw new TypeError(`plugin must be objects, got ${plugin}`);
26
+ }
27
+ if (!plugin.name) {
28
+ plugin.name = "anonymous";
29
+ }
30
+ const { serverRoutes } = plugin;
31
+ if (serverRoutes) {
32
+ for (const serverRoute of serverRoutes) {
33
+ allServerRoutes.push(serverRoute);
34
+ }
35
+ }
36
+ const { serverPlugins } = plugin;
37
+ if (serverPlugins) {
38
+ const serverPlugins = plugin.serverPlugins;
39
+ for (const serverPlugin of serverPlugins) {
40
+ allServerPlugins.push(serverPlugin);
41
+ }
42
+ }
43
+ pluginArray.push(plugin);
44
+ };
45
+ addPlugin(jsenvPluginHtmlSyntaxErrorFallback());
46
+ for (const plugin of plugins) {
47
+ addPlugin(plugin);
48
+ }
49
+ await Promise.all(pluginPromises);
50
+
51
+ return {
52
+ pluginArray,
53
+ allServerRoutes,
54
+ allServerPlugins,
55
+ };
56
+ };
57
+
58
+ export const createJsenvPluginsController = async (
59
+ pluginStore,
60
+ kitchen,
61
+ { meta } = {},
62
+ ) => {
63
+ kitchen.context.getPluginMeta = (id) => pluginsController.getPluginMeta(id);
64
+ const pluginsController = await createPluginsController({
65
+ plugins: pluginStore.pluginArray,
66
+ pluginDescription: JSENV_PLUGIN_DESCRIPTION,
67
+ filterPlugin: (plugin) => testAppliesDuring(plugin, kitchen),
68
+ getInitPluginArgs: (plugin) => [kitchen.context, { plugin }],
69
+ getEffectArgs: ({ otherPlugins }) => [
70
+ { kitchenContext: kitchen.context, otherPlugins },
71
+ ],
72
+ meta,
73
+ });
74
+ return pluginsController;
75
+ };
76
+
77
+ const hook = { type: "hook" };
78
+ const nonHook = {};
79
+
80
+ const assertUrlReturnValue = (valueReturned, urlInfo, { hook }) => {
81
+ if (valueReturned instanceof URL) {
82
+ return valueReturned.href;
83
+ }
84
+ if (typeof valueReturned === "string") {
85
+ return valueReturned;
86
+ }
87
+ throw new Error(
88
+ `Unexpected value returned by hook "${hook.plugin.name}.${hook.name}()": it must be a string; got ${valueReturned}`,
89
+ );
90
+ };
91
+ const assertContentReturnValue = (valueReturned, urlInfo, { hook }) => {
92
+ if (typeof valueReturned === "string" || Buffer.isBuffer(valueReturned)) {
93
+ return { content: valueReturned };
94
+ }
95
+ if (typeof valueReturned === "object") {
96
+ const { content, body } = valueReturned;
97
+ if (urlInfo.url.startsWith("ignore:")) {
98
+ return valueReturned;
99
+ }
100
+ if (typeof content !== "string" && !Buffer.isBuffer(content) && !body) {
101
+ if (Object.hasOwn(valueReturned, "contentInjections")) {
102
+ return valueReturned;
103
+ }
104
+ throw new Error(
105
+ `Unexpected "content" returned by hook "${hook.plugin.name}.${hook.name}()": it must be a string or a buffer; got ${content}`,
106
+ );
107
+ }
108
+ return valueReturned;
109
+ }
110
+ throw new Error(
111
+ `Unexpected value returned by hook "${hook.plugin.name}.${hook.name}()": it must be a string, a buffer or an object; got ${valueReturned}`,
112
+ );
113
+ };
114
+
115
+ const JSENV_PLUGIN_DESCRIPTION = {
116
+ name: "jsenv plugin",
117
+ properties: {
118
+ // non-hook properties (silently skipped)
119
+ appliesDuring: nonHook,
120
+ serverEvents: nonHook,
121
+ mustStayFirst: nonHook,
122
+ serverRoutes: nonHook,
123
+ serverPlugins: nonHook,
124
+ // hooks
125
+ init: hook,
126
+ resolveReference: {
127
+ type: "hook",
128
+ assertAndNormalize: assertUrlReturnValue,
129
+ },
130
+ redirectReference: {
131
+ type: "hook",
132
+ assertAndNormalize: assertUrlReturnValue,
133
+ },
134
+ transformReferenceSearchParams: hook,
135
+ formatReference: hook,
136
+ urlInfoCreated: hook,
137
+ fetchUrlContent: {
138
+ type: "hook",
139
+ assertAndNormalize: assertContentReturnValue,
140
+ },
141
+ transformUrlContent: {
142
+ type: "hook",
143
+ assertAndNormalize: assertContentReturnValue,
144
+ },
145
+ finalizeUrlContent: {
146
+ type: "hook",
147
+ assertAndNormalize: assertContentReturnValue,
148
+ },
149
+ bundle: hook,
150
+ optimizeBuildUrlContent: {
151
+ type: "hook",
152
+ assertAndNormalize: assertContentReturnValue,
153
+ },
154
+ cooked: hook,
155
+ augmentResponse: hook,
156
+ destroy: hook,
157
+ effect: hook,
158
+ refineBuildUrlContent: hook,
159
+ refineBuild: hook,
160
+ // serverRoutes and serverPlugins are nonHook above
161
+ },
162
+ };
163
+
164
+ const testAppliesDuring = (plugin, kitchen) => {
165
+ const { appliesDuring } = plugin;
166
+ if (appliesDuring === undefined) {
167
+ return true;
168
+ }
169
+ if (appliesDuring === "*") {
170
+ return true;
171
+ }
172
+ if (typeof appliesDuring === "string") {
173
+ if (appliesDuring !== "dev" && appliesDuring !== "build") {
174
+ throw new TypeError(
175
+ `"appliesDuring" must be "dev" or "build", got ${appliesDuring}`,
176
+ );
177
+ }
178
+ if (kitchen.context[appliesDuring]) {
179
+ return true;
180
+ }
181
+ return false;
182
+ }
183
+ if (typeof appliesDuring === "object") {
184
+ for (const key of Object.keys(appliesDuring)) {
185
+ if (!appliesDuring[key] && kitchen.context[key]) {
186
+ return false;
187
+ }
188
+ if (appliesDuring[key] && kitchen.context[key]) {
189
+ return true;
190
+ }
191
+ }
192
+ return false;
193
+ }
194
+ throw new TypeError(
195
+ `"appliesDuring" must be an object or a string, got ${appliesDuring}`,
196
+ );
197
+ };
@@ -142,7 +142,7 @@ export const jsenvPluginDirectoryListing = ({
142
142
  };
143
143
  },
144
144
  },
145
- devServerRoutes: [
145
+ serverRoutes: [
146
146
  {
147
147
  endpoint:
148
148
  "GET /.internal/directory_content.websocket?directory=:directory",
@@ -90,7 +90,7 @@ export const jsenvPluginServerEvents = ({ clientAutoreload }) => {
90
90
  return stringifyHtmlAst(htmlAst);
91
91
  },
92
92
  },
93
- devServerRoutes: [
93
+ serverRoutes: [
94
94
  {
95
95
  endpoint: "GET /.internal/events.websocket",
96
96
  description: `Jsenv dev server emit server events on this endpoint. When a file is saved the "reload" event is sent here.`,