@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 +3 -3
- package/src/html/html_node.js +25 -14
- package/src/html/html_parse.js +3 -2
- package/src/js/js_static_analysis/import_export.js +4 -4
- package/src/js/js_static_analysis/import_meta_resolve.js +27 -0
- package/src/js/js_static_analysis/new_url.js +15 -5
- package/src/js/js_static_analysis/system.js +34 -2
- package/src/js/js_static_analysis/web_worker.js +1 -1
- package/src/js/js_static_analysis/web_worker_entry_point.js +19 -1
- package/src/js/parse_js_urls.js +16 -0
- package/src/main.js +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/ast",
|
|
3
|
-
"version": "1.4.
|
|
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.
|
|
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.
|
|
42
|
+
"postcss": "8.4.19",
|
|
43
43
|
"postcss-value-parser": "4.2.0"
|
|
44
44
|
}
|
|
45
45
|
}
|
package/src/html/html_node.js
CHANGED
|
@@ -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-
|
|
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
|
|
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-
|
|
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
|
|
55
|
+
return insertHtmlNodeBefore(scriptNode, importmapParent, nextSibling)
|
|
58
56
|
}
|
|
59
57
|
if (nextSibling.nodeName === "link") {
|
|
60
58
|
after = nextSibling
|
|
61
59
|
}
|
|
62
60
|
}
|
|
63
|
-
return
|
|
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
|
|
69
|
+
return insertHtmlNodeBefore(scriptNode, headNode, child)
|
|
72
70
|
}
|
|
73
71
|
if (child.nodeName === "link") {
|
|
74
72
|
after = child
|
|
75
73
|
}
|
|
76
74
|
}
|
|
77
|
-
return
|
|
75
|
+
return insertHtmlNodeAfter(scriptNode, headNode, after)
|
|
78
76
|
}
|
|
79
77
|
|
|
80
|
-
const
|
|
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
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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) => {
|
package/src/html/html_parse.js
CHANGED
|
@@ -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-
|
|
72
|
-
"jsenv-
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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
|
|
91
|
-
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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
|
}
|
package/src/js/parse_js_urls.js
CHANGED
|
@@ -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)) {
|