@jsenv/ast 1.1.1 → 1.2.0
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.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Parse and transform HTML,CSS and JS",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
"directory": "packages/ast"
|
|
10
10
|
},
|
|
11
11
|
"publishConfig": {
|
|
12
|
-
"access": "public"
|
|
13
|
-
"registry": "https://registry.npmjs.org"
|
|
12
|
+
"access": "public"
|
|
14
13
|
},
|
|
15
14
|
"author": {
|
|
16
15
|
"name": "dmail",
|
|
@@ -34,13 +33,13 @@
|
|
|
34
33
|
"test": "node --conditions=development ./scripts/test.mjs"
|
|
35
34
|
},
|
|
36
35
|
"dependencies": {
|
|
37
|
-
"@babel/parser": "7.18.
|
|
38
|
-
"@parcel/css": "1.
|
|
39
|
-
"acorn": "8.
|
|
36
|
+
"@babel/parser": "7.18.8",
|
|
37
|
+
"@parcel/css": "1.12.2",
|
|
38
|
+
"acorn": "8.8.0",
|
|
40
39
|
"acorn-import-assertions": "1.8.0",
|
|
41
40
|
"acorn-walk": "8.2.0",
|
|
42
41
|
"parse5": "7.0.0",
|
|
43
42
|
"postcss": "8.4.14",
|
|
44
43
|
"postcss-value-parser": "4.2.0"
|
|
45
44
|
}
|
|
46
|
-
}
|
|
45
|
+
}
|
|
@@ -1,17 +1,80 @@
|
|
|
1
1
|
import { getHtmlNodeAttribute } from "./html_node_attributes.js"
|
|
2
2
|
|
|
3
3
|
export const analyzeScriptNode = (scriptNode) => {
|
|
4
|
-
const
|
|
5
|
-
if (
|
|
6
|
-
return
|
|
4
|
+
const typeAttribute = getHtmlNodeAttribute(scriptNode, "type")
|
|
5
|
+
if (typeAttribute === undefined || typeAttribute === "text/javascript") {
|
|
6
|
+
return {
|
|
7
|
+
type: "js_classic",
|
|
8
|
+
contentType: "text/javascript",
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
if (typeAttribute === "module") {
|
|
12
|
+
return {
|
|
13
|
+
type: "js_module",
|
|
14
|
+
contentType: "text/javascript",
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
if (typeAttribute === "importmap") {
|
|
18
|
+
return {
|
|
19
|
+
type: "importmap",
|
|
20
|
+
contentType: "application/importmap+json",
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
// jsx
|
|
24
|
+
if (typeAttribute === "text/jsx") {
|
|
25
|
+
return {
|
|
26
|
+
type: "js_classic",
|
|
27
|
+
contentType: "text/javascript",
|
|
28
|
+
extension: ".jsx",
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (typeAttribute === "module/jsx") {
|
|
32
|
+
return {
|
|
33
|
+
type: "js_module",
|
|
34
|
+
contentType: "text/javascript",
|
|
35
|
+
extension: ".jsx",
|
|
36
|
+
}
|
|
7
37
|
}
|
|
8
|
-
|
|
9
|
-
|
|
38
|
+
// typescript
|
|
39
|
+
if (typeAttribute === "text/ts") {
|
|
40
|
+
return {
|
|
41
|
+
type: "js_classic",
|
|
42
|
+
contentType: "text/javascript",
|
|
43
|
+
extension: ".ts",
|
|
44
|
+
}
|
|
10
45
|
}
|
|
11
|
-
if (
|
|
12
|
-
return
|
|
46
|
+
if (typeAttribute === "module/ts") {
|
|
47
|
+
return {
|
|
48
|
+
type: "js_module",
|
|
49
|
+
contentType: "text/javascript",
|
|
50
|
+
extension: ".ts",
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// typescript and jsx
|
|
54
|
+
if (typeAttribute === "text/tsx") {
|
|
55
|
+
return {
|
|
56
|
+
type: "js_classic",
|
|
57
|
+
contentType: "text/javascript",
|
|
58
|
+
extension: ".tsx",
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (typeAttribute === "module/tsx") {
|
|
62
|
+
return {
|
|
63
|
+
type: "js_module",
|
|
64
|
+
contentType: "text/javascript",
|
|
65
|
+
extension: ".tsx",
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// from MDN about [type] attribute:
|
|
69
|
+
// "Any other value: The embedded content is treated as a data block
|
|
70
|
+
// which won't be processed by the browser. Developers must use a valid MIME type
|
|
71
|
+
// that is not a JavaScript MIME type to denote data blocks.
|
|
72
|
+
// The src attribute will be ignored."
|
|
73
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-type
|
|
74
|
+
return {
|
|
75
|
+
type: "text",
|
|
76
|
+
contentType: "text/plain",
|
|
13
77
|
}
|
|
14
|
-
return type
|
|
15
78
|
}
|
|
16
79
|
|
|
17
80
|
export const analyzeLinkNode = (linkNode) => {
|
|
@@ -21,7 +84,7 @@ export const analyzeLinkNode = (linkNode) => {
|
|
|
21
84
|
isStylesheet: true,
|
|
22
85
|
}
|
|
23
86
|
}
|
|
24
|
-
const
|
|
87
|
+
const isResourceHint = [
|
|
25
88
|
"preconnect",
|
|
26
89
|
"dns-prefetch",
|
|
27
90
|
"prefetch",
|
|
@@ -29,7 +92,7 @@ export const analyzeLinkNode = (linkNode) => {
|
|
|
29
92
|
"modulepreload",
|
|
30
93
|
].includes(rel)
|
|
31
94
|
return {
|
|
32
|
-
|
|
95
|
+
isResourceHint,
|
|
33
96
|
rel,
|
|
34
97
|
}
|
|
35
98
|
}
|
|
@@ -7,7 +7,7 @@ import { setHtmlNodeText } from "./html_node_text.js"
|
|
|
7
7
|
export const inlineScriptNode = (script, textContent) => {
|
|
8
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,
|
|
@@ -18,7 +18,7 @@ export const inlineScriptNode = (script, textContent) => {
|
|
|
18
18
|
export const inlineLinkStylesheetNode = (link, textContent) => {
|
|
19
19
|
const href = getHtmlNodeAttribute(link, "href")
|
|
20
20
|
setHtmlNodeAttributes(link, {
|
|
21
|
-
"
|
|
21
|
+
"inlined-from-href": href,
|
|
22
22
|
"href": undefined,
|
|
23
23
|
"rel": undefined,
|
|
24
24
|
"type": undefined,
|
|
@@ -34,7 +34,7 @@ export const inlineLinkStylesheetNode = (link, textContent) => {
|
|
|
34
34
|
export const inlineImgNode = (img, contentAsBase64) => {
|
|
35
35
|
const src = getHtmlNodeAttribute(img, "src")
|
|
36
36
|
setHtmlNodeAttributes(img, {
|
|
37
|
-
"
|
|
37
|
+
"inlined-from-src": src,
|
|
38
38
|
"src": contentAsBase64,
|
|
39
39
|
})
|
|
40
40
|
}
|
package/src/html/html_node.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { parseFragment } from "parse5"
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
getHtmlNodeAttribute,
|
|
5
|
-
setHtmlNodeAttributes,
|
|
6
|
-
} from "./html_node_attributes.js"
|
|
3
|
+
import { setHtmlNodeAttributes } from "./html_node_attributes.js"
|
|
7
4
|
import { findHtmlNode } from "./html_search.js"
|
|
8
5
|
import { analyzeScriptNode } from "./html_analysis.js"
|
|
9
6
|
|
|
@@ -20,18 +17,20 @@ export const createHtmlNode = ({ tagName, textContent = "", ...rest }) => {
|
|
|
20
17
|
return fragment.childNodes[0]
|
|
21
18
|
}
|
|
22
19
|
|
|
23
|
-
export const injectScriptNodeAsEarlyAsPossible = (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
20
|
+
export const injectScriptNodeAsEarlyAsPossible = (
|
|
21
|
+
htmlAst,
|
|
22
|
+
scriptNode,
|
|
23
|
+
jsenvPluginName = "jsenv",
|
|
24
|
+
) => {
|
|
25
|
+
setHtmlNodeAttributes(scriptNode, {
|
|
26
|
+
"jsenv-plugin-owner": jsenvPluginName,
|
|
27
|
+
"jsenv-plugin-action": "injected",
|
|
28
|
+
})
|
|
29
|
+
const isJsModule = analyzeScriptNode(scriptNode).type === "js_module"
|
|
30
|
+
if (isJsModule) {
|
|
32
31
|
const firstImportmapScript = findHtmlNode(htmlAst, (node) => {
|
|
33
32
|
if (node.nodeName !== "script") return false
|
|
34
|
-
return analyzeScriptNode(node) === "importmap"
|
|
33
|
+
return analyzeScriptNode(node).type === "importmap"
|
|
35
34
|
})
|
|
36
35
|
if (firstImportmapScript) {
|
|
37
36
|
return insertAfter(
|
|
@@ -97,9 +97,9 @@ export const getHtmlNodeAttributePosition = (node, attributeName) => {
|
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
const originalPositionAttributeName =
|
|
100
|
-
attributeName === "
|
|
100
|
+
attributeName === "inlined-from-src"
|
|
101
101
|
? "original-src-position"
|
|
102
|
-
: attributeName === "
|
|
102
|
+
: attributeName === "inlined-from-href"
|
|
103
103
|
? "original-href-position"
|
|
104
104
|
: `original-${attributeName}-position`
|
|
105
105
|
const originalPosition = getHtmlNodeAttribute(
|
package/src/html/html_parse.js
CHANGED
|
@@ -66,10 +66,10 @@ export const stringifyHtmlAst = (
|
|
|
66
66
|
"original-position": undefined,
|
|
67
67
|
"original-src-position": undefined,
|
|
68
68
|
"original-href-position": undefined,
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
69
|
+
"inlined-from-src": undefined,
|
|
70
|
+
"inlined-from-href": undefined,
|
|
71
|
+
"jsenv-plugin-owner": undefined,
|
|
72
|
+
"jsenv-plugin-action": undefined,
|
|
73
73
|
})
|
|
74
74
|
},
|
|
75
75
|
})
|
|
@@ -31,6 +31,13 @@ export const analyzeNewUrlCall = (node, { isJsModule, onUrl }) => {
|
|
|
31
31
|
const baseUrlType = analyzeUrlNodeType(secondArgNode, { isJsModule })
|
|
32
32
|
if (baseUrlType) {
|
|
33
33
|
// we can understand the second argument
|
|
34
|
+
if (
|
|
35
|
+
baseUrlType === "StringLiteral" &&
|
|
36
|
+
secondArgNode.value === "file:///"
|
|
37
|
+
) {
|
|
38
|
+
// ignore new URL(specifier, "file:///")
|
|
39
|
+
return
|
|
40
|
+
}
|
|
34
41
|
const urlType = analyzeUrlNodeType(firstArgNode, { isJsModule })
|
|
35
42
|
if (urlType === "StringLiteral") {
|
|
36
43
|
// we can understand the first argument
|