@jsenv/core 39.1.3 → 39.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 CHANGED
@@ -10,29 +10,32 @@ Jsenv is a suite of tools that can be used in projects involving JavaScript.
10
10
  4. **test runner**; execute all test files at once
11
11
 
12
12
  It favors standards and simplicity.
13
- As a result it can be enjoyed by people without much experience in tooling or seeking for simple tools without hidden complexities
13
+ As a result it can be enjoyed by people without much experience in tooling or seeking for simple tools without hidden complexities.
14
14
 
15
- Now what do you want to do?
15
+ If you want to try jsenv on your machine, use [#CLI](#cli).
16
16
 
17
- | Scenario | Action |
18
- | ----------------------------------------------------- | ---------------------------------------------------- |
19
- | I want to try a demo on my machine | Go to [./demos](#demos) |
20
- | I want to try jsenv on a project I have on my machine | Go to [./cli](#cli) |
21
- | I want to learn how to use jsenv | Go to [./docs/users/users.md](./docs/users/users.md) |
17
+ Link to [documentation](./docs/users/users.md)
22
18
 
23
- # Demos
19
+ # CLI
20
+
21
+ The following command helps to init jsenv on your machine.
22
+
23
+ ```console
24
+ npm @jsenv/cli
25
+ ```
24
26
 
25
- A demo is a project pre-configured with jsenv.
26
- The following command can be used to install and try a demo:
27
+ CLI will init jsenv in a directory. It can be a new directory or an existing one.
27
28
 
28
29
  ```console
29
- npm create jsenv@latest
30
+ Welcome in jsenv CLI
31
+ ? Enter a directory: ›
30
32
  ```
31
33
 
32
- It will prompt to choose one of the available demo:
34
+ Then you'll be prompted to select a template.
33
35
 
34
36
  ```console
35
- ? Select a demo: › - Use arrow-keys. Return to submit.
37
+ Enter a directory: › demo
38
+ ? Select a template: › - Use arrow-keys. Return to submit.
36
39
  ❯ web
37
40
  web-components
38
41
  web-react
@@ -40,41 +43,27 @@ It will prompt to choose one of the available demo:
40
43
  node-package
41
44
  ```
42
45
 
43
- Selecting "web" will copy [create-jsenv/demo-web/](./packages/related/create-jsenv/demo-web/) files into a directory:
46
+ A template is a project pre-configured with jsenv.
47
+ Selecting "web" would init [demo-web/](./packages/related/cli/demo-web/):
44
48
 
45
49
  ```console
46
- Select a demo: › web
47
- copy demo files into "[...]jsenv-demo-web/" (done in 0.1 second)
48
- ----- commands to run -----
49
- cd jsenv-demo-web
50
+ Enter a directory: › demo
51
+ Select a template: web
52
+ init jsenv in "[...]/demo/" (done in 0.01 second)
53
+ ----- 2 commands to run -----
54
+ cd demo
50
55
  npm install
51
- npm start
52
- ---------------------------
56
+ -----------------------------
53
57
  ```
54
58
 
55
- After running the suggested commands the demo is ready.
56
-
57
- The demo contains preconfigured scripts:
59
+ The templates have installed scripts:
58
60
 
59
61
  - `npm run dev`: starts a server for source files; Documented in [B) Dev](./docs/users/b_dev/b_dev.md).
60
62
  - `npm run build`: generate build files; Documented in [C) Build](./docs/users/c_build/c_build.md).
61
63
  - `npm run build:serve`: start a server for build files; Documented in [C) Build#how-to-serve-build-files](./docs/users/c_build/c_build.md#3-how-to-serve-build-files).
62
64
  - `npm run test`: execute test files; Documented in [D) Test](./docs/users/d_test/d_test.md).
63
65
 
64
- # CLI
65
-
66
- Jsenv commands to test it quickly.
67
-
68
- | I want to | Command |
69
- | ------------------------------------- | ------------------------ |
70
- | Start a local server for source files | `npx @jsenv/cli dev` |
71
- | Build source files into "./dist/" | `npx @jsenv/cli build` |
72
- | Start a local server for build files | `npx @jsenv/cli preview` |
73
- | Run all test files | `npx @jsenv/cli test` |
74
-
75
- The commands are very basic, for advanced use cases you should use jsenv API.
76
-
77
- For example in order to start a dev server you would rather do `npm run dev` that would be declared in [package.json#scripts.dev](./packages/related/create-jsenv/demo-web/package.json#L8) to execute [scripts/dev.mjs](./packages/related/create-jsenv/demo-web/scripts/dev.mjs).
66
+ <!-- For example in order to start a dev server you would rather do `npm run dev` that would be declared in [package.json#scripts.dev](./packages/related/create-jsenv/demo-web/package.json#L8) to execute [scripts/dev.mjs](./packages/related/create-jsenv/demo-web/scripts/dev.mjs). -->
78
67
 
79
68
  # The best parts
80
69
 
@@ -2092,18 +2092,26 @@ const setUrlFilename = (url, filename) => {
2092
2092
  };
2093
2093
 
2094
2094
  const ensurePathnameTrailingSlash = (url) => {
2095
- const urlObject = new URL(url);
2096
- const { pathname } = urlObject;
2097
- if (pathname.endsWith("/")) {
2098
- return url;
2095
+ if (typeof url === "string") {
2096
+ const urlObject = new URL(url);
2097
+ const { pathname } = urlObject;
2098
+ if (pathname.endsWith("/")) {
2099
+ return url;
2100
+ }
2101
+ let { origin } = urlObject;
2102
+ // origin is "null" for "file://" urls with Node.js
2103
+ if (origin === "null" && urlObject.href.startsWith("file:")) {
2104
+ origin = "file://";
2105
+ }
2106
+ const { search, hash } = urlObject;
2107
+ const urlWithTrailingSlash = `${origin}${pathname}/${search}${hash}`;
2108
+ return urlWithTrailingSlash;
2099
2109
  }
2100
- let { origin } = urlObject;
2101
- // origin is "null" for "file://" urls with Node.js
2102
- if (origin === "null" && urlObject.href.startsWith("file:")) {
2103
- origin = "file://";
2110
+ if (url.pathname.endsWith("/")) {
2111
+ return url;
2104
2112
  }
2105
- const { search, hash } = urlObject;
2106
- return `${origin}${pathname}/${search}${hash}`;
2113
+ url.pathname += "/";
2114
+ return url;
2107
2115
  };
2108
2116
 
2109
2117
  const isFileSystemPath$1 = (value) => {
@@ -11558,6 +11566,7 @@ const createDependencies = (ownerUrlInfo) => {
11558
11566
  isOriginalPosition,
11559
11567
  specifierLine,
11560
11568
  specifierColumn,
11569
+ content,
11561
11570
  ...rest
11562
11571
  }) => {
11563
11572
  const parentUrl = isOriginalPosition
@@ -11578,6 +11587,7 @@ const createDependencies = (ownerUrlInfo) => {
11578
11587
  specifierLine,
11579
11588
  specifierColumn,
11580
11589
  isInline: true,
11590
+ content,
11581
11591
  ...rest,
11582
11592
  });
11583
11593
  return reference;
@@ -11905,6 +11915,12 @@ const createReference = ({
11905
11915
  ownerUrlInfo = reference.ownerUrlInfo,
11906
11916
  ...props
11907
11917
  }) => {
11918
+ const content =
11919
+ ownerUrlInfo === undefined
11920
+ ? isOriginalPosition
11921
+ ? reference.ownerUrlInfo.originalContent
11922
+ : reference.ownerUrlInfo.content
11923
+ : ownerUrlInfo.content;
11908
11924
  const trace = traceFromUrlSite({
11909
11925
  url:
11910
11926
  ownerUrlInfo === undefined
@@ -11912,12 +11928,7 @@ const createReference = ({
11912
11928
  ? reference.ownerUrlInfo.url
11913
11929
  : reference.ownerUrlInfo.generatedUrl
11914
11930
  : reference.ownerUrlInfo.url,
11915
- content:
11916
- ownerUrlInfo === undefined
11917
- ? isOriginalPosition
11918
- ? reference.ownerUrlInfo.originalContent
11919
- : reference.ownerUrlInfo.content
11920
- : ownerUrlInfo.content,
11931
+ content,
11921
11932
  line,
11922
11933
  column,
11923
11934
  });
@@ -12114,14 +12125,15 @@ const applyDependencyRemovalEffects = (reference) => {
12114
12125
  };
12115
12126
 
12116
12127
  const traceFromUrlSite = (urlSite) => {
12128
+ const codeFrame = urlSite.content
12129
+ ? generateContentFrame({
12130
+ content: urlSite.content,
12131
+ line: urlSite.line,
12132
+ column: urlSite.column,
12133
+ })
12134
+ : "";
12117
12135
  return {
12118
- codeFrame: urlSite.content
12119
- ? generateContentFrame({
12120
- content: urlSite.content,
12121
- line: urlSite.line,
12122
- column: urlSite.column,
12123
- })
12124
- : "",
12136
+ codeFrame,
12125
12137
  message: stringifyUrlSite(urlSite),
12126
12138
  url: urlSite.url,
12127
12139
  line: urlSite.line,
@@ -12131,7 +12143,7 @@ const traceFromUrlSite = (urlSite) => {
12131
12143
 
12132
12144
  const adjustUrlSite = (urlInfo, { url, line, column }) => {
12133
12145
  const isOriginal = url === urlInfo.url;
12134
- const adjust = (urlSite, urlInfo) => {
12146
+ const adjust = (urlInfo, urlSite) => {
12135
12147
  if (!urlSite.isOriginal) {
12136
12148
  return urlSite;
12137
12149
  }
@@ -12140,33 +12152,35 @@ const adjustUrlSite = (urlInfo, { url, line, column }) => {
12140
12152
  return urlSite;
12141
12153
  }
12142
12154
  const parentUrlInfo = urlInfo.graph.getUrlInfo(inlineUrlSite.url);
12143
- return adjust(
12144
- {
12145
- isOriginal: true,
12146
- url: inlineUrlSite.url,
12147
- content: inlineUrlSite.content,
12148
- line:
12149
- inlineUrlSite.line === undefined
12150
- ? urlSite.line
12151
- : inlineUrlSite.line + urlSite.line,
12152
- column:
12153
- inlineUrlSite.column === undefined
12154
- ? urlSite.column
12155
- : inlineUrlSite.column + urlSite.column,
12156
- },
12157
- parentUrlInfo,
12158
- );
12159
- };
12160
- return adjust(
12161
- {
12162
- isOriginal,
12163
- url,
12164
- content: isOriginal ? urlInfo.originalContent : urlInfo.content,
12155
+ line =
12156
+ inlineUrlSite.line === undefined
12157
+ ? urlSite.line
12158
+ : inlineUrlSite.line + urlSite.line;
12159
+ // we remove 1 to the line because imagine the following html:
12160
+ // <style>body { color: red; }</style>
12161
+ // -> content starts same line as <style> (same for <script>)
12162
+ if (urlInfo.content[0] === "\n") {
12163
+ line = line - 1;
12164
+ }
12165
+ column =
12166
+ inlineUrlSite.column === undefined
12167
+ ? urlSite.column
12168
+ : inlineUrlSite.column + urlSite.column;
12169
+ return adjust(parentUrlInfo, {
12170
+ isOriginal: true,
12171
+ url: inlineUrlSite.url,
12172
+ content: inlineUrlSite.content,
12165
12173
  line,
12166
12174
  column,
12167
- },
12168
- urlInfo,
12169
- );
12175
+ });
12176
+ };
12177
+ return adjust(urlInfo, {
12178
+ isOriginal,
12179
+ url,
12180
+ content: isOriginal ? urlInfo.originalContent : urlInfo.content,
12181
+ line,
12182
+ column,
12183
+ });
12170
12184
  };
12171
12185
 
12172
12186
  const getRedirectedReferenceProps = (reference, url) => {
@@ -13686,13 +13700,16 @@ const createResolveUrlError = ({
13686
13700
  ...details
13687
13701
  }) => {
13688
13702
  const resolveError = new Error(
13689
- createDetailedMessage$1(`Failed to resolve url reference`, {
13690
- reason,
13691
- ...details,
13692
- "specifier": `"${reference.specifier}"`,
13693
- "specifier trace": reference.trace.message,
13694
- ...detailsFromPluginController(pluginController),
13695
- }),
13703
+ createDetailedMessage$1(
13704
+ `Failed to resolve url reference
13705
+ ${reference.trace.message}
13706
+ ${reason}`,
13707
+ {
13708
+ ...detailsFromFirstReference(reference),
13709
+ ...details,
13710
+ ...detailsFromPluginController(pluginController),
13711
+ },
13712
+ ),
13696
13713
  );
13697
13714
  resolveError.name = "RESOLVE_URL_ERROR";
13698
13715
  resolveError.code = code;
@@ -13727,14 +13744,18 @@ const createFetchUrlContentError = ({
13727
13744
  reason,
13728
13745
  ...details
13729
13746
  }) => {
13747
+ const reference = urlInfo.firstReference;
13730
13748
  const fetchError = new Error(
13731
- createDetailedMessage$1(`Failed to fetch url content`, {
13732
- reason,
13733
- ...details,
13734
- "url": urlInfo.url,
13735
- "url reference trace": urlInfo.firstReference.trace.message,
13736
- ...detailsFromPluginController(pluginController),
13737
- }),
13749
+ createDetailedMessage$1(
13750
+ `Failed to fetch url content
13751
+ ${reference.trace.message}
13752
+ ${reason}`,
13753
+ {
13754
+ ...detailsFromFirstReference(reference),
13755
+ ...details,
13756
+ ...detailsFromPluginController(pluginController),
13757
+ },
13758
+ ),
13738
13759
  );
13739
13760
  fetchError.name = "FETCH_URL_CONTENT_ERROR";
13740
13761
  fetchError.code = code;
@@ -13743,7 +13764,7 @@ const createFetchUrlContentError = ({
13743
13764
  if (code === "PARSE_ERROR") {
13744
13765
  fetchError.trace = error.trace;
13745
13766
  } else {
13746
- fetchError.trace = urlInfo.firstReference.trace;
13767
+ fetchError.trace = reference.trace;
13747
13768
  }
13748
13769
  fetchError.asResponse = error.asResponse;
13749
13770
  return fetchError;
@@ -13792,73 +13813,101 @@ const createTransformUrlContentError = ({
13792
13813
  urlInfo,
13793
13814
  error,
13794
13815
  }) => {
13816
+ if (error.code === "MODULE_NOT_FOUND") {
13817
+ return error;
13818
+ }
13795
13819
  if (error.code === "DIRECTORY_REFERENCE_NOT_ALLOWED") {
13796
13820
  return error;
13797
13821
  }
13822
+ if (error.code === "PARSE_ERROR") {
13823
+ const reference = urlInfo.firstReference;
13824
+ let trace = reference.trace;
13825
+ let line = error.line;
13826
+ let column = error.column;
13827
+ if (urlInfo.isInline) {
13828
+ line = trace.line + line;
13829
+ line = line - 1;
13830
+ trace = {
13831
+ ...trace,
13832
+ line,
13833
+ column,
13834
+ codeFrame: generateContentFrame({
13835
+ line,
13836
+ column,
13837
+ content: urlInfo.inlineUrlSite.content,
13838
+ }),
13839
+ message: stringifyUrlSite({
13840
+ url: urlInfo.inlineUrlSite.url,
13841
+ line,
13842
+ column,
13843
+ content: urlInfo.inlineUrlSite.content,
13844
+ }),
13845
+ };
13846
+ } else {
13847
+ trace = {
13848
+ url: urlInfo.url,
13849
+ line,
13850
+ column: error.column,
13851
+ codeFrame: generateContentFrame({
13852
+ line,
13853
+ column: error.column,
13854
+ content: urlInfo.content,
13855
+ }),
13856
+ message: stringifyUrlSite({
13857
+ url: urlInfo.url,
13858
+ line,
13859
+ column: error.column,
13860
+ content: urlInfo.content,
13861
+ }),
13862
+ };
13863
+ }
13864
+ const transformError = new Error(
13865
+ createDetailedMessage$1(
13866
+ `parse error on "${urlInfo.type}"
13867
+ ${trace.message}
13868
+ ${error.message}`,
13869
+ {
13870
+ "first reference": `${reference.trace.url}:${reference.trace.line}:${reference.trace.column}`,
13871
+ ...detailsFromFirstReference(reference),
13872
+ ...detailsFromPluginController(pluginController),
13873
+ },
13874
+ ),
13875
+ );
13876
+ transformError.cause = error;
13877
+ transformError.name = "TRANSFORM_URL_CONTENT_ERROR";
13878
+ transformError.code = "PARSE_ERROR";
13879
+ transformError.stack = error.stack;
13880
+ transformError.reason = error.message;
13881
+ transformError.trace = trace;
13882
+ transformError.asResponse = error.asResponse;
13883
+ return transformError;
13884
+ }
13798
13885
  const createFailedToTransformError = ({
13799
13886
  code = error.code || "TRANSFORM_URL_CONTENT_ERROR",
13800
13887
  reason,
13801
13888
  ...details
13802
13889
  }) => {
13890
+ const reference = urlInfo.firstReference;
13891
+ let trace = reference.trace;
13803
13892
  const transformError = new Error(
13804
13893
  createDetailedMessage$1(
13805
- `"transformUrlContent" error on "${urlInfo.type}"`,
13894
+ `"transformUrlContent" error on "${urlInfo.type}"
13895
+ ${trace.message}
13896
+ ${reason}`,
13806
13897
  {
13807
- reason,
13898
+ ...detailsFromFirstReference(reference),
13808
13899
  ...details,
13809
- "url": urlInfo.url,
13810
- "url reference trace": urlInfo.firstReference.trace.message,
13811
13900
  ...detailsFromPluginController(pluginController),
13812
13901
  },
13813
13902
  ),
13814
13903
  );
13904
+ transformError.cause = error;
13815
13905
  transformError.name = "TRANSFORM_URL_CONTENT_ERROR";
13816
13906
  transformError.code = code;
13817
13907
  transformError.reason = reason;
13818
13908
  transformError.stack = error.stack;
13819
13909
  transformError.url = urlInfo.url;
13820
- transformError.trace = urlInfo.firstReference.trace;
13821
- if (code === "PARSE_ERROR") {
13822
- transformError.reason = `parse error on ${urlInfo.type}`;
13823
- transformError.cause = error;
13824
- let line = error.line;
13825
- if (urlInfo.type === "js_module") {
13826
- line = line - 1;
13827
- }
13828
- if (urlInfo.isInline) {
13829
- transformError.trace.line = urlInfo.firstReference.trace.line + line;
13830
- transformError.trace.column =
13831
- urlInfo.firstReference.trace.column + error.column;
13832
- transformError.trace.codeFrame = generateContentFrame({
13833
- line: transformError.trace.line,
13834
- column: transformError.trace.column,
13835
- content: urlInfo.inlineUrlSite.content,
13836
- });
13837
- transformError.trace.message = stringifyUrlSite({
13838
- url: urlInfo.inlineUrlSite.url,
13839
- line: transformError.trace.line,
13840
- column: transformError.trace.column,
13841
- content: urlInfo.inlineUrlSite.content,
13842
- });
13843
- } else {
13844
- transformError.trace = {
13845
- url: urlInfo.url,
13846
- line,
13847
- column: error.column,
13848
- codeFrame: generateContentFrame({
13849
- line,
13850
- column: error.column,
13851
- content: urlInfo.content,
13852
- }),
13853
- message: stringifyUrlSite({
13854
- url: urlInfo.url,
13855
- line,
13856
- column: error.column,
13857
- content: urlInfo.content,
13858
- }),
13859
- };
13860
- }
13861
- }
13910
+ transformError.trace = trace;
13862
13911
  transformError.asResponse = error.asResponse;
13863
13912
  return transformError;
13864
13913
  };
@@ -13870,17 +13919,20 @@ const createTransformUrlContentError = ({
13870
13919
 
13871
13920
  const createFinalizeUrlContentError = ({
13872
13921
  pluginController,
13873
-
13874
13922
  urlInfo,
13875
13923
  error,
13876
13924
  }) => {
13925
+ const reference = urlInfo.firstReference;
13877
13926
  const finalizeError = new Error(
13878
- createDetailedMessage$1(`"finalizeUrlContent" error on "${urlInfo.type}"`, {
13879
- ...detailsFromValueThrown(error),
13880
- "url": urlInfo.url,
13881
- "url reference trace": urlInfo.firstReference.trace.message,
13882
- ...detailsFromPluginController(pluginController),
13883
- }),
13927
+ createDetailedMessage$1(
13928
+ `"finalizeUrlContent" error on "${urlInfo.type}"
13929
+ ${reference.trace.message}`,
13930
+ {
13931
+ ...detailsFromFirstReference(reference),
13932
+ ...detailsFromValueThrown(error),
13933
+ ...detailsFromPluginController(pluginController),
13934
+ },
13935
+ ),
13884
13936
  );
13885
13937
  if (error && error instanceof Error) {
13886
13938
  finalizeError.cause = error;
@@ -13891,6 +13943,23 @@ const createFinalizeUrlContentError = ({
13891
13943
  return finalizeError;
13892
13944
  };
13893
13945
 
13946
+ const detailsFromFirstReference = (reference) => {
13947
+ const referenceInProject = getFirstReferenceInProject(reference);
13948
+ if (referenceInProject === reference) {
13949
+ return {};
13950
+ }
13951
+ return {
13952
+ "first reference in project": `${referenceInProject.trace.url}:${referenceInProject.trace.line}:${referenceInProject.trace.column}`,
13953
+ };
13954
+ };
13955
+ const getFirstReferenceInProject = (reference) => {
13956
+ const ownerUrlInfo = reference.ownerUrlInfo;
13957
+ if (!ownerUrlInfo.url.includes("/node_modules/")) {
13958
+ return reference;
13959
+ }
13960
+ return getFirstReferenceInProject(ownerUrlInfo.firstReference);
13961
+ };
13962
+
13894
13963
  const detailsFromPluginController = (pluginController) => {
13895
13964
  const currentPlugin = pluginController.getCurrentPlugin();
13896
13965
  if (!currentPlugin) {
@@ -13901,6 +13970,18 @@ const detailsFromPluginController = (pluginController) => {
13901
13970
 
13902
13971
  const detailsFromValueThrown = (valueThrownByPlugin) => {
13903
13972
  if (valueThrownByPlugin && valueThrownByPlugin instanceof Error) {
13973
+ if (
13974
+ valueThrownByPlugin.code === "PARSE_ERROR" ||
13975
+ valueThrownByPlugin.code === "MODULE_NOT_FOUND" ||
13976
+ valueThrownByPlugin.name === "RESOLVE_URL_ERROR" ||
13977
+ valueThrownByPlugin.name === "FETCH_URL_CONTENT_ERROR" ||
13978
+ valueThrownByPlugin.name === "TRANSFORM_URL_CONTENT_ERROR" ||
13979
+ valueThrownByPlugin.name === "FINALIZE_URL_CONTENT_ERROR"
13980
+ ) {
13981
+ return {
13982
+ "error message": valueThrownByPlugin.message,
13983
+ };
13984
+ }
13904
13985
  return {
13905
13986
  "error stack": valueThrownByPlugin.stack,
13906
13987
  };
@@ -14520,16 +14601,21 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
14520
14601
  e.code !== "DIRECTORY_REFERENCE_NOT_ALLOWED" &&
14521
14602
  errorOnInlineContentCanSkipThrow(urlInfo)
14522
14603
  ) {
14523
- const errorInfo =
14524
- e.code === "PARSE_ERROR" && e.cause
14525
- ? `${e.cause.reasonCode}\n${e.trace?.message}`
14526
- : e.stack;
14527
14604
  // When something like <style> or <script> contains syntax error
14528
14605
  // the HTML in itself it still valid
14529
14606
  // keep the syntax error and continue with the HTML
14607
+ if (e.code === "PARSE_ERROR") {
14608
+ logger.error(`parse error on "${urlInfo.type}"
14609
+ ${e.trace?.message}
14610
+ ${e.reason}
14611
+ --- declared in ---
14612
+ ${urlInfo.firstReference.trace.message}`);
14613
+ return;
14614
+ }
14530
14615
  logger.error(
14531
- `Error while cooking ${urlInfo.type} declared in ${urlInfo.firstReference.trace.message}:
14532
- ${errorInfo}`,
14616
+ `Error while cooking ${urlInfo.type}
14617
+ ${urlInfo.firstReference.trace.message}
14618
+ ${e.stack}`,
14533
14619
  );
14534
14620
  return;
14535
14621
  }
@@ -16101,10 +16187,7 @@ const jsenvPluginHtmlReferenceAnalysis = ({
16101
16187
  type,
16102
16188
  expectedType,
16103
16189
  isOriginalPosition: isOriginal,
16104
- // we remove 1 to the line because imagine the following html:
16105
- // <style>body { color: red; }</style>
16106
- // -> content starts same line as <style> (same for <script>)
16107
- specifierLine: line - 1,
16190
+ specifierLine: line,
16108
16191
  specifierColumn: column,
16109
16192
  specifier: inlineContentUrl,
16110
16193
  contentType,
@@ -16223,7 +16306,7 @@ const jsenvPluginHtmlReferenceAnalysis = ({
16223
16306
  },
16224
16307
  );
16225
16308
  const importmapReferenceInlined = importmapReference.inline({
16226
- line: line - 1,
16309
+ line,
16227
16310
  column,
16228
16311
  isOriginal,
16229
16312
  specifier: importmapInlineUrl,
@@ -18777,7 +18860,7 @@ const jsenvPluginInliningIntoHtml = () => {
18777
18860
  url: linkReference.url,
18778
18861
  });
18779
18862
  const linkReferenceInlined = linkReference.inline({
18780
- line: line - 1,
18863
+ line,
18781
18864
  column,
18782
18865
  isOriginal,
18783
18866
  specifier: linkInlineUrl,
@@ -18829,7 +18912,7 @@ const jsenvPluginInliningIntoHtml = () => {
18829
18912
  url: scriptReference.url,
18830
18913
  });
18831
18914
  const scriptReferenceInlined = scriptReference.inline({
18832
- line: line - 1,
18915
+ line,
18833
18916
  column,
18834
18917
  isOriginal,
18835
18918
  specifier: scriptInlineUrl,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "39.1.3",
3
+ "version": "39.2.1",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -40,47 +40,47 @@
40
40
  "./packages/independent/*",
41
41
  "./packages/internal/*",
42
42
  "./packages/related/*",
43
- "./packages/related/create-jsenv/*"
43
+ "./packages/related/cli/*"
44
44
  ],
45
45
  "scripts": {
46
46
  "eslint": "npx eslint . --ext=.js,.mjs,.cjs,.html",
47
- "dev": "node --conditions=development ./scripts/dev/dev.mjs",
48
47
  "test": "node --conditions=development ./scripts/test/test.mjs",
49
- "test:workspace": "npm run test --workspaces --if-present -- --workspace",
50
- "test:ci": "CI=1 npm run test",
51
- "test:workspace:ci": "CI=1 npm run test:workspace",
52
- "test:only_dev_server_errors": "node --conditions=development ./tests/dev_server/errors/dev_errors_snapshots.test.mjs",
53
48
  "build": "node --conditions=development ./scripts/build/build.mjs",
54
- "build:file_size": "node ./scripts/build/build_file_size.mjs --log",
55
- "build:workspace": "npm run build --workspaces --if-present --conditions=developement",
56
- "monorepo:upgrade_versions": "node ./scripts/monorepo/upgrade_external_versions.mjs",
49
+ "workspace:test": "npm run test --workspaces --if-present -- --workspace",
50
+ "workspace:build": "npm run build --workspaces --if-present --conditions=developement",
57
51
  "monorepo:sync_packages_versions": "node ./scripts/monorepo/sync_packages_versions.mjs",
58
52
  "monorepo:publish": "node ./scripts/monorepo/publish_packages.mjs",
53
+ "monorepo:upgrade_versions": "node ./scripts/monorepo/upgrade_external_versions.mjs",
59
54
  "monorepo:node_modules_clear": "npx @jsenv/snapshot clear **/node_modules/",
55
+ "build:file_size": "node ./scripts/build/build_file_size.mjs --log",
60
56
  "performances": "node --expose-gc ./scripts/performance/generate_performance_report.mjs --log --once",
61
57
  "prettier": "prettier --write .",
58
+ "test:ci": "CI=1 npm run test",
59
+ "test:only_dev_server_errors": "node --conditions=development ./tests/dev_server/errors/dev_errors_snapshots.test.mjs",
60
+ "workspace:test:ci": "CI=1 npm run workspace:test",
61
+ "dev": "node --conditions=development ./scripts/dev/dev.mjs",
62
62
  "certificate:install": "node ./scripts/dev/install_certificate_authority.mjs",
63
63
  "prepublishOnly": "npm run build"
64
64
  },
65
65
  "dependencies": {
66
66
  "@financial-times/polyfill-useragent-normaliser": "1.10.2",
67
67
  "@jsenv/abort": "4.3.0",
68
- "@jsenv/ast": "6.2.2",
69
- "@jsenv/filesystem": "4.8.0",
68
+ "@jsenv/ast": "6.2.3",
69
+ "@jsenv/filesystem": "4.8.1",
70
70
  "@jsenv/humanize": "1.2.4",
71
71
  "@jsenv/importmap": "1.2.1",
72
72
  "@jsenv/integrity": "0.0.2",
73
- "@jsenv/js-module-fallback": "1.3.23",
73
+ "@jsenv/js-module-fallback": "1.3.24",
74
74
  "@jsenv/node-esm-resolution": "1.0.2",
75
- "@jsenv/plugin-bundling": "2.6.16",
75
+ "@jsenv/plugin-bundling": "2.6.17",
76
76
  "@jsenv/plugin-minification": "1.5.5",
77
- "@jsenv/plugin-supervisor": "1.5.2",
78
- "@jsenv/plugin-transpilation": "1.4.6",
77
+ "@jsenv/plugin-supervisor": "1.5.4",
78
+ "@jsenv/plugin-transpilation": "1.4.7",
79
79
  "@jsenv/runtime-compat": "1.3.0",
80
80
  "@jsenv/server": "15.2.13",
81
- "@jsenv/sourcemap": "1.2.14",
81
+ "@jsenv/sourcemap": "1.2.15",
82
82
  "@jsenv/url-meta": "8.4.2",
83
- "@jsenv/urls": "2.2.11",
83
+ "@jsenv/urls": "2.3.0",
84
84
  "@jsenv/utils": "2.1.1"
85
85
  },
86
86
  "devDependencies": {
@@ -13,13 +13,16 @@ export const createResolveUrlError = ({
13
13
  ...details
14
14
  }) => {
15
15
  const resolveError = new Error(
16
- createDetailedMessage(`Failed to resolve url reference`, {
17
- reason,
18
- ...details,
19
- "specifier": `"${reference.specifier}"`,
20
- "specifier trace": reference.trace.message,
21
- ...detailsFromPluginController(pluginController),
22
- }),
16
+ createDetailedMessage(
17
+ `Failed to resolve url reference
18
+ ${reference.trace.message}
19
+ ${reason}`,
20
+ {
21
+ ...detailsFromFirstReference(reference),
22
+ ...details,
23
+ ...detailsFromPluginController(pluginController),
24
+ },
25
+ ),
23
26
  );
24
27
  resolveError.name = "RESOLVE_URL_ERROR";
25
28
  resolveError.code = code;
@@ -54,14 +57,18 @@ export const createFetchUrlContentError = ({
54
57
  reason,
55
58
  ...details
56
59
  }) => {
60
+ const reference = urlInfo.firstReference;
57
61
  const fetchError = new Error(
58
- createDetailedMessage(`Failed to fetch url content`, {
59
- reason,
60
- ...details,
61
- "url": urlInfo.url,
62
- "url reference trace": urlInfo.firstReference.trace.message,
63
- ...detailsFromPluginController(pluginController),
64
- }),
62
+ createDetailedMessage(
63
+ `Failed to fetch url content
64
+ ${reference.trace.message}
65
+ ${reason}`,
66
+ {
67
+ ...detailsFromFirstReference(reference),
68
+ ...details,
69
+ ...detailsFromPluginController(pluginController),
70
+ },
71
+ ),
65
72
  );
66
73
  fetchError.name = "FETCH_URL_CONTENT_ERROR";
67
74
  fetchError.code = code;
@@ -70,7 +77,7 @@ export const createFetchUrlContentError = ({
70
77
  if (code === "PARSE_ERROR") {
71
78
  fetchError.trace = error.trace;
72
79
  } else {
73
- fetchError.trace = urlInfo.firstReference.trace;
80
+ fetchError.trace = reference.trace;
74
81
  }
75
82
  fetchError.asResponse = error.asResponse;
76
83
  return fetchError;
@@ -119,73 +126,101 @@ export const createTransformUrlContentError = ({
119
126
  urlInfo,
120
127
  error,
121
128
  }) => {
129
+ if (error.code === "MODULE_NOT_FOUND") {
130
+ return error;
131
+ }
122
132
  if (error.code === "DIRECTORY_REFERENCE_NOT_ALLOWED") {
123
133
  return error;
124
134
  }
135
+ if (error.code === "PARSE_ERROR") {
136
+ const reference = urlInfo.firstReference;
137
+ let trace = reference.trace;
138
+ let line = error.line;
139
+ let column = error.column;
140
+ if (urlInfo.isInline) {
141
+ line = trace.line + line;
142
+ line = line - 1;
143
+ trace = {
144
+ ...trace,
145
+ line,
146
+ column,
147
+ codeFrame: generateContentFrame({
148
+ line,
149
+ column,
150
+ content: urlInfo.inlineUrlSite.content,
151
+ }),
152
+ message: stringifyUrlSite({
153
+ url: urlInfo.inlineUrlSite.url,
154
+ line,
155
+ column,
156
+ content: urlInfo.inlineUrlSite.content,
157
+ }),
158
+ };
159
+ } else {
160
+ trace = {
161
+ url: urlInfo.url,
162
+ line,
163
+ column: error.column,
164
+ codeFrame: generateContentFrame({
165
+ line,
166
+ column: error.column,
167
+ content: urlInfo.content,
168
+ }),
169
+ message: stringifyUrlSite({
170
+ url: urlInfo.url,
171
+ line,
172
+ column: error.column,
173
+ content: urlInfo.content,
174
+ }),
175
+ };
176
+ }
177
+ const transformError = new Error(
178
+ createDetailedMessage(
179
+ `parse error on "${urlInfo.type}"
180
+ ${trace.message}
181
+ ${error.message}`,
182
+ {
183
+ "first reference": `${reference.trace.url}:${reference.trace.line}:${reference.trace.column}`,
184
+ ...detailsFromFirstReference(reference),
185
+ ...detailsFromPluginController(pluginController),
186
+ },
187
+ ),
188
+ );
189
+ transformError.cause = error;
190
+ transformError.name = "TRANSFORM_URL_CONTENT_ERROR";
191
+ transformError.code = "PARSE_ERROR";
192
+ transformError.stack = error.stack;
193
+ transformError.reason = error.message;
194
+ transformError.trace = trace;
195
+ transformError.asResponse = error.asResponse;
196
+ return transformError;
197
+ }
125
198
  const createFailedToTransformError = ({
126
199
  code = error.code || "TRANSFORM_URL_CONTENT_ERROR",
127
200
  reason,
128
201
  ...details
129
202
  }) => {
203
+ const reference = urlInfo.firstReference;
204
+ let trace = reference.trace;
130
205
  const transformError = new Error(
131
206
  createDetailedMessage(
132
- `"transformUrlContent" error on "${urlInfo.type}"`,
207
+ `"transformUrlContent" error on "${urlInfo.type}"
208
+ ${trace.message}
209
+ ${reason}`,
133
210
  {
134
- reason,
211
+ ...detailsFromFirstReference(reference),
135
212
  ...details,
136
- "url": urlInfo.url,
137
- "url reference trace": urlInfo.firstReference.trace.message,
138
213
  ...detailsFromPluginController(pluginController),
139
214
  },
140
215
  ),
141
216
  );
217
+ transformError.cause = error;
142
218
  transformError.name = "TRANSFORM_URL_CONTENT_ERROR";
143
219
  transformError.code = code;
144
220
  transformError.reason = reason;
145
221
  transformError.stack = error.stack;
146
222
  transformError.url = urlInfo.url;
147
- transformError.trace = urlInfo.firstReference.trace;
148
- if (code === "PARSE_ERROR") {
149
- transformError.reason = `parse error on ${urlInfo.type}`;
150
- transformError.cause = error;
151
- let line = error.line;
152
- if (urlInfo.type === "js_module") {
153
- line = line - 1;
154
- }
155
- if (urlInfo.isInline) {
156
- transformError.trace.line = urlInfo.firstReference.trace.line + line;
157
- transformError.trace.column =
158
- urlInfo.firstReference.trace.column + error.column;
159
- transformError.trace.codeFrame = generateContentFrame({
160
- line: transformError.trace.line,
161
- column: transformError.trace.column,
162
- content: urlInfo.inlineUrlSite.content,
163
- });
164
- transformError.trace.message = stringifyUrlSite({
165
- url: urlInfo.inlineUrlSite.url,
166
- line: transformError.trace.line,
167
- column: transformError.trace.column,
168
- content: urlInfo.inlineUrlSite.content,
169
- });
170
- } else {
171
- transformError.trace = {
172
- url: urlInfo.url,
173
- line,
174
- column: error.column,
175
- codeFrame: generateContentFrame({
176
- line,
177
- column: error.column,
178
- content: urlInfo.content,
179
- }),
180
- message: stringifyUrlSite({
181
- url: urlInfo.url,
182
- line,
183
- column: error.column,
184
- content: urlInfo.content,
185
- }),
186
- };
187
- }
188
- }
223
+ transformError.trace = trace;
189
224
  transformError.asResponse = error.asResponse;
190
225
  return transformError;
191
226
  };
@@ -197,17 +232,20 @@ export const createTransformUrlContentError = ({
197
232
 
198
233
  export const createFinalizeUrlContentError = ({
199
234
  pluginController,
200
-
201
235
  urlInfo,
202
236
  error,
203
237
  }) => {
238
+ const reference = urlInfo.firstReference;
204
239
  const finalizeError = new Error(
205
- createDetailedMessage(`"finalizeUrlContent" error on "${urlInfo.type}"`, {
206
- ...detailsFromValueThrown(error),
207
- "url": urlInfo.url,
208
- "url reference trace": urlInfo.firstReference.trace.message,
209
- ...detailsFromPluginController(pluginController),
210
- }),
240
+ createDetailedMessage(
241
+ `"finalizeUrlContent" error on "${urlInfo.type}"
242
+ ${reference.trace.message}`,
243
+ {
244
+ ...detailsFromFirstReference(reference),
245
+ ...detailsFromValueThrown(error),
246
+ ...detailsFromPluginController(pluginController),
247
+ },
248
+ ),
211
249
  );
212
250
  if (error && error instanceof Error) {
213
251
  finalizeError.cause = error;
@@ -218,6 +256,23 @@ export const createFinalizeUrlContentError = ({
218
256
  return finalizeError;
219
257
  };
220
258
 
259
+ const detailsFromFirstReference = (reference) => {
260
+ const referenceInProject = getFirstReferenceInProject(reference);
261
+ if (referenceInProject === reference) {
262
+ return {};
263
+ }
264
+ return {
265
+ "first reference in project": `${referenceInProject.trace.url}:${referenceInProject.trace.line}:${referenceInProject.trace.column}`,
266
+ };
267
+ };
268
+ const getFirstReferenceInProject = (reference) => {
269
+ const ownerUrlInfo = reference.ownerUrlInfo;
270
+ if (!ownerUrlInfo.url.includes("/node_modules/")) {
271
+ return reference;
272
+ }
273
+ return getFirstReferenceInProject(ownerUrlInfo.firstReference);
274
+ };
275
+
221
276
  const detailsFromPluginController = (pluginController) => {
222
277
  const currentPlugin = pluginController.getCurrentPlugin();
223
278
  if (!currentPlugin) {
@@ -228,6 +283,18 @@ const detailsFromPluginController = (pluginController) => {
228
283
 
229
284
  const detailsFromValueThrown = (valueThrownByPlugin) => {
230
285
  if (valueThrownByPlugin && valueThrownByPlugin instanceof Error) {
286
+ if (
287
+ valueThrownByPlugin.code === "PARSE_ERROR" ||
288
+ valueThrownByPlugin.code === "MODULE_NOT_FOUND" ||
289
+ valueThrownByPlugin.name === "RESOLVE_URL_ERROR" ||
290
+ valueThrownByPlugin.name === "FETCH_URL_CONTENT_ERROR" ||
291
+ valueThrownByPlugin.name === "TRANSFORM_URL_CONTENT_ERROR" ||
292
+ valueThrownByPlugin.name === "FINALIZE_URL_CONTENT_ERROR"
293
+ ) {
294
+ return {
295
+ "error message": valueThrownByPlugin.message,
296
+ };
297
+ }
231
298
  return {
232
299
  "error stack": valueThrownByPlugin.stack,
233
300
  };
@@ -487,16 +487,21 @@ ${ANSI.color(normalizedReturnValue, ANSI.YELLOW)}
487
487
  e.code !== "DIRECTORY_REFERENCE_NOT_ALLOWED" &&
488
488
  errorOnInlineContentCanSkipThrow(urlInfo)
489
489
  ) {
490
- const errorInfo =
491
- e.code === "PARSE_ERROR" && e.cause
492
- ? `${e.cause.reasonCode}\n${e.trace?.message}`
493
- : e.stack;
494
490
  // When something like <style> or <script> contains syntax error
495
491
  // the HTML in itself it still valid
496
492
  // keep the syntax error and continue with the HTML
493
+ if (e.code === "PARSE_ERROR") {
494
+ logger.error(`parse error on "${urlInfo.type}"
495
+ ${e.trace?.message}
496
+ ${e.reason}
497
+ --- declared in ---
498
+ ${urlInfo.firstReference.trace.message}`);
499
+ return;
500
+ }
497
501
  logger.error(
498
- `Error while cooking ${urlInfo.type} declared in ${urlInfo.firstReference.trace.message}:
499
- ${errorInfo}`,
502
+ `Error while cooking ${urlInfo.type}
503
+ ${urlInfo.firstReference.trace.message}
504
+ ${e.stack}`,
500
505
  );
501
506
  return;
502
507
  }
@@ -64,6 +64,7 @@ export const createDependencies = (ownerUrlInfo) => {
64
64
  isOriginalPosition,
65
65
  specifierLine,
66
66
  specifierColumn,
67
+ content,
67
68
  ...rest
68
69
  }) => {
69
70
  const parentUrl = isOriginalPosition
@@ -84,6 +85,7 @@ export const createDependencies = (ownerUrlInfo) => {
84
85
  specifierLine,
85
86
  specifierColumn,
86
87
  isInline: true,
88
+ content,
87
89
  ...rest,
88
90
  });
89
91
  return reference;
@@ -411,6 +413,12 @@ const createReference = ({
411
413
  ownerUrlInfo = reference.ownerUrlInfo,
412
414
  ...props
413
415
  }) => {
416
+ const content =
417
+ ownerUrlInfo === undefined
418
+ ? isOriginalPosition
419
+ ? reference.ownerUrlInfo.originalContent
420
+ : reference.ownerUrlInfo.content
421
+ : ownerUrlInfo.content;
414
422
  const trace = traceFromUrlSite({
415
423
  url:
416
424
  ownerUrlInfo === undefined
@@ -418,12 +426,7 @@ const createReference = ({
418
426
  ? reference.ownerUrlInfo.url
419
427
  : reference.ownerUrlInfo.generatedUrl
420
428
  : reference.ownerUrlInfo.url,
421
- content:
422
- ownerUrlInfo === undefined
423
- ? isOriginalPosition
424
- ? reference.ownerUrlInfo.originalContent
425
- : reference.ownerUrlInfo.content
426
- : ownerUrlInfo.content,
429
+ content,
427
430
  line,
428
431
  column,
429
432
  });
@@ -620,14 +623,15 @@ const applyDependencyRemovalEffects = (reference) => {
620
623
  };
621
624
 
622
625
  const traceFromUrlSite = (urlSite) => {
626
+ const codeFrame = urlSite.content
627
+ ? generateContentFrame({
628
+ content: urlSite.content,
629
+ line: urlSite.line,
630
+ column: urlSite.column,
631
+ })
632
+ : "";
623
633
  return {
624
- codeFrame: urlSite.content
625
- ? generateContentFrame({
626
- content: urlSite.content,
627
- line: urlSite.line,
628
- column: urlSite.column,
629
- })
630
- : "",
634
+ codeFrame,
631
635
  message: stringifyUrlSite(urlSite),
632
636
  url: urlSite.url,
633
637
  line: urlSite.line,
@@ -637,7 +641,7 @@ const traceFromUrlSite = (urlSite) => {
637
641
 
638
642
  const adjustUrlSite = (urlInfo, { url, line, column }) => {
639
643
  const isOriginal = url === urlInfo.url;
640
- const adjust = (urlSite, urlInfo) => {
644
+ const adjust = (urlInfo, urlSite) => {
641
645
  if (!urlSite.isOriginal) {
642
646
  return urlSite;
643
647
  }
@@ -646,33 +650,35 @@ const adjustUrlSite = (urlInfo, { url, line, column }) => {
646
650
  return urlSite;
647
651
  }
648
652
  const parentUrlInfo = urlInfo.graph.getUrlInfo(inlineUrlSite.url);
649
- return adjust(
650
- {
651
- isOriginal: true,
652
- url: inlineUrlSite.url,
653
- content: inlineUrlSite.content,
654
- line:
655
- inlineUrlSite.line === undefined
656
- ? urlSite.line
657
- : inlineUrlSite.line + urlSite.line,
658
- column:
659
- inlineUrlSite.column === undefined
660
- ? urlSite.column
661
- : inlineUrlSite.column + urlSite.column,
662
- },
663
- parentUrlInfo,
664
- );
665
- };
666
- return adjust(
667
- {
668
- isOriginal,
669
- url,
670
- content: isOriginal ? urlInfo.originalContent : urlInfo.content,
653
+ line =
654
+ inlineUrlSite.line === undefined
655
+ ? urlSite.line
656
+ : inlineUrlSite.line + urlSite.line;
657
+ // we remove 1 to the line because imagine the following html:
658
+ // <style>body { color: red; }</style>
659
+ // -> content starts same line as <style> (same for <script>)
660
+ if (urlInfo.content[0] === "\n") {
661
+ line = line - 1;
662
+ }
663
+ column =
664
+ inlineUrlSite.column === undefined
665
+ ? urlSite.column
666
+ : inlineUrlSite.column + urlSite.column;
667
+ return adjust(parentUrlInfo, {
668
+ isOriginal: true,
669
+ url: inlineUrlSite.url,
670
+ content: inlineUrlSite.content,
671
671
  line,
672
672
  column,
673
- },
674
- urlInfo,
675
- );
673
+ });
674
+ };
675
+ return adjust(urlInfo, {
676
+ isOriginal,
677
+ url,
678
+ content: isOriginal ? urlInfo.originalContent : urlInfo.content,
679
+ line,
680
+ column,
681
+ });
676
682
  };
677
683
 
678
684
  const getRedirectedReferenceProps = (reference, url) => {
@@ -47,7 +47,7 @@ export const jsenvPluginInliningIntoHtml = () => {
47
47
  url: linkReference.url,
48
48
  });
49
49
  const linkReferenceInlined = linkReference.inline({
50
- line: line - 1,
50
+ line,
51
51
  column,
52
52
  isOriginal,
53
53
  specifier: linkInlineUrl,
@@ -99,7 +99,7 @@ export const jsenvPluginInliningIntoHtml = () => {
99
99
  url: scriptReference.url,
100
100
  });
101
101
  const scriptReferenceInlined = scriptReference.inline({
102
- line: line - 1,
102
+ line,
103
103
  column,
104
104
  isOriginal,
105
105
  specifier: scriptInlineUrl,
@@ -264,10 +264,7 @@ export const jsenvPluginHtmlReferenceAnalysis = ({
264
264
  type,
265
265
  expectedType,
266
266
  isOriginalPosition: isOriginal,
267
- // we remove 1 to the line because imagine the following html:
268
- // <style>body { color: red; }</style>
269
- // -> content starts same line as <style> (same for <script>)
270
- specifierLine: line - 1,
267
+ specifierLine: line,
271
268
  specifierColumn: column,
272
269
  specifier: inlineContentUrl,
273
270
  contentType,
@@ -386,7 +383,7 @@ export const jsenvPluginHtmlReferenceAnalysis = ({
386
383
  },
387
384
  );
388
385
  const importmapReferenceInlined = importmapReference.inline({
389
- line: line - 1,
386
+ line,
390
387
  column,
391
388
  isOriginal,
392
389
  specifier: importmapInlineUrl,