@jsenv/snapshot 2.8.9 → 2.8.10
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 +2 -2
- package/src/replace_fluctuating_values.js +12 -5
- package/src/side_effects/log/log_side_effects.js +65 -3
- package/src/side_effects/render_logs_gif.js +2 -1
- package/src/side_effects/render_side_effects.js +32 -9
- package/src/side_effects/snapshot_side_effects.js +2 -0
- package/src/side_effects/snapshot_tests.js +105 -84
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/snapshot",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.10",
|
|
4
4
|
"description": "Snapshot testing",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"test": "node --conditions=development ./scripts/test.mjs"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@jsenv/assert": "4.
|
|
36
|
+
"@jsenv/assert": "4.2.0",
|
|
37
37
|
"@jsenv/ast": "6.2.16",
|
|
38
38
|
"@jsenv/exception": "1.1.0",
|
|
39
39
|
"@jsenv/filesystem": "4.10.0",
|
|
@@ -38,8 +38,8 @@ export const replaceFluctuatingValues = (
|
|
|
38
38
|
const extension = urlToExtension(fileUrl);
|
|
39
39
|
if (extension === ".html") {
|
|
40
40
|
stringType = "html";
|
|
41
|
-
} else if (extension === ".svg") {
|
|
42
|
-
stringType = "
|
|
41
|
+
} else if (extension === ".svg" || extension === ".xml") {
|
|
42
|
+
stringType = "xml";
|
|
43
43
|
} else if (extension === ".json" || CONTENT_TYPE.isJson(contentType)) {
|
|
44
44
|
stringType = "json";
|
|
45
45
|
}
|
|
@@ -92,10 +92,10 @@ export const replaceFluctuatingValues = (
|
|
|
92
92
|
const replaced = replaceInObject(jsValue, { replace: replaceThings });
|
|
93
93
|
return JSON.stringify(replaced, null, " ");
|
|
94
94
|
}
|
|
95
|
-
if (stringType === "html" || stringType === "
|
|
95
|
+
if (stringType === "html" || stringType === "xml") {
|
|
96
96
|
// do parse html
|
|
97
97
|
const htmlAst =
|
|
98
|
-
stringType === "
|
|
98
|
+
stringType === "xml"
|
|
99
99
|
? parseSvgString(value)
|
|
100
100
|
: parseHtml({
|
|
101
101
|
html: value,
|
|
@@ -112,7 +112,14 @@ export const replaceFluctuatingValues = (
|
|
|
112
112
|
const attributes = getHtmlNodeAttributes(node);
|
|
113
113
|
if (attributes) {
|
|
114
114
|
for (const name of Object.keys(attributes)) {
|
|
115
|
-
|
|
115
|
+
const attributeValue = attributes[name];
|
|
116
|
+
if (name === "timestamp") {
|
|
117
|
+
attributes[name] = "[timestamp]";
|
|
118
|
+
} else if (name === "time") {
|
|
119
|
+
attributes[name] = "[time]";
|
|
120
|
+
} else {
|
|
121
|
+
attributes[name] = replaceThings(attributeValue);
|
|
122
|
+
}
|
|
116
123
|
}
|
|
117
124
|
setHtmlNodeAttributes(node, attributes);
|
|
118
125
|
}
|
|
@@ -5,7 +5,31 @@ import { groupLogSideEffects } from "./group_log_side_effects.js";
|
|
|
5
5
|
const logSideEffectsOptionsDefault = {
|
|
6
6
|
prevent: true,
|
|
7
7
|
group: true,
|
|
8
|
-
|
|
8
|
+
level: "info", // "debug", "trace", "info", "warn", "error", "off"
|
|
9
|
+
onlyIfLevel: "debug",
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const isLogSideEffect = (sideEffect) => {
|
|
13
|
+
const { type } = sideEffect;
|
|
14
|
+
return typeof typeToLevelMap[type] === "number";
|
|
15
|
+
};
|
|
16
|
+
const typeToLevelMap = {
|
|
17
|
+
"console.debug": 0,
|
|
18
|
+
"console.trace": 1,
|
|
19
|
+
"console.info": 2,
|
|
20
|
+
"console.log": 2,
|
|
21
|
+
"process.stdout": 2,
|
|
22
|
+
"console.warn": 3,
|
|
23
|
+
"console.error": 4,
|
|
24
|
+
"process.stderr": 4,
|
|
25
|
+
};
|
|
26
|
+
const levelNumberMap = {
|
|
27
|
+
debug: 0,
|
|
28
|
+
trace: 1,
|
|
29
|
+
info: 2,
|
|
30
|
+
warn: 3,
|
|
31
|
+
error: 4,
|
|
32
|
+
off: 5,
|
|
9
33
|
};
|
|
10
34
|
|
|
11
35
|
export const logSideEffects = (logSideEffectsOptions) => {
|
|
@@ -16,7 +40,30 @@ export const logSideEffects = (logSideEffectsOptions) => {
|
|
|
16
40
|
return {
|
|
17
41
|
name: "console",
|
|
18
42
|
install: (addSideEffect, { addFinallyCallback }) => {
|
|
19
|
-
const { prevent, group,
|
|
43
|
+
const { level, prevent, group, onlyIfLevel } = logSideEffectsOptions;
|
|
44
|
+
const levelNumber = levelNumberMap[level];
|
|
45
|
+
if (onlyIfLevel && onlyIfLevel !== "debug") {
|
|
46
|
+
const onlyIfLevelNumber = levelNumberMap[onlyIfLevel];
|
|
47
|
+
addFinallyCallback((sideEffects) => {
|
|
48
|
+
const logSideEffects = [];
|
|
49
|
+
let hasOneOfLevelOrAbove;
|
|
50
|
+
for (const sideEffect of sideEffects) {
|
|
51
|
+
if (!isLogSideEffect(sideEffect)) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
logSideEffects.push(sideEffect);
|
|
55
|
+
if (!hasOneOfLevelOrAbove) {
|
|
56
|
+
const sideEffectLevel = typeToLevelMap[sideEffect.type];
|
|
57
|
+
hasOneOfLevelOrAbove = sideEffectLevel >= onlyIfLevelNumber;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!hasOneOfLevelOrAbove) {
|
|
61
|
+
for (const logSideEffect of logSideEffects) {
|
|
62
|
+
sideEffects.removeSideEffect(logSideEffect);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
20
67
|
if (group) {
|
|
21
68
|
addFinallyCallback((sideEffects) => {
|
|
22
69
|
groupLogSideEffects(sideEffects, {
|
|
@@ -60,8 +107,23 @@ export const logSideEffects = (logSideEffectsOptions) => {
|
|
|
60
107
|
});
|
|
61
108
|
});
|
|
62
109
|
}
|
|
110
|
+
|
|
63
111
|
const addLogSideEffect = (type, message) => {
|
|
64
|
-
|
|
112
|
+
const sideEffectLevel = typeToLevelMap[type];
|
|
113
|
+
if (sideEffectLevel < levelNumber) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
message = String(message);
|
|
117
|
+
// some messages are flaky by definition we don't want to
|
|
118
|
+
// fail on thoose
|
|
119
|
+
if (
|
|
120
|
+
message.includes(
|
|
121
|
+
"GL Driver Message (OpenGL, Performance, GL_CLOSE_PATH_NV, High): GPU stall due to ReadPixels",
|
|
122
|
+
)
|
|
123
|
+
) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (message.includes("task queue exceeded allotted deadline by")) {
|
|
65
127
|
return;
|
|
66
128
|
}
|
|
67
129
|
addSideEffect({
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { writeFileSync } from "@jsenv/filesystem";
|
|
2
2
|
import { startTerminalRecording } from "@jsenv/terminal-recorder";
|
|
3
|
+
import { isLogSideEffect } from "./log/log_side_effects.js";
|
|
3
4
|
|
|
4
5
|
export const renderLogsGif = async (sideEffects, gitFileUrl) => {
|
|
5
6
|
const terminalRecorder = await startTerminalRecording({
|
|
6
7
|
gif: true,
|
|
7
8
|
});
|
|
8
9
|
for (const sideEffect of sideEffects) {
|
|
9
|
-
if (sideEffect
|
|
10
|
+
if (isLogSideEffect(sideEffect)) {
|
|
10
11
|
await terminalRecorder.write(sideEffect.value, {
|
|
11
12
|
delay: sideEffect.delay,
|
|
12
13
|
});
|
|
@@ -37,9 +37,11 @@ export const createBigSizeEffect =
|
|
|
37
37
|
export const renderSideEffects = (
|
|
38
38
|
sideEffects,
|
|
39
39
|
{
|
|
40
|
+
sourceFileUrl,
|
|
40
41
|
sideEffectMdFileUrl,
|
|
41
42
|
generateOutFileUrl,
|
|
42
43
|
generatedBy = true,
|
|
44
|
+
title,
|
|
43
45
|
titleLevel = 1,
|
|
44
46
|
getBigSizeEffect = createBigSizeEffect({
|
|
45
47
|
details: { line: 15, length: 2000 },
|
|
@@ -63,6 +65,8 @@ export const renderSideEffects = (
|
|
|
63
65
|
};
|
|
64
66
|
|
|
65
67
|
let markdown = "";
|
|
68
|
+
markdown += `# [${title}](${urlToRelativeUrl(sourceFileUrl, sideEffectMdFileUrl, { preferRelativeNotation: true })})`;
|
|
69
|
+
markdown += "\n\n";
|
|
66
70
|
let sideEffectNumber = 0;
|
|
67
71
|
for (const sideEffect of sideEffects) {
|
|
68
72
|
if (sideEffect.skippable) {
|
|
@@ -76,14 +80,15 @@ export const renderSideEffects = (
|
|
|
76
80
|
}
|
|
77
81
|
const lastSideEffectNumber = sideEffectNumber;
|
|
78
82
|
|
|
83
|
+
let sideEffectMd = "";
|
|
79
84
|
for (const sideEffect of sideEffects) {
|
|
80
85
|
if (sideEffect.skippable) {
|
|
81
86
|
continue;
|
|
82
87
|
}
|
|
83
|
-
if (
|
|
84
|
-
|
|
88
|
+
if (sideEffectMd) {
|
|
89
|
+
sideEffectMd += "\n\n";
|
|
85
90
|
}
|
|
86
|
-
|
|
91
|
+
sideEffectMd += renderOneSideEffect(sideEffect, {
|
|
87
92
|
sideEffectMdFileUrl,
|
|
88
93
|
generateOutFileUrl,
|
|
89
94
|
rootDirectoryUrl,
|
|
@@ -94,22 +99,40 @@ export const renderSideEffects = (
|
|
|
94
99
|
lastSideEffectNumber,
|
|
95
100
|
});
|
|
96
101
|
}
|
|
102
|
+
markdown += sideEffectMd;
|
|
97
103
|
if (generatedBy) {
|
|
98
|
-
|
|
104
|
+
markdown += "\n";
|
|
105
|
+
markdown += "---";
|
|
106
|
+
markdown += "\n\n";
|
|
107
|
+
markdown += renderSmallLink(
|
|
99
108
|
{
|
|
100
109
|
text: "@jsenv/snapshot",
|
|
101
110
|
href: "https://github.com/jsenv/core/tree/main/packages/independent/snapshot",
|
|
102
111
|
},
|
|
103
|
-
{
|
|
104
|
-
prefix: "Generated by ",
|
|
105
|
-
},
|
|
112
|
+
{ prefix: "Generated by " },
|
|
106
113
|
);
|
|
107
|
-
markdown += "\n\n";
|
|
108
|
-
markdown += generatedByLink;
|
|
109
114
|
}
|
|
110
115
|
return markdown;
|
|
111
116
|
};
|
|
112
117
|
|
|
118
|
+
export const renderInfosTableMd = (infos) => {
|
|
119
|
+
const infoKeys = Object.keys(infos);
|
|
120
|
+
if (infoKeys.length === 0) {
|
|
121
|
+
return "";
|
|
122
|
+
}
|
|
123
|
+
let infoTableMd = "";
|
|
124
|
+
infoTableMd += "\n";
|
|
125
|
+
infoTableMd += `Infos | `;
|
|
126
|
+
infoTableMd += "\n";
|
|
127
|
+
infoTableMd += `----- | ------`;
|
|
128
|
+
for (const key of infoKeys) {
|
|
129
|
+
infoTableMd += "\n";
|
|
130
|
+
infoTableMd += `${key} | ${infos[key]}`;
|
|
131
|
+
}
|
|
132
|
+
infoTableMd += "\n";
|
|
133
|
+
return infoTableMd;
|
|
134
|
+
};
|
|
135
|
+
|
|
113
136
|
export const renderSmallLink = (
|
|
114
137
|
link,
|
|
115
138
|
{ prefix = "", suffix = "", indent } = {},
|
|
@@ -60,6 +60,8 @@ export const snapshotSideEffects = (
|
|
|
60
60
|
const outDirectorySnapshot = takeDirectorySnapshot(outDirectoryUrl);
|
|
61
61
|
const onSideEffects = (sideEffects) => {
|
|
62
62
|
const sideEffectFileContent = renderSideEffects(sideEffects, {
|
|
63
|
+
sourceFileUrl,
|
|
64
|
+
title: urlToFilename(sourceFileUrl),
|
|
63
65
|
sideEffectMdFileUrl,
|
|
64
66
|
generateOutFileUrl,
|
|
65
67
|
errorTransform,
|
|
@@ -37,8 +37,6 @@ export const snapshotTests = async (
|
|
|
37
37
|
},
|
|
38
38
|
rootDirectoryUrl,
|
|
39
39
|
generatedBy = true,
|
|
40
|
-
linkToSource = true,
|
|
41
|
-
linkToEachSource,
|
|
42
40
|
errorTransform,
|
|
43
41
|
logEffects,
|
|
44
42
|
filesystemEffects,
|
|
@@ -47,7 +45,7 @@ export const snapshotTests = async (
|
|
|
47
45
|
) => {
|
|
48
46
|
filesystemActions = {
|
|
49
47
|
...filesystemActions,
|
|
50
|
-
"**/*.svg": "
|
|
48
|
+
"**/*.svg": "compare_presence_only",
|
|
51
49
|
};
|
|
52
50
|
|
|
53
51
|
const sourceName = urlToBasename(sourceFileUrl, true);
|
|
@@ -67,42 +65,32 @@ export const snapshotTests = async (
|
|
|
67
65
|
|
|
68
66
|
const dirUrlMap = new Map();
|
|
69
67
|
const sideEffectsMap = new Map();
|
|
70
|
-
const
|
|
71
|
-
|
|
68
|
+
const testArray = [];
|
|
69
|
+
let index = 0;
|
|
70
|
+
let hasOnly = false;
|
|
72
71
|
const test = (scenario, fn, options) => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
testArray.push({
|
|
73
|
+
index,
|
|
74
|
+
scenario,
|
|
75
|
+
fn,
|
|
76
|
+
options,
|
|
77
|
+
callSite: getCallerLocation(2),
|
|
78
|
+
});
|
|
79
|
+
index++;
|
|
77
80
|
};
|
|
78
81
|
test.ONLY = (scenario, fn, options) => {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
hasOnly = true;
|
|
83
|
+
testArray.push({
|
|
84
|
+
index,
|
|
85
|
+
scenario,
|
|
86
|
+
fn,
|
|
87
|
+
options,
|
|
88
|
+
callSite: getCallerLocation(2),
|
|
89
|
+
only: true,
|
|
90
|
+
});
|
|
91
|
+
index++;
|
|
83
92
|
};
|
|
84
93
|
const fnReturnValue = await fnRegisteringTest({ test });
|
|
85
|
-
|
|
86
|
-
let activeTestMap;
|
|
87
|
-
const toIgnoreActions = {};
|
|
88
|
-
if (onlyTestMap.size) {
|
|
89
|
-
activeTestMap = onlyTestMap;
|
|
90
|
-
for (const [scenario] of testMap) {
|
|
91
|
-
const testScenario = asValidFilename(scenario);
|
|
92
|
-
const generateScenarioOutFileUrl = (outfilename) => {
|
|
93
|
-
return generateOutFileUrl(`${testScenario}/${outfilename}`);
|
|
94
|
-
};
|
|
95
|
-
const scenarioOutDirectoryUrl = generateScenarioOutFileUrl("");
|
|
96
|
-
toIgnoreActions[scenarioOutDirectoryUrl] = "ignore";
|
|
97
|
-
}
|
|
98
|
-
} else {
|
|
99
|
-
activeTestMap = testMap;
|
|
100
|
-
}
|
|
101
|
-
// ignore tout ceux aui sont désactivé
|
|
102
|
-
const outDirectorySnapshot = takeDirectorySnapshot(outDirectoryUrl, {
|
|
103
|
-
...filesystemActions,
|
|
104
|
-
...toIgnoreActions,
|
|
105
|
-
});
|
|
106
94
|
const captureSideEffects = createCaptureSideEffects({
|
|
107
95
|
sourceFileUrl,
|
|
108
96
|
rootDirectoryUrl,
|
|
@@ -110,50 +98,79 @@ export const snapshotTests = async (
|
|
|
110
98
|
filesystemEffects,
|
|
111
99
|
filesystemActions,
|
|
112
100
|
});
|
|
101
|
+
const sourceRelativeUrl = urlToRelativeUrl(
|
|
102
|
+
sourceFileUrl,
|
|
103
|
+
sideEffectMdFileUrl,
|
|
104
|
+
{
|
|
105
|
+
preferRelativeNotation: true,
|
|
106
|
+
},
|
|
107
|
+
);
|
|
113
108
|
let markdown = "";
|
|
114
|
-
markdown += `# ${
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
suffix:
|
|
124
|
-
linkToSource && sourceFileUrl
|
|
125
|
-
? generateExecutingLink(sourceFileUrl, sideEffectMdFileUrl)
|
|
126
|
-
: "",
|
|
127
|
-
},
|
|
109
|
+
markdown += `# [${urlToFilename(sourceFileUrl)}](${sourceRelativeUrl})`;
|
|
110
|
+
markdown += `\n\n`;
|
|
111
|
+
let testMd = "";
|
|
112
|
+
testMd += `\n\n`;
|
|
113
|
+
let outDirectorySnapshot;
|
|
114
|
+
if (testArray.length === 0) {
|
|
115
|
+
outDirectorySnapshot = takeDirectorySnapshot(
|
|
116
|
+
outDirectoryUrl,
|
|
117
|
+
filesystemActions,
|
|
128
118
|
);
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
119
|
+
testMd += "No test";
|
|
120
|
+
testMd += "\n";
|
|
121
|
+
} else {
|
|
122
|
+
let allTestMd = "";
|
|
123
|
+
const scenarioDirs = [];
|
|
124
|
+
const scenarioIgnoreActions = {};
|
|
125
|
+
const testToExecuteArray = [];
|
|
126
|
+
for (const testRegistered of testArray) {
|
|
127
|
+
const { scenario, only } = testRegistered;
|
|
128
|
+
const scenarioFilename = asValidFilename(scenario);
|
|
129
|
+
scenarioDirs.push(scenarioFilename);
|
|
130
|
+
const generateScenarioOutFileUrl = (outFilename) => {
|
|
131
|
+
return generateOutFileUrl(`${scenarioFilename}/${outFilename}`);
|
|
132
|
+
};
|
|
133
|
+
const scenarioOutDirectoryUrl = generateScenarioOutFileUrl("");
|
|
134
|
+
dirUrlMap.set(scenario, scenarioOutDirectoryUrl);
|
|
135
|
+
const scenarioMdFileUrl = generateScenarioOutFileUrl(
|
|
136
|
+
`${scenarioFilename}.md`,
|
|
137
|
+
);
|
|
138
|
+
allTestMd += `- [${scenario}](${urlToRelativeUrl(scenarioMdFileUrl, sideEffectMdFileUrl)})`;
|
|
139
|
+
allTestMd += "\n";
|
|
140
|
+
if (hasOnly && !only) {
|
|
141
|
+
scenarioIgnoreActions[scenarioOutDirectoryUrl] = "ignore";
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
testRegistered.generateScenarioOutFileUrl = generateScenarioOutFileUrl;
|
|
145
|
+
testRegistered.scenarioMdFileUrl = scenarioMdFileUrl;
|
|
146
|
+
testToExecuteArray.push(testRegistered);
|
|
147
|
+
}
|
|
148
|
+
outDirectorySnapshot = takeDirectorySnapshot(outDirectoryUrl, {
|
|
149
|
+
...filesystemActions,
|
|
150
|
+
...scenarioIgnoreActions,
|
|
155
151
|
});
|
|
156
|
-
|
|
152
|
+
for (const testToExecute of testToExecuteArray) {
|
|
153
|
+
const {
|
|
154
|
+
scenario,
|
|
155
|
+
fn,
|
|
156
|
+
callSite,
|
|
157
|
+
scenarioMdFileUrl,
|
|
158
|
+
generateScenarioOutFileUrl,
|
|
159
|
+
} = testToExecute;
|
|
160
|
+
const sideEffects = await captureSideEffects(fn, {
|
|
161
|
+
baseDirectory: String(new URL("./", callSite.url)),
|
|
162
|
+
});
|
|
163
|
+
sideEffectsMap.set(scenario, sideEffects);
|
|
164
|
+
const sideEffectsMarkdown = renderSideEffects(sideEffects, {
|
|
165
|
+
sourceFileUrl: `${callSite.url}#L${callSite.line}`,
|
|
166
|
+
sideEffectMdFileUrl: scenarioMdFileUrl,
|
|
167
|
+
generateOutFileUrl: generateScenarioOutFileUrl,
|
|
168
|
+
title: scenario,
|
|
169
|
+
errorTransform,
|
|
170
|
+
});
|
|
171
|
+
writeFileSync(scenarioMdFileUrl, sideEffectsMarkdown);
|
|
172
|
+
}
|
|
173
|
+
testMd += allTestMd;
|
|
157
174
|
}
|
|
158
175
|
if (typeof fnReturnValue === "function") {
|
|
159
176
|
await fnReturnValue();
|
|
@@ -174,21 +191,25 @@ export const snapshotTests = async (
|
|
|
174
191
|
// });
|
|
175
192
|
// }
|
|
176
193
|
// }
|
|
194
|
+
markdown += testMd;
|
|
195
|
+
if (generatedBy) {
|
|
196
|
+
markdown += "\n";
|
|
197
|
+
markdown += "---";
|
|
198
|
+
markdown += "\n\n";
|
|
199
|
+
markdown += renderSmallLink(
|
|
200
|
+
{
|
|
201
|
+
text: "@jsenv/snapshot",
|
|
202
|
+
href: "https://github.com/jsenv/core/tree/main/packages/independent/snapshot",
|
|
203
|
+
},
|
|
204
|
+
{ prefix: "Generated by " },
|
|
205
|
+
);
|
|
206
|
+
}
|
|
177
207
|
writeFileSync(sideEffectMdFileUrl, markdown);
|
|
178
208
|
outDirectorySnapshot.compare(throwWhenDiff);
|
|
179
209
|
|
|
180
210
|
return { dirUrlMap, sideEffectsMap };
|
|
181
211
|
};
|
|
182
212
|
|
|
183
|
-
const generateExecutingLink = (sourceFileUrl, sideEffectFileUrl) => {
|
|
184
|
-
const relativeUrl = urlToRelativeUrl(sourceFileUrl, sideEffectFileUrl, {
|
|
185
|
-
preferRelativeNotation: true,
|
|
186
|
-
});
|
|
187
|
-
const href = `${relativeUrl}`;
|
|
188
|
-
const text = `${relativeUrl}`;
|
|
189
|
-
return ` executing <a href="${href}">${text}</a>`;
|
|
190
|
-
};
|
|
191
|
-
|
|
192
213
|
// see https://github.com/parshap/node-sanitize-filename/blob/master/index.js
|
|
193
214
|
const asValidFilename = (string) => {
|
|
194
215
|
return string
|