@jsenv/ast 3.0.7 → 3.0.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/ast",
3
- "version": "3.0.7",
3
+ "version": "3.0.8",
4
4
  "description": "Parse and transform HTML,CSS and JS",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,6 +1,6 @@
1
- import { fileURLToPath } from "node:url"
1
+ import { fileURLToPath } from "node:url";
2
2
 
3
- import { createCssParseError } from "./css_parse_error.js"
3
+ import { createCssParseError } from "./css_parse_error.js";
4
4
 
5
5
  export const applyPostCss = async ({
6
6
  sourcemaps = "comment",
@@ -11,10 +11,10 @@ export const applyPostCss = async ({
11
11
  map,
12
12
  content,
13
13
  }) => {
14
- const { default: postcss } = await import("postcss")
14
+ const { default: postcss } = await import("postcss");
15
15
 
16
16
  try {
17
- const cssFileUrl = urlToFileUrl(url)
17
+ const cssFileUrl = urlToFileUrl(url);
18
18
  const result = await postcss(plugins).process(content, {
19
19
  collectUrls: true,
20
20
  from: fileURLToPath(cssFileUrl),
@@ -26,12 +26,12 @@ export const applyPostCss = async ({
26
26
  ...(map ? { prev: JSON.stringify(map) } : {}),
27
27
  },
28
28
  ...options,
29
- })
29
+ });
30
30
  return {
31
31
  postCssMessages: result.messages,
32
32
  map: result.map.toJSON(),
33
33
  content: result.css,
34
- }
34
+ };
35
35
  } catch (error) {
36
36
  if (error.name === "CssSyntaxError") {
37
37
  throw createCssParseError({
@@ -40,11 +40,11 @@ export const applyPostCss = async ({
40
40
  url,
41
41
  line: error.line,
42
42
  column: error.column,
43
- })
43
+ });
44
44
  }
45
- throw error
45
+ throw error;
46
46
  }
47
- }
47
+ };
48
48
 
49
49
  // the goal of this function is to take an url that is likely an http url
50
50
  // info a file:// url
@@ -52,13 +52,13 @@ export const applyPostCss = async ({
52
52
  // must becomes file:///dir/file.js
53
53
  // but in windows it must be file://C:/dir/file.js
54
54
  const filesystemRootUrl =
55
- process.platform === "win32" ? `file:///${process.cwd()[0]}:/` : "file:///"
55
+ process.platform === "win32" ? `file:///${process.cwd()[0]}:/` : "file:///";
56
56
  const urlToFileUrl = (url) => {
57
- const urlString = String(url)
57
+ const urlString = String(url);
58
58
  if (urlString.startsWith("file:")) {
59
- return urlString
59
+ return urlString;
60
60
  }
61
- const origin = new URL(url).origin
62
- const afterOrigin = urlString.slice(origin.length)
63
- return new URL(afterOrigin, filesystemRootUrl).href
64
- }
61
+ const origin = new URL(url).origin;
62
+ const afterOrigin = urlString.slice(origin.length);
63
+ return new URL(afterOrigin, filesystemRootUrl).href;
64
+ };
@@ -5,11 +5,11 @@ export const createCssParseError = ({
5
5
  line,
6
6
  column,
7
7
  }) => {
8
- const parseError = new Error(message)
9
- parseError.reasonCode = reasonCode
10
- parseError.code = "PARSE_ERROR"
11
- parseError.url = url
12
- parseError.line = line
13
- parseError.column = column
14
- return parseError
15
- }
8
+ const parseError = new Error(message);
9
+ parseError.reasonCode = reasonCode;
10
+ parseError.code = "PARSE_ERROR";
11
+ parseError.url = url;
12
+ parseError.line = line;
13
+ parseError.column = column;
14
+ return parseError;
15
+ };
@@ -1,8 +1,8 @@
1
- import { applyPostCss } from "./apply_post_css.js"
2
- import { postCssPluginUrlVisitor } from "./postcss_plugin_url_visitor.js"
1
+ import { applyPostCss } from "./apply_post_css.js";
2
+ import { postCssPluginUrlVisitor } from "./postcss_plugin_url_visitor.js";
3
3
 
4
4
  export const parseCssUrls = async ({ css, url }) => {
5
- const cssUrls = []
5
+ const cssUrls = [];
6
6
  await applyPostCss({
7
7
  content: css,
8
8
  url,
@@ -24,10 +24,10 @@ export const parseCssUrls = async ({ css, url }) => {
24
24
  end: specifierEnd,
25
25
  line: specifierLine,
26
26
  column: specifierColumn,
27
- })
27
+ });
28
28
  },
29
29
  }),
30
30
  ],
31
- })
32
- return cssUrls
33
- }
31
+ });
32
+ return cssUrls;
33
+ };
@@ -11,37 +11,37 @@ hence sourcemap cannot point the original source location
11
11
 
12
12
  */
13
13
 
14
- import { pathToFileURL } from "node:url"
15
- import { createRequire } from "node:module"
14
+ import { pathToFileURL } from "node:url";
15
+ import { createRequire } from "node:module";
16
16
 
17
- const require = createRequire(import.meta.url)
17
+ const require = createRequire(import.meta.url);
18
18
 
19
19
  export const postCssPluginUrlVisitor = ({ urlVisitor = () => null }) => {
20
- const parseCssValue = require("postcss-value-parser")
21
- const stringifyCssNodes = parseCssValue.stringify
20
+ const parseCssValue = require("postcss-value-parser");
21
+ const stringifyCssNodes = parseCssValue.stringify;
22
22
 
23
23
  return {
24
24
  postcssPlugin: "url_visitor",
25
25
  prepare: (result) => {
26
- const { from } = result.opts
27
- const fromUrl = String(pathToFileURL(from))
28
- const mutations = []
26
+ const { from } = result.opts;
27
+ const fromUrl = String(pathToFileURL(from));
28
+ const mutations = [];
29
29
  return {
30
30
  AtRule: {
31
31
  import: (atImportNode, { AtRule }) => {
32
32
  if (atImportNode.parent.type !== "root") {
33
- atImportNode.warn(result, "`@import` should be top level")
34
- return
33
+ atImportNode.warn(result, "`@import` should be top level");
34
+ return;
35
35
  }
36
36
  if (atImportNode.nodes) {
37
37
  atImportNode.warn(
38
38
  result,
39
39
  "`@import` was not terminated correctly",
40
- )
41
- return
40
+ );
41
+ return;
42
42
  }
43
- const parsed = parseCssValue(atImportNode.params)
44
- let [urlNode] = parsed.nodes
43
+ const parsed = parseCssValue(atImportNode.params);
44
+ let [urlNode] = parsed.nodes;
45
45
  if (
46
46
  !urlNode ||
47
47
  (urlNode.type !== "string" && urlNode.type !== "function")
@@ -49,62 +49,63 @@ export const postCssPluginUrlVisitor = ({ urlVisitor = () => null }) => {
49
49
  atImportNode.warn(
50
50
  result,
51
51
  `No URL in \`${atImportNode.toString()}\``,
52
- )
53
- return
52
+ );
53
+ return;
54
54
  }
55
- let url = ""
55
+ let url = "";
56
56
  if (urlNode.type === "string") {
57
- url = urlNode.value
57
+ url = urlNode.value;
58
58
  } else if (urlNode.type === "function") {
59
59
  // Invalid function
60
60
  if (!/^url$/i.test(urlNode.value)) {
61
61
  atImportNode.warn(
62
62
  result,
63
63
  `Invalid \`url\` function in \`${atImportNode.toString()}\``,
64
- )
65
- return
64
+ );
65
+ return;
66
66
  }
67
- const firstNode = urlNode.nodes[0]
67
+ const firstNode = urlNode.nodes[0];
68
68
  if (firstNode && firstNode.type === "string") {
69
- urlNode = firstNode
70
- url = urlNode.value
69
+ urlNode = firstNode;
70
+ url = urlNode.value;
71
71
  } else {
72
- urlNode = urlNode.nodes
73
- url = stringifyCssNodes(urlNode.nodes)
72
+ urlNode = urlNode.nodes;
73
+ url = stringifyCssNodes(urlNode.nodes);
74
74
  }
75
75
  }
76
76
 
77
- url = url.trim()
77
+ url = url.trim();
78
78
  if (url.length === 0) {
79
79
  atImportNode.warn(
80
80
  result,
81
81
  `Empty URL in \`${atImportNode.toString()}\``,
82
- )
83
- return
82
+ );
83
+ return;
84
84
  }
85
85
 
86
- const specifier = url
87
- url = new URL(specifier, fromUrl).href
86
+ const specifier = url;
87
+ url = new URL(specifier, fromUrl).href;
88
88
  if (url === fromUrl) {
89
89
  atImportNode.warn(
90
90
  result,
91
91
  `\`@import\` loop in \`${atImportNode.toString()}\``,
92
- )
93
- return
92
+ );
93
+ return;
94
94
  }
95
95
 
96
- const atRuleStart = atImportNode.source.start.offset
97
- const atRuleEnd = atImportNode.source.end.offset + 1 // for the ";"
96
+ const atRuleStart = atImportNode.source.start.offset;
97
+ const atRuleEnd = atImportNode.source.end.offset + 1; // for the ";"
98
98
  const atRuleRaw = atImportNode.source.input.css.slice(
99
99
  atRuleStart,
100
100
  atRuleEnd,
101
- )
102
- const specifierIndex = atRuleRaw.indexOf(atImportNode.params)
103
- const specifierStart = atRuleStart + specifierIndex
104
- const specifierEnd = specifierStart + parsed.nodes[0].sourceEndIndex
105
- const specifierLine = atImportNode.source.start.line
101
+ );
102
+ const specifierIndex = atRuleRaw.indexOf(atImportNode.params);
103
+ const specifierStart = atRuleStart + specifierIndex;
104
+ const specifierEnd =
105
+ specifierStart + parsed.nodes[0].sourceEndIndex;
106
+ const specifierLine = atImportNode.source.start.line;
106
107
  const specifierColumn =
107
- atImportNode.source.start.column + specifierIndex
108
+ atImportNode.source.start.column + specifierIndex;
108
109
  urlVisitor({
109
110
  declarationNode: atImportNode,
110
111
  type: "@import",
@@ -117,23 +118,23 @@ export const postCssPluginUrlVisitor = ({ urlVisitor = () => null }) => {
117
118
  specifierEnd,
118
119
  replace: (newUrlSpecifier) => {
119
120
  if (newUrlSpecifier === urlNode.value) {
120
- return
121
+ return;
121
122
  }
122
- urlNode.value = newUrlSpecifier
123
- const newParams = parsed.toString()
123
+ urlNode.value = newUrlSpecifier;
124
+ const newParams = parsed.toString();
124
125
  const newAtImportRule = new AtRule({
125
126
  name: "import",
126
127
  params: newParams,
127
128
  source: atImportNode.source,
128
- })
129
- atImportNode.replaceWith(newAtImportRule)
129
+ });
130
+ atImportNode.replaceWith(newAtImportRule);
130
131
  },
131
- })
132
+ });
132
133
  },
133
134
  },
134
135
  Declaration: (declarationNode) => {
135
- const parsed = parseCssValue(declarationNode.value)
136
- const urlMutations = []
136
+ const parsed = parseCssValue(declarationNode.value);
137
+ const urlMutations = [];
137
138
  walkUrls(parsed, {
138
139
  stringifyCssNodes,
139
140
  visitor: ({ url, urlNode }) => {
@@ -142,37 +143,37 @@ export const postCssPluginUrlVisitor = ({ urlVisitor = () => null }) => {
142
143
  declarationNode.warn(
143
144
  result,
144
145
  `Empty URL in \`${declarationNode.toString()}\``,
145
- )
146
- return
146
+ );
147
+ return;
147
148
  }
148
149
  // Skip Data URI
149
150
  if (isDataUrl(url)) {
150
- return
151
+ return;
151
152
  }
152
- const specifier = url
153
- url = new URL(specifier, pathToFileURL(from))
153
+ const specifier = url;
154
+ url = new URL(specifier, pathToFileURL(from));
154
155
 
155
- const declarationNodeStart = declarationNode.source.start.offset
156
+ const declarationNodeStart = declarationNode.source.start.offset;
156
157
  const afterDeclarationNode =
157
- declarationNode.source.input.css.slice(declarationNodeStart)
158
+ declarationNode.source.input.css.slice(declarationNodeStart);
158
159
  const valueIndex = afterDeclarationNode.indexOf(
159
160
  declarationNode.value,
160
- )
161
- const valueStart = declarationNodeStart + valueIndex
162
- const specifierStart = valueStart + urlNode.sourceIndex
161
+ );
162
+ const valueStart = declarationNodeStart + valueIndex;
163
+ const specifierStart = valueStart + urlNode.sourceIndex;
163
164
  const specifierEnd =
164
165
  specifierStart +
165
166
  (urlNode.type === "word"
166
167
  ? urlNode.value.length
167
- : urlNode.value.length + 2) // the quotes
168
+ : urlNode.value.length + 2); // the quotes
168
169
  // value raw
169
170
  // declarationNode.source.input.css.slice(valueStart)
170
171
  // specifier raw
171
172
  // declarationNode.source.input.css.slice(specifierStart, specifierEnd)
172
- const specifierLine = declarationNode.source.start.line
173
+ const specifierLine = declarationNode.source.start.line;
173
174
  const specifierColumn =
174
175
  declarationNode.source.start.column +
175
- (specifierStart - declarationNodeStart)
176
+ (specifierStart - declarationNodeStart);
176
177
 
177
178
  urlVisitor({
178
179
  declarationNode,
@@ -186,61 +187,61 @@ export const postCssPluginUrlVisitor = ({ urlVisitor = () => null }) => {
186
187
  urlMutations.push(() => {
187
188
  // the specifier desires to be inside double quotes
188
189
  if (newUrlSpecifier[0] === `"`) {
189
- urlNode.type = "word"
190
- urlNode.value = newUrlSpecifier
191
- return
190
+ urlNode.type = "word";
191
+ urlNode.value = newUrlSpecifier;
192
+ return;
192
193
  }
193
194
  // the specifier desires to be inside simple quotes
194
195
  if (newUrlSpecifier[0] === `'`) {
195
- urlNode.type = "word"
196
- urlNode.value = newUrlSpecifier
197
- return
196
+ urlNode.type = "word";
197
+ urlNode.value = newUrlSpecifier;
198
+ return;
198
199
  }
199
200
  // the specifier desired to be just a word
200
201
  // for the "word" type so that newUrlSpecifier can opt-out of being between quotes
201
202
  // useful to inject __v__ calls for css inside js
202
- urlNode.type = "word"
203
- urlNode.value = newUrlSpecifier
204
- })
203
+ urlNode.type = "word";
204
+ urlNode.value = newUrlSpecifier;
205
+ });
205
206
  },
206
- })
207
+ });
207
208
  },
208
- })
209
+ });
209
210
  if (urlMutations.length) {
210
211
  mutations.push(() => {
211
212
  urlMutations.forEach((urlMutation) => {
212
- urlMutation()
213
- })
214
- declarationNode.value = parsed.toString()
215
- })
213
+ urlMutation();
214
+ });
215
+ declarationNode.value = parsed.toString();
216
+ });
216
217
  }
217
218
  },
218
219
  OnceExit: () => {
219
220
  mutations.forEach((mutation) => {
220
- mutation()
221
- })
221
+ mutation();
222
+ });
222
223
  },
223
- }
224
+ };
224
225
  },
225
- }
226
- }
227
- postCssPluginUrlVisitor.postcss = true
226
+ };
227
+ };
228
+ postCssPluginUrlVisitor.postcss = true;
228
229
 
229
230
  const walkUrls = (parsed, { stringifyCssNodes, visitor }) => {
230
231
  parsed.walk((node) => {
231
232
  // https://github.com/andyjansson/postcss-functions
232
233
  if (isUrlFunctionNode(node)) {
233
- const { nodes } = node
234
- const [urlNode] = nodes
234
+ const { nodes } = node;
235
+ const [urlNode] = nodes;
235
236
  const url =
236
237
  urlNode && urlNode.type === "string"
237
238
  ? urlNode.value
238
- : stringifyCssNodes(nodes)
239
+ : stringifyCssNodes(nodes);
239
240
  visitor({
240
241
  url: url.trim(),
241
242
  urlNode,
242
- })
243
- return
243
+ });
244
+ return;
244
245
  }
245
246
 
246
247
  if (isImageSetFunctionNode(node)) {
@@ -249,40 +250,40 @@ const walkUrls = (parsed, { stringifyCssNodes, visitor }) => {
249
250
  visitor({
250
251
  url: childNode.value.trim(),
251
252
  urlNode: childNode,
252
- })
253
- return
253
+ });
254
+ return;
254
255
  }
255
256
 
256
257
  if (isUrlFunctionNode(node)) {
257
- const { nodes } = childNode
258
- const [urlNode] = nodes
258
+ const { nodes } = childNode;
259
+ const [urlNode] = nodes;
259
260
  const url =
260
261
  urlNode && urlNode.type === "string"
261
262
  ? urlNode.value
262
- : stringifyCssNodes(nodes)
263
+ : stringifyCssNodes(nodes);
263
264
  visitor({
264
265
  url: url.trim(),
265
266
  urlNode,
266
- })
267
- return
267
+ });
268
+ return;
268
269
  }
269
- })
270
+ });
270
271
  }
271
- })
272
- }
272
+ });
273
+ };
273
274
 
274
275
  const isUrlFunctionNode = (node) => {
275
- return node.type === "function" && /^url$/i.test(node.value)
276
- }
276
+ return node.type === "function" && /^url$/i.test(node.value);
277
+ };
277
278
 
278
279
  const isImageSetFunctionNode = (node) => {
279
280
  return (
280
281
  node.type === "function" && /^(?:-webkit-)?image-set$/i.test(node.value)
281
- )
282
- }
282
+ );
283
+ };
283
284
 
284
285
  const isDataUrl = (url) => {
285
286
  return /data:[^\n\r;]+?(?:;charset=[^\n\r;]+?)?;base64,([\d+/A-Za-z]+={0,2})/.test(
286
287
  url,
287
- )
288
- }
288
+ );
289
+ };
@@ -1,24 +1,24 @@
1
- import { getHtmlNodeAttribute } from "./html_node_attributes.js"
1
+ import { getHtmlNodeAttribute } from "./html_node_attributes.js";
2
2
 
3
3
  export const analyzeScriptNode = (scriptNode) => {
4
- const typeAttribute = getHtmlNodeAttribute(scriptNode, "type")
4
+ const typeAttribute = getHtmlNodeAttribute(scriptNode, "type");
5
5
  if (typeAttribute === undefined || typeAttribute === "text/javascript") {
6
6
  return {
7
7
  type: "js_classic",
8
8
  contentType: "text/javascript",
9
- }
9
+ };
10
10
  }
11
11
  if (typeAttribute === "module") {
12
12
  return {
13
13
  type: "js_module",
14
14
  contentType: "text/javascript",
15
- }
15
+ };
16
16
  }
17
17
  if (typeAttribute === "importmap") {
18
18
  return {
19
19
  type: "importmap",
20
20
  contentType: "application/importmap+json",
21
- }
21
+ };
22
22
  }
23
23
  // jsx
24
24
  if (typeAttribute === "text/jsx") {
@@ -26,14 +26,14 @@ export const analyzeScriptNode = (scriptNode) => {
26
26
  type: "js_classic",
27
27
  contentType: "text/javascript",
28
28
  extension: ".jsx",
29
- }
29
+ };
30
30
  }
31
31
  if (typeAttribute === "module/jsx") {
32
32
  return {
33
33
  type: "js_module",
34
34
  contentType: "text/javascript",
35
35
  extension: ".jsx",
36
- }
36
+ };
37
37
  }
38
38
  // typescript
39
39
  if (typeAttribute === "text/ts") {
@@ -41,14 +41,14 @@ export const analyzeScriptNode = (scriptNode) => {
41
41
  type: "js_classic",
42
42
  contentType: "text/javascript",
43
43
  extension: ".ts",
44
- }
44
+ };
45
45
  }
46
46
  if (typeAttribute === "module/ts") {
47
47
  return {
48
48
  type: "js_module",
49
49
  contentType: "text/javascript",
50
50
  extension: ".ts",
51
- }
51
+ };
52
52
  }
53
53
  // typescript and jsx
54
54
  if (typeAttribute === "text/tsx") {
@@ -56,14 +56,14 @@ export const analyzeScriptNode = (scriptNode) => {
56
56
  type: "js_classic",
57
57
  contentType: "text/javascript",
58
58
  extension: ".tsx",
59
- }
59
+ };
60
60
  }
61
61
  if (typeAttribute === "module/tsx") {
62
62
  return {
63
63
  type: "js_module",
64
64
  contentType: "text/javascript",
65
65
  extension: ".tsx",
66
- }
66
+ };
67
67
  }
68
68
  // from MDN about [type] attribute:
69
69
  // "Any other value: The embedded content is treated as a data block
@@ -74,15 +74,15 @@ export const analyzeScriptNode = (scriptNode) => {
74
74
  return {
75
75
  type: "text",
76
76
  contentType: "text/plain",
77
- }
78
- }
77
+ };
78
+ };
79
79
 
80
80
  export const analyzeLinkNode = (linkNode) => {
81
- const rel = getHtmlNodeAttribute(linkNode, "rel")
81
+ const rel = getHtmlNodeAttribute(linkNode, "rel");
82
82
  if (rel === "stylesheet") {
83
83
  return {
84
84
  isStylesheet: true,
85
- }
85
+ };
86
86
  }
87
87
  const isResourceHint = [
88
88
  "preconnect",
@@ -90,9 +90,9 @@ export const analyzeLinkNode = (linkNode) => {
90
90
  "prefetch",
91
91
  "preload",
92
92
  "modulepreload",
93
- ].includes(rel)
93
+ ].includes(rel);
94
94
  return {
95
95
  isResourceHint,
96
96
  rel,
97
- }
98
- }
97
+ };
98
+ };
@@ -1,22 +1,22 @@
1
1
  import {
2
2
  getHtmlNodeAttribute,
3
3
  setHtmlNodeAttributes,
4
- } from "./html_node_attributes.js"
5
- import { setHtmlNodeText } from "./html_node_text.js"
4
+ } from "./html_node_attributes.js";
5
+ import { setHtmlNodeText } from "./html_node_text.js";
6
6
 
7
7
  export const inlineScriptNode = (script, textContent) => {
8
- const src = getHtmlNodeAttribute(script, "src")
8
+ const src = getHtmlNodeAttribute(script, "src");
9
9
  setHtmlNodeAttributes(script, {
10
10
  "inlined-from-src": src,
11
11
  "src": undefined,
12
12
  "crossorigin": undefined,
13
13
  "integrity": undefined,
14
- })
15
- setHtmlNodeText(script, textContent)
16
- }
14
+ });
15
+ setHtmlNodeText(script, textContent);
16
+ };
17
17
 
18
18
  export const inlineLinkStylesheetNode = (link, textContent) => {
19
- const href = getHtmlNodeAttribute(link, "href")
19
+ const href = getHtmlNodeAttribute(link, "href");
20
20
  setHtmlNodeAttributes(link, {
21
21
  "inlined-from-href": href,
22
22
  "href": undefined,
@@ -25,16 +25,16 @@ export const inlineLinkStylesheetNode = (link, textContent) => {
25
25
  "as": undefined,
26
26
  "crossorigin": undefined,
27
27
  "integrity": undefined,
28
- })
29
- link.nodeName = "style"
30
- link.tagName = "style"
31
- setHtmlNodeText(link, textContent)
32
- }
28
+ });
29
+ link.nodeName = "style";
30
+ link.tagName = "style";
31
+ setHtmlNodeText(link, textContent);
32
+ };
33
33
 
34
34
  export const inlineImgNode = (img, contentAsBase64) => {
35
- const src = getHtmlNodeAttribute(img, "src")
35
+ const src = getHtmlNodeAttribute(img, "src");
36
36
  setHtmlNodeAttributes(img, {
37
37
  "inlined-from-src": src,
38
38
  "src": contentAsBase64,
39
- })
40
- }
39
+ });
40
+ };