@jsenv/snapshot 2.0.1 → 2.1.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/snapshot",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Snapshot testing",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@jsenv/assert": "4.1.4",
|
|
38
|
+
"@jsenv/ast": "6.2.4",
|
|
38
39
|
"@jsenv/filesystem": "4.8.1",
|
|
39
40
|
"@jsenv/urls": "2.3.0",
|
|
40
41
|
"@jsenv/utils": "2.1.1",
|
|
@@ -4,42 +4,98 @@
|
|
|
4
4
|
import stripAnsi from "strip-ansi";
|
|
5
5
|
import { pathToFileURL, fileURLToPath } from "node:url";
|
|
6
6
|
import { escapeRegexpSpecialChars } from "@jsenv/utils/src/string/escape_regexp_special_chars.js";
|
|
7
|
+
import {
|
|
8
|
+
parseSvgString,
|
|
9
|
+
parseHtml,
|
|
10
|
+
setHtmlNodeText,
|
|
11
|
+
visitHtmlNodes,
|
|
12
|
+
getHtmlNodeText,
|
|
13
|
+
getHtmlNodeAttributes,
|
|
14
|
+
setHtmlNodeAttributes,
|
|
15
|
+
stringifyHtmlAst,
|
|
16
|
+
} from "@jsenv/ast";
|
|
17
|
+
import { urlToExtension } from "@jsenv/urls";
|
|
7
18
|
|
|
8
19
|
export const replaceFluctuatingValues = (
|
|
9
20
|
string,
|
|
10
21
|
{
|
|
22
|
+
fileUrl,
|
|
11
23
|
removeAnsi = true,
|
|
12
24
|
rootDirectoryUrl = pathToFileURL(process.cwd()),
|
|
13
25
|
// for unit tests
|
|
14
|
-
rootDirectoryPath
|
|
26
|
+
rootDirectoryPath,
|
|
15
27
|
isWindows = process.platform === "win32",
|
|
16
28
|
} = {},
|
|
17
29
|
) => {
|
|
18
|
-
if (removeAnsi) {
|
|
19
|
-
string = stripAnsi(string);
|
|
20
|
-
}
|
|
21
30
|
rootDirectoryUrl = String(rootDirectoryUrl);
|
|
22
31
|
if (rootDirectoryUrl[rootDirectoryUrl.length - 1] === "/") {
|
|
23
32
|
rootDirectoryUrl = rootDirectoryUrl.slice(0, -1);
|
|
24
33
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const windowPathRegex = new RegExp(
|
|
28
|
-
`${escapeRegexpSpecialChars(rootDirectoryPath)}(((?:\\\\(?:[\\w !#()-]+|[.]{1,2})+)*)(?:\\\\)?)`,
|
|
29
|
-
"gm",
|
|
30
|
-
);
|
|
31
|
-
string = string.replaceAll(windowPathRegex, (match, afterCwd) => {
|
|
32
|
-
return `cwd()${afterCwd.replaceAll("\\", "/")}`;
|
|
33
|
-
});
|
|
34
|
-
} else {
|
|
35
|
-
string = string.replaceAll(rootDirectoryPath, "cwd()");
|
|
34
|
+
if (rootDirectoryPath === undefined) {
|
|
35
|
+
rootDirectoryPath = fileURLToPath(rootDirectoryUrl);
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
const replaceFileUrls = (value) => {
|
|
38
|
+
return value.replaceAll(rootDirectoryUrl, "file:///cwd()");
|
|
39
|
+
};
|
|
40
|
+
const replaceFilePaths = isWindows
|
|
41
|
+
? (value) => {
|
|
42
|
+
const windowPathRegex = new RegExp(
|
|
43
|
+
`${escapeRegexpSpecialChars(rootDirectoryPath)}(((?:\\\\(?:[\\w !#()-]+|[.]{1,2})+)*)(?:\\\\)?)`,
|
|
44
|
+
"gm",
|
|
45
|
+
);
|
|
46
|
+
return value.replaceAll(windowPathRegex, (match, afterCwd) => {
|
|
47
|
+
return `cwd()${afterCwd.replaceAll("\\", "/")}`;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
: (value) => {
|
|
51
|
+
return value.replaceAll(rootDirectoryPath, "cwd()");
|
|
52
|
+
};
|
|
53
|
+
const replaceThings = (value) => {
|
|
54
|
+
if (removeAnsi) {
|
|
55
|
+
value = stripAnsi(value);
|
|
56
|
+
}
|
|
57
|
+
value = replaceFileUrls(value);
|
|
58
|
+
value = replaceFilePaths(value);
|
|
59
|
+
value = replaceHttpUrls(value);
|
|
60
|
+
return value;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
if (fileUrl) {
|
|
64
|
+
const extension = urlToExtension(fileUrl);
|
|
65
|
+
if (extension === ".svg" || extension === ".html") {
|
|
66
|
+
// do parse html
|
|
67
|
+
const htmlAst =
|
|
68
|
+
extension === ".svg"
|
|
69
|
+
? parseSvgString(string)
|
|
70
|
+
: parseHtml({
|
|
71
|
+
html: string,
|
|
72
|
+
storeOriginalPositions: false,
|
|
73
|
+
});
|
|
74
|
+
// for each attribute value
|
|
75
|
+
// and each text node content
|
|
76
|
+
visitHtmlNodes(htmlAst, {
|
|
77
|
+
"*": (node) => {
|
|
78
|
+
const htmlNodeText = getHtmlNodeText(node);
|
|
79
|
+
if (htmlNodeText) {
|
|
80
|
+
setHtmlNodeText(node, replaceThings(htmlNodeText));
|
|
81
|
+
}
|
|
82
|
+
const attributes = getHtmlNodeAttributes(node);
|
|
83
|
+
if (attributes) {
|
|
84
|
+
for (const name of Object.keys(attributes)) {
|
|
85
|
+
attributes[name] = replaceThings(attributes[name]);
|
|
86
|
+
}
|
|
87
|
+
setHtmlNodeAttributes(node, attributes);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
return stringifyHtmlAst(htmlAst);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return replaceThings(string);
|
|
39
95
|
};
|
|
40
96
|
|
|
41
97
|
const replaceHttpUrls = (source) => {
|
|
42
|
-
return source.replace(/(?:https?|ftp):\/\/\S
|
|
98
|
+
return source.replace(/(?:https?|ftp):\/\/\S+[\w/]/g, (match) => {
|
|
43
99
|
const lastChar = match[match.length - 1];
|
|
44
100
|
// hotfix because our url regex sucks a bit
|
|
45
101
|
const endsWithSeparationChar = lastChar === ")" || lastChar === ":";
|
|
@@ -48,10 +104,14 @@ const replaceHttpUrls = (source) => {
|
|
|
48
104
|
}
|
|
49
105
|
try {
|
|
50
106
|
const urlObject = new URL(match);
|
|
107
|
+
if (urlObject.hostname === "www.w3.org") {
|
|
108
|
+
return match;
|
|
109
|
+
}
|
|
51
110
|
if (urlObject.port) {
|
|
52
111
|
urlObject.port = 9999;
|
|
53
112
|
}
|
|
54
|
-
|
|
113
|
+
const url = urlObject.href;
|
|
114
|
+
return url;
|
|
55
115
|
} catch (e) {
|
|
56
116
|
return match;
|
|
57
117
|
}
|