@jsenv/ast 1.4.3 → 1.4.5

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": "1.4.3",
3
+ "version": "1.4.5",
4
4
  "description": "Parse and transform HTML,CSS and JS",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -33,13 +33,13 @@
33
33
  "test": "node --conditions=development ./scripts/test.mjs"
34
34
  },
35
35
  "dependencies": {
36
- "@babel/parser": "7.20.1",
36
+ "@babel/parser": "7.20.3",
37
37
  "@parcel/css": "1.14.0",
38
38
  "acorn": "8.8.1",
39
39
  "acorn-import-assertions": "1.8.0",
40
40
  "acorn-walk": "8.2.0",
41
41
  "parse5": "7.1.1",
42
- "postcss": "8.4.18",
42
+ "postcss": "8.4.19",
43
43
  "postcss-value-parser": "4.2.0"
44
44
  }
45
45
  }
@@ -19,12 +19,11 @@ export const createHtmlNode = ({ tagName, textContent = "", ...rest }) => {
19
19
 
20
20
  export const injectHtmlNode = (htmlAst, node, jsenvPluginName = "jsenv") => {
21
21
  setHtmlNodeAttributes(node, {
22
- "jsenv-plugin-owner": jsenvPluginName,
23
- "jsenv-plugin-action": "injected",
22
+ "jsenv-injected-by": jsenvPluginName,
24
23
  })
25
24
  const htmlHtmlNode = findChild(htmlAst, (node) => node.nodeName === "html")
26
25
  const bodyNode = findChild(htmlHtmlNode, (node) => node.nodeName === "body")
27
- return insertAfter(node, bodyNode)
26
+ return insertHtmlNodeAfter(node, bodyNode)
28
27
  }
29
28
 
30
29
  export const injectScriptNodeAsEarlyAsPossible = (
@@ -33,8 +32,7 @@ export const injectScriptNodeAsEarlyAsPossible = (
33
32
  jsenvPluginName = "jsenv",
34
33
  ) => {
35
34
  setHtmlNodeAttributes(scriptNode, {
36
- "jsenv-plugin-owner": jsenvPluginName,
37
- "jsenv-plugin-action": "injected",
35
+ "jsenv-injected-by": jsenvPluginName,
38
36
  })
39
37
  const isJsModule = analyzeScriptNode(scriptNode).type === "js_module"
40
38
  if (isJsModule) {
@@ -54,13 +52,13 @@ export const injectScriptNodeAsEarlyAsPossible = (
54
52
  let after = firstImportmapScript
55
53
  for (const nextSibling of nextSiblings) {
56
54
  if (nextSibling.nodeName === "script") {
57
- return insertBefore(scriptNode, importmapParent, nextSibling)
55
+ return insertHtmlNodeBefore(scriptNode, importmapParent, nextSibling)
58
56
  }
59
57
  if (nextSibling.nodeName === "link") {
60
58
  after = nextSibling
61
59
  }
62
60
  }
63
- return insertAfter(scriptNode, importmapParent, after)
61
+ return insertHtmlNodeAfter(scriptNode, importmapParent, after)
64
62
  }
65
63
  }
66
64
  const headNode = findChild(htmlAst, (node) => node.nodeName === "html")
@@ -68,16 +66,20 @@ export const injectScriptNodeAsEarlyAsPossible = (
68
66
  let after = headNode.childNodes[0]
69
67
  for (const child of headNode.childNodes) {
70
68
  if (child.nodeName === "script") {
71
- return insertBefore(scriptNode, headNode, child)
69
+ return insertHtmlNodeBefore(scriptNode, headNode, child)
72
70
  }
73
71
  if (child.nodeName === "link") {
74
72
  after = child
75
73
  }
76
74
  }
77
- return insertAfter(scriptNode, headNode, after)
75
+ return insertHtmlNodeAfter(scriptNode, headNode, after)
78
76
  }
79
77
 
80
- const insertBefore = (nodeToInsert, futureParentNode, futureNextSibling) => {
78
+ export const insertHtmlNodeBefore = (
79
+ nodeToInsert,
80
+ futureParentNode,
81
+ futureNextSibling,
82
+ ) => {
81
83
  const { childNodes = [] } = futureParentNode
82
84
  const futureIndex = futureNextSibling
83
85
  ? childNodes.indexOf(futureNextSibling)
@@ -85,7 +87,11 @@ const insertBefore = (nodeToInsert, futureParentNode, futureNextSibling) => {
85
87
  injectWithWhitespaces(nodeToInsert, futureParentNode, futureIndex)
86
88
  }
87
89
 
88
- const insertAfter = (nodeToInsert, futureParentNode, futurePrevSibling) => {
90
+ export const insertHtmlNodeAfter = (
91
+ nodeToInsert,
92
+ futureParentNode,
93
+ futurePrevSibling,
94
+ ) => {
89
95
  const { childNodes = [] } = futureParentNode
90
96
  const futureIndex = futurePrevSibling
91
97
  ? childNodes.indexOf(futurePrevSibling) + 1
@@ -127,9 +133,14 @@ const injectWithWhitespaces = (nodeToInsert, futureParentNode, futureIndex) => {
127
133
  const findChild = ({ childNodes = [] }, predicate) => childNodes.find(predicate)
128
134
 
129
135
  const stringifyAttributes = (object) => {
130
- return Object.keys(object)
131
- .map((key) => `${key}=${valueToHtmlAttributeValue(object[key])}`)
132
- .join(" ")
136
+ let string = ""
137
+ Object.keys(object).forEach((key) => {
138
+ const value = object[key]
139
+ if (value === undefined) return
140
+ if (string !== "") string += " "
141
+ string += `${key}=${valueToHtmlAttributeValue(value)}`
142
+ })
143
+ return string
133
144
  }
134
145
 
135
146
  const valueToHtmlAttributeValue = (value) => {
@@ -68,8 +68,9 @@ export const stringifyHtmlAst = (
68
68
  "original-href-position": undefined,
69
69
  "inlined-from-src": undefined,
70
70
  "inlined-from-href": undefined,
71
- "jsenv-plugin-owner": undefined,
72
- "jsenv-plugin-action": undefined,
71
+ "jsenv-cooked-by": undefined,
72
+ "jsenv-inlined-by": undefined,
73
+ "jsenv-injected-by": undefined,
73
74
  "jsenv-debug": undefined,
74
75
  })
75
76
  },
@@ -4,7 +4,7 @@ export const analyzeImportDeclaration = (node, { onUrl }) => {
4
4
  const specifierNode = node.source
5
5
  const assertionInfo = extractImportAssertionsInfo(node)
6
6
  onUrl({
7
- type: "js_import_export",
7
+ type: "js_import",
8
8
  subtype: "import_static",
9
9
  specifier: specifierNode.value,
10
10
  specifierStart: specifierNode.start,
@@ -23,7 +23,7 @@ export const analyzeImportExpression = (node, { onUrl }) => {
23
23
  const assertionInfo = extractImportAssertionsInfo(node)
24
24
 
25
25
  onUrl({
26
- type: "js_import_export",
26
+ type: "js_import",
27
27
  subtype: "import_dynamic",
28
28
  specifier: specifierNode.value,
29
29
  specifierStart: specifierNode.start,
@@ -45,7 +45,7 @@ export const analyzeExportNamedDeclaration = (node, { onUrl }) => {
45
45
  return
46
46
  }
47
47
  onUrl({
48
- type: "js_import_export",
48
+ type: "js_import",
49
49
  subtype: "export_named",
50
50
  specifier: specifierNode.value,
51
51
  specifierStart: specifierNode.start,
@@ -57,7 +57,7 @@ export const analyzeExportNamedDeclaration = (node, { onUrl }) => {
57
57
  export const analyzeExportAllDeclaration = (node, { onUrl }) => {
58
58
  const specifierNode = node.source
59
59
  onUrl({
60
- type: "js_import_export",
60
+ type: "js_import",
61
61
  subtype: "export_all",
62
62
  specifier: specifierNode.value,
63
63
  specifierStart: specifierNode.start,
@@ -0,0 +1,27 @@
1
+ import { isStringLiteralNode } from "./helpers.js"
2
+
3
+ export const isImportMetaResolveCall = (node) => {
4
+ return (
5
+ node.type === "CallExpression" &&
6
+ node.callee.type === "MemberExpression" &&
7
+ node.callee.object.type === "MetaProperty" &&
8
+ node.callee.property.type === "Identifier" &&
9
+ node.callee.property.name === "resolve"
10
+ )
11
+ }
12
+
13
+ export const analyzeImportMetaResolveCall = (node, { onUrl }) => {
14
+ const firstArg = node.arguments[0]
15
+ if (firstArg && isStringLiteralNode(firstArg)) {
16
+ onUrl({
17
+ node,
18
+ type: "js_import",
19
+ subtype: "import_meta_resolve",
20
+ specifier: firstArg.value,
21
+ specifierStart: firstArg.start,
22
+ specifierEnd: firstArg.end,
23
+ specifierLine: firstArg.loc.start.line,
24
+ specifierColumn: firstArg.loc.start.column,
25
+ })
26
+ }
27
+ }
@@ -14,7 +14,7 @@ export const analyzeNewUrlCall = (node, { isJsModule, onUrl }) => {
14
14
  if (urlType === "StringLiteral") {
15
15
  const specifierNode = firstArgNode
16
16
  onUrl({
17
- type: "js_url_specifier",
17
+ type: "js_url",
18
18
  subtype: "new_url_first_arg",
19
19
  specifier: specifierNode.value,
20
20
  specifierStart: specifierNode.start,
@@ -43,7 +43,7 @@ export const analyzeNewUrlCall = (node, { isJsModule, onUrl }) => {
43
43
  // we can understand the first argument
44
44
  const specifierNode = firstArgNode
45
45
  onUrl({
46
- type: "js_url_specifier",
46
+ type: "js_url",
47
47
  subtype: "new_url_first_arg",
48
48
  specifier: specifierNode.value,
49
49
  specifierStart: specifierNode.start,
@@ -58,7 +58,7 @@ export const analyzeNewUrlCall = (node, { isJsModule, onUrl }) => {
58
58
  if (baseUrlType === "StringLiteral") {
59
59
  const specifierNode = secondArgNode
60
60
  onUrl({
61
- type: "js_url_specifier",
61
+ type: "js_url",
62
62
  subtype: "new_url_second_arg",
63
63
  specifier: specifierNode.value,
64
64
  specifierStart: specifierNode.start,
@@ -87,8 +87,18 @@ const analyzeUrlNodeType = (secondArgNode, { isJsModule }) => {
87
87
  if (!isJsModule && isContextMetaUrlFromSystemJs(secondArgNode)) {
88
88
  return "context.meta.url"
89
89
  }
90
- if (!isJsModule && isDocumentCurrentScriptSrc(secondArgNode)) {
91
- return "document.currentScript.src"
90
+ if (!isJsModule) {
91
+ if (isDocumentCurrentScriptSrc(secondArgNode)) {
92
+ return "document.currentScript.src"
93
+ }
94
+ // new URL('specifier', document.currentScript.src)
95
+ // becomes
96
+ // var _currentUrl = document.currentScript.src
97
+ // new URL('specifier', currentUrl)
98
+ // (search for scope.generateUidIdentifier("currentUrl")
99
+ if (secondArgNode.type === "Identifier") {
100
+ return "document.currentScript.src"
101
+ }
92
102
  }
93
103
  return null
94
104
  }
@@ -30,7 +30,7 @@ const analyzeSystemRegisterDeps = (node, { onUrl }) => {
30
30
  if (isStringLiteralNode(element)) {
31
31
  const specifierNode = element
32
32
  onUrl({
33
- type: "js_url_specifier",
33
+ type: "js_url",
34
34
  subtype: "system_register_arg",
35
35
  expectedType: "js_classic",
36
36
  specifier: specifierNode.value,
@@ -61,7 +61,7 @@ export const analyzeSystemImportCall = (node, { onUrl }) => {
61
61
  if (isStringLiteralNode(firstArgNode)) {
62
62
  const specifierNode = firstArgNode
63
63
  onUrl({
64
- type: "js_url_specifier",
64
+ type: "js_url",
65
65
  subtype: "system_import_arg",
66
66
  expectedType: "js_classic",
67
67
  specifier: specifierNode.value,
@@ -72,3 +72,35 @@ export const analyzeSystemImportCall = (node, { onUrl }) => {
72
72
  })
73
73
  }
74
74
  }
75
+
76
+ export const isSystemResolveCall = (node) => {
77
+ const callee = node.callee
78
+ return (
79
+ callee.type === "MemberExpression" &&
80
+ callee.object.type === "MemberExpression" &&
81
+ callee.object.object.type === "Identifier" &&
82
+ // because of minification we can't assume _context.
83
+ // so anything matching "*.meta.resolve()"
84
+ // will be assumed to be the equivalent to "meta.resolve()"
85
+ // callee.object.object.name === "_context" &&
86
+ callee.object.property.type === "Identifier" &&
87
+ callee.object.property.name === "meta" &&
88
+ callee.property.type === "Identifier" &&
89
+ callee.property.name === "resolve"
90
+ )
91
+ }
92
+ export const analyzeSystemResolveCall = (node, { onUrl }) => {
93
+ const firstArgNode = node.arguments[0]
94
+ if (isStringLiteralNode(firstArgNode)) {
95
+ const specifierNode = firstArgNode
96
+ onUrl({
97
+ type: "js_url",
98
+ subtype: "system_resolve_arg",
99
+ specifier: specifierNode.value,
100
+ specifierStart: specifierNode.start,
101
+ specifierEnd: specifierNode.end,
102
+ specifierLine: specifierNode.loc.start.line,
103
+ specifierColumn: specifierNode.loc.start.column,
104
+ })
105
+ }
106
+ }
@@ -18,7 +18,7 @@ export const analyzeImportScriptCalls = (node, { onUrl }) => {
18
18
  if (isStringLiteralNode(arg)) {
19
19
  const specifierNode = arg
20
20
  onUrl({
21
- type: "js_url_specifier",
21
+ type: "js_url",
22
22
  subtype: "self_import_scripts_arg",
23
23
  expectedType: "js_classic",
24
24
  specifier: specifierNode.value,
@@ -1,5 +1,9 @@
1
1
  import { getTypePropertyNode, isStringLiteralNode } from "./helpers.js"
2
2
  import { isNewUrlCall, analyzeNewUrlCall } from "./new_url.js"
3
+ import {
4
+ isImportMetaResolveCall,
5
+ analyzeImportMetaResolveCall,
6
+ } from "./import_meta_resolve.js"
3
7
 
4
8
  export const isNewWorkerCall = (node) => {
5
9
  return (
@@ -114,7 +118,7 @@ const analyzeWorkerCallArguments = (
114
118
  if (isStringLiteralNode(firstArgNode)) {
115
119
  const specifierNode = firstArgNode
116
120
  onUrl({
117
- type: "js_url_specifier",
121
+ type: "js_url",
118
122
  subtype: referenceSubtype,
119
123
  expectedType,
120
124
  expectedSubtype,
@@ -139,5 +143,19 @@ const analyzeWorkerCallArguments = (
139
143
  onUrl(mention)
140
144
  },
141
145
  })
146
+ return
147
+ }
148
+ if (isJsModule && isImportMetaResolveCall(firstArgNode)) {
149
+ analyzeImportMetaResolveCall(firstArgNode, {
150
+ onUrl: (mention) => {
151
+ Object.assign(mention, {
152
+ expectedType,
153
+ expectedSubtype,
154
+ typePropertyNode,
155
+ })
156
+ onUrl(mention)
157
+ },
158
+ })
159
+ return
142
160
  }
143
161
  }
@@ -7,6 +7,10 @@ import {
7
7
  analyzeExportNamedDeclaration,
8
8
  analyzeExportAllDeclaration,
9
9
  } from "./js_static_analysis/import_export.js"
10
+ import {
11
+ isImportMetaResolveCall,
12
+ analyzeImportMetaResolveCall,
13
+ } from "./js_static_analysis/import_meta_resolve.js"
10
14
  import {
11
15
  isNewWorkerCall,
12
16
  analyzeNewWorkerCall,
@@ -28,6 +32,8 @@ import {
28
32
  analyzeSystemRegisterCall,
29
33
  isSystemImportCall,
30
34
  analyzeSystemImportCall,
35
+ isSystemResolveCall,
36
+ analyzeSystemResolveCall,
31
37
  } from "./js_static_analysis/system.js"
32
38
 
33
39
  export const parseJsUrls = async ({
@@ -59,6 +65,10 @@ export const parseJsUrls = async ({
59
65
  analyzeExportAllDeclaration(node, { onUrl })
60
66
  },
61
67
  CallExpression: (node) => {
68
+ if (isJsModule && isImportMetaResolveCall(node)) {
69
+ analyzeImportMetaResolveCall(node, { onUrl })
70
+ return
71
+ }
62
72
  if (isServiceWorkerRegisterCall(node)) {
63
73
  analyzeServiceWorkerRegisterCall(node, {
64
74
  isJsModule,
@@ -84,6 +94,12 @@ export const parseJsUrls = async ({
84
94
  })
85
95
  return
86
96
  }
97
+ if (!isJsModule && isSystemResolveCall(node)) {
98
+ analyzeSystemResolveCall(node, {
99
+ onUrl,
100
+ })
101
+ return
102
+ }
87
103
  },
88
104
  NewExpression: (node, ancestors) => {
89
105
  if (isNewWorkerCall(node)) {
package/src/main.js CHANGED
@@ -22,6 +22,7 @@ export {
22
22
  createHtmlNode,
23
23
  injectHtmlNode,
24
24
  injectScriptNodeAsEarlyAsPossible,
25
+ insertHtmlNodeAfter,
25
26
  } from "./html/html_node.js"
26
27
  export {
27
28
  inlineScriptNode,