sqlmath 0.0.1 → 2021.11.20
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/.npmignore +10 -0
- package/CHANGELOG.md +53 -2
- package/LICENSE +16 -22
- package/README.md +18 -219
- package/_binary_sqlmath_napi8_darwin_x64.node +0 -0
- package/_binary_sqlmath_napi8_linux_x64.node +0 -0
- package/_binary_sqlmath_napi8_win32_x64.node +0 -0
- package/jslint.mjs +10998 -0
- package/package.json +23 -8
- package/sqlmath.mjs +1713 -0
- package/.gitconfig +0 -25
- package/.github/workflows/ci.yml +0 -61
- package/.gitignore +0 -24
- package/extension-functions.c +0 -2047
- package/jslint_ci.sh +0 -1968
- package/node_sqlite3.cc +0 -11877
- package/sqlite-autoconf-3360000/INSTALL +0 -370
- package/sqlite-autoconf-3360000/Makefile.am +0 -20
- package/sqlite-autoconf-3360000/Makefile.fallback +0 -19
- package/sqlite-autoconf-3360000/Makefile.in +0 -1028
- package/sqlite-autoconf-3360000/Makefile.msc +0 -1037
- package/sqlite-autoconf-3360000/README.txt +0 -113
- package/sqlite-autoconf-3360000/Replace.cs +0 -223
- package/sqlite-autoconf-3360000/aclocal.m4 +0 -10199
- package/sqlite-autoconf-3360000/compile +0 -347
- package/sqlite-autoconf-3360000/config.guess +0 -1480
- package/sqlite-autoconf-3360000/config.sub +0 -1801
- package/sqlite-autoconf-3360000/configure +0 -16135
- package/sqlite-autoconf-3360000/configure.ac +0 -285
- package/sqlite-autoconf-3360000/depcomp +0 -791
- package/sqlite-autoconf-3360000/install-sh +0 -508
- package/sqlite-autoconf-3360000/ltmain.sh +0 -11156
- package/sqlite-autoconf-3360000/missing +0 -215
- package/sqlite-autoconf-3360000/shell.c +0 -22381
- package/sqlite-autoconf-3360000/sqlite3.1 +0 -286
- package/sqlite-autoconf-3360000/sqlite3.c +0 -235517
- package/sqlite-autoconf-3360000/sqlite3.h +0 -12353
- package/sqlite-autoconf-3360000/sqlite3.pc.in +0 -13
- package/sqlite-autoconf-3360000/sqlite3.rc +0 -83
- package/sqlite-autoconf-3360000/sqlite3ext.h +0 -663
- package/sqlite-autoconf-3360000/sqlite3rc.h +0 -3
- package/sqlite-autoconf-3360000/tea/Makefile.in +0 -440
- package/sqlite-autoconf-3360000/tea/README +0 -36
- package/sqlite-autoconf-3360000/tea/aclocal.m4 +0 -9
- package/sqlite-autoconf-3360000/tea/configure +0 -9989
- package/sqlite-autoconf-3360000/tea/configure.ac +0 -201
- package/sqlite-autoconf-3360000/tea/doc/sqlite3.n +0 -15
- package/sqlite-autoconf-3360000/tea/generic/tclsqlite3.c +0 -4016
- package/sqlite-autoconf-3360000/tea/license.terms +0 -6
- package/sqlite-autoconf-3360000/tea/pkgIndex.tcl.in +0 -7
- package/sqlite-autoconf-3360000/tea/tclconfig/install-sh +0 -528
- package/sqlite-autoconf-3360000/tea/tclconfig/tcl.m4 +0 -4168
- package/sqlite-autoconf-3360000/tea/win/makefile.vc +0 -419
- package/sqlite-autoconf-3360000/tea/win/nmakehlp.c +0 -815
- package/sqlite-autoconf-3360000/tea/win/rules.vc +0 -711
- package/sqlmath.js +0 -238
- package/test/backup.test.js +0 -279
- package/test/blob.test.js +0 -54
- package/test/cache.test.js +0 -42
- package/test/constants.test.js +0 -44
- package/test/database_fail.test.js +0 -153
- package/test/each.test.js +0 -39
- package/test/exec.test.js +0 -39
- package/test/extension.test.js +0 -26
- package/test/extension_functions.test.js +0 -29
- package/test/fts-content.test.js +0 -13
- package/test/interrupt.test.js +0 -80
- package/test/issue-108.test.js +0 -28
- package/test/json.test.js +0 -22
- package/test/map.test.js +0 -63
- package/test/named_columns.test.js +0 -38
- package/test/named_params.test.js +0 -69
- package/test/null_error.test.js +0 -41
- package/test/nw/.gitignore +0 -3
- package/test/nw/Makefile +0 -39
- package/test/nw/index.html +0 -14
- package/test/nw/package.json +0 -9
- package/test/open_close.test.js +0 -187
- package/test/other_objects.test.js +0 -98
- package/test/parallel_insert.test.js +0 -44
- package/test/prepare.test.js +0 -427
- package/test/profile.test.js +0 -57
- package/test/rerun.test.js +0 -50
- package/test/scheduling.test.js +0 -44
- package/test/serialization.test.js +0 -104
- package/test/support/createdb-electron.js +0 -10
- package/test/support/createdb.js +0 -47
- package/test/support/elmo.png +0 -0
- package/test/support/helper.js +0 -37
- package/test/support/script.sql +0 -70
- package/test/trace.test.js +0 -67
- package/test/unicode.test.js +0 -114
- package/test/upsert.test.js +0 -27
- package/test/verbose.test.js +0 -60
- package/test.js +0 -141
- package/test.slr.mjs +0 -212
package/jslint_ci.sh
DELETED
|
@@ -1,1968 +0,0 @@
|
|
|
1
|
-
#!/bin/sh
|
|
2
|
-
|
|
3
|
-
# POSIX reference
|
|
4
|
-
# http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html
|
|
5
|
-
# http://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
|
|
6
|
-
|
|
7
|
-
# sh one-liner
|
|
8
|
-
#
|
|
9
|
-
# git branch -d -r origin/aa
|
|
10
|
-
# git config --global diff.algorithm histogram
|
|
11
|
-
# git fetch origin alpha beta master && git fetch upstream alpha beta master
|
|
12
|
-
# git fetch origin alpha beta master --tags
|
|
13
|
-
# git fetch upstream "refs/tags/*:refs/tags/*"
|
|
14
|
-
# git ls-files --stage | sort
|
|
15
|
-
# git ls-remote --heads origin
|
|
16
|
-
# git update-index --chmod=+x aa.js
|
|
17
|
-
# head CHANGELOG.md -n50
|
|
18
|
-
# ln -f jslint.mjs ~/jslint.mjs
|
|
19
|
-
# openssl rand -base64 32 # random key
|
|
20
|
-
# sh jslint_ci.sh shCiBranchPromote origin alpha beta
|
|
21
|
-
# sh jslint_ci.sh shRunWithScreenshotTxt .build/screenshot-changelog.svg head -n50 CHANGELOG.md
|
|
22
|
-
# vim rgx-lowercase \L\1\e
|
|
23
|
-
|
|
24
|
-
shBrowserScreenshot() {(set -e
|
|
25
|
-
# this function will run headless-chrome to screenshot url $1 with
|
|
26
|
-
# window-size $2
|
|
27
|
-
node --input-type=module -e '
|
|
28
|
-
import moduleChildProcess from "child_process";
|
|
29
|
-
import modulePath from "path";
|
|
30
|
-
import moduleUrl from "url";
|
|
31
|
-
// init debugInline
|
|
32
|
-
(function () {
|
|
33
|
-
let consoleError = console.error;
|
|
34
|
-
globalThis.debugInline = globalThis.debugInline || function (...argList) {
|
|
35
|
-
|
|
36
|
-
// this function will both print <argList> to stderr and return <argList>[0]
|
|
37
|
-
|
|
38
|
-
consoleError("\n\ndebugInline");
|
|
39
|
-
consoleError(...argList);
|
|
40
|
-
consoleError("\n");
|
|
41
|
-
return argList[0];
|
|
42
|
-
};
|
|
43
|
-
}());
|
|
44
|
-
(function () {
|
|
45
|
-
let file;
|
|
46
|
-
let timeStart;
|
|
47
|
-
let url;
|
|
48
|
-
if (process.platform !== "linux") {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
timeStart = Date.now();
|
|
52
|
-
url = process.argv[1];
|
|
53
|
-
if (!(
|
|
54
|
-
/^\w+?:/
|
|
55
|
-
).test(url)) {
|
|
56
|
-
url = modulePath.resolve(url);
|
|
57
|
-
}
|
|
58
|
-
file = moduleUrl.parse(url).pathname;
|
|
59
|
-
// remove prefix $PWD from file
|
|
60
|
-
if (String(file + "/").startsWith(process.cwd() + "/")) {
|
|
61
|
-
file = file.replace(process.cwd(), "");
|
|
62
|
-
}
|
|
63
|
-
file = ".build/screenshot-browser-" + encodeURIComponent(file).replace((
|
|
64
|
-
/%/g
|
|
65
|
-
), "_").toLowerCase() + ".png";
|
|
66
|
-
moduleChildProcess.spawn(
|
|
67
|
-
(
|
|
68
|
-
process.platform === "darwin"
|
|
69
|
-
? "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
|
70
|
-
: process.platform === "win32"
|
|
71
|
-
? "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"
|
|
72
|
-
: "/usr/bin/google-chrome-stable"
|
|
73
|
-
),
|
|
74
|
-
[
|
|
75
|
-
"--headless",
|
|
76
|
-
"--ignore-certificate-errors",
|
|
77
|
-
"--incognito",
|
|
78
|
-
"--screenshot",
|
|
79
|
-
"--timeout=30000",
|
|
80
|
-
"--user-data-dir=/dev/null",
|
|
81
|
-
"--window-size=800x600",
|
|
82
|
-
"-screenshot=" + file,
|
|
83
|
-
(
|
|
84
|
-
(process.getuid && process.getuid() === 0)
|
|
85
|
-
? "--no-sandbox"
|
|
86
|
-
: ""
|
|
87
|
-
),
|
|
88
|
-
url
|
|
89
|
-
].concat(process.argv.filter(function (elem) {
|
|
90
|
-
return elem.startsWith("-");
|
|
91
|
-
})).filter(function (elem) {
|
|
92
|
-
return elem;
|
|
93
|
-
}),
|
|
94
|
-
{
|
|
95
|
-
stdio: [
|
|
96
|
-
"ignore", 1, 2
|
|
97
|
-
]
|
|
98
|
-
}
|
|
99
|
-
).on("exit", function (exitCode) {
|
|
100
|
-
console.error(
|
|
101
|
-
"shBrowserScreenshot"
|
|
102
|
-
+ "\n - url - " + url
|
|
103
|
-
+ "\n - wrote - " + file
|
|
104
|
-
+ "\n - timeElapsed - " + (Date.now() - timeStart) + " ms"
|
|
105
|
-
+ "\n - EXIT_CODE=" + exitCode
|
|
106
|
-
);
|
|
107
|
-
});
|
|
108
|
-
}());
|
|
109
|
-
' "$@" # "'
|
|
110
|
-
)}
|
|
111
|
-
|
|
112
|
-
shCiArtifactUpload() {(set -e
|
|
113
|
-
# this function will upload build-artifacts to branch-gh-pages
|
|
114
|
-
local BRANCH
|
|
115
|
-
local SIZE
|
|
116
|
-
node --input-type=module -e '
|
|
117
|
-
process.exit(Number(
|
|
118
|
-
`${process.version.split(".")[0]}.${process.arch}.${process.platform}` !==
|
|
119
|
-
process.env.CI_NODE_VERSION_ARCH_PLATFORM
|
|
120
|
-
));
|
|
121
|
-
' || return 0
|
|
122
|
-
# init $BRANCH
|
|
123
|
-
BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
|
124
|
-
git pull --unshallow origin "$BRANCH"
|
|
125
|
-
# init .git/config
|
|
126
|
-
git config --local user.email "github-actions@users.noreply.github.com"
|
|
127
|
-
git config --local user.name "github-actions"
|
|
128
|
-
# screenshot asset-image-jslint
|
|
129
|
-
shImageJslintCreate &
|
|
130
|
-
# screenshot web-demo
|
|
131
|
-
shBrowserScreenshot \
|
|
132
|
-
https://jslint-org.github.io/jslint/branch-beta/index.html
|
|
133
|
-
node --input-type=module -e '
|
|
134
|
-
import moduleFs from "fs";
|
|
135
|
-
import moduleChildProcess from "child_process";
|
|
136
|
-
(async function () {
|
|
137
|
-
let screenshotCurl = await moduleFs.promises.stat("jslint.mjs");
|
|
138
|
-
screenshotCurl = String(`
|
|
139
|
-
echo "\
|
|
140
|
-
% Total % Received % Xferd Average Speed Time Time Time Current
|
|
141
|
-
Dload Upload Total Spent Left Speed
|
|
142
|
-
100 250k 100 250k 0 0 250k 0 0:00:01 --:--:-- 0:00:01 250k\
|
|
143
|
-
"
|
|
144
|
-
`).trim().replace((
|
|
145
|
-
/250/g
|
|
146
|
-
), Math.floor(screenshotCurl.size / 1024));
|
|
147
|
-
[
|
|
148
|
-
// parallel-task - screenshot files
|
|
149
|
-
[
|
|
150
|
-
"shRunWithScreenshotTxt",
|
|
151
|
-
".build/screenshot-files.svg",
|
|
152
|
-
"shGitLsTree"
|
|
153
|
-
],
|
|
154
|
-
// parallel-task - screenshot changelog
|
|
155
|
-
[
|
|
156
|
-
"shRunWithScreenshotTxt",
|
|
157
|
-
".build/screenshot-changelog.svg",
|
|
158
|
-
"head",
|
|
159
|
-
"-n50",
|
|
160
|
-
"CHANGELOG.md"
|
|
161
|
-
]
|
|
162
|
-
].forEach(function (argList) {
|
|
163
|
-
moduleChildProcess.spawn("./jslint_ci.sh", argList, {
|
|
164
|
-
stdio: [
|
|
165
|
-
"ignore", 1, 2
|
|
166
|
-
]
|
|
167
|
-
}).on("exit", function (exitCode) {
|
|
168
|
-
if (exitCode) {
|
|
169
|
-
process.exit(exitCode);
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
});
|
|
173
|
-
// parallel-task - screenshot example-shell-commands in README.md
|
|
174
|
-
Array.from(String(
|
|
175
|
-
await moduleFs.promises.readFile("README.md", "utf8")
|
|
176
|
-
).matchAll(
|
|
177
|
-
/\n```shell\u0020<!--\u0020shRunWithScreenshotTxt\u0020(.*?)\u0020-->\n([\S\s]*?\n)```\n/g
|
|
178
|
-
)).forEach(async function ([
|
|
179
|
-
ignore, file, script
|
|
180
|
-
]) {
|
|
181
|
-
await moduleFs.promises.writeFile(file + ".sh", (
|
|
182
|
-
"printf \u0027"
|
|
183
|
-
+ script.trim().replace((
|
|
184
|
-
/[%\\]/gm
|
|
185
|
-
), "$&$&").replace((
|
|
186
|
-
/\u0027/g
|
|
187
|
-
), "\u0027\"\u0027\"\u0027").replace((
|
|
188
|
-
/^/gm
|
|
189
|
-
), "> ")
|
|
190
|
-
+ "\n\n\n\u0027\n"
|
|
191
|
-
+ script.replace(
|
|
192
|
-
"curl -L https://www.jslint.com/jslint.mjs > jslint.mjs",
|
|
193
|
-
screenshotCurl
|
|
194
|
-
)
|
|
195
|
-
));
|
|
196
|
-
moduleChildProcess.spawn(
|
|
197
|
-
"./jslint_ci.sh",
|
|
198
|
-
[
|
|
199
|
-
"shRunWithScreenshotTxt",
|
|
200
|
-
file,
|
|
201
|
-
"sh",
|
|
202
|
-
file + ".sh"
|
|
203
|
-
],
|
|
204
|
-
{
|
|
205
|
-
stdio: [
|
|
206
|
-
"ignore", 1, 2
|
|
207
|
-
]
|
|
208
|
-
}
|
|
209
|
-
);
|
|
210
|
-
});
|
|
211
|
-
}());
|
|
212
|
-
' # '
|
|
213
|
-
# seo - inline css-assets and invalidate cached-assets
|
|
214
|
-
node --input-type=module -e '
|
|
215
|
-
import moduleFs from "fs";
|
|
216
|
-
(async function () {
|
|
217
|
-
let cacheKey = Math.random().toString(36).slice(-4);
|
|
218
|
-
let fileDict = {};
|
|
219
|
-
await Promise.all([
|
|
220
|
-
"asset-codemirror-rollup.css",
|
|
221
|
-
"browser.mjs",
|
|
222
|
-
"index.html"
|
|
223
|
-
].map(async function (file) {
|
|
224
|
-
fileDict[file] = await moduleFs.promises.readFile(file, "utf8");
|
|
225
|
-
}));
|
|
226
|
-
|
|
227
|
-
// Inline css-assets.
|
|
228
|
-
|
|
229
|
-
fileDict["index.html"] = fileDict["index.html"].replace((
|
|
230
|
-
"\n<link rel=\"stylesheet\" href=\"asset-codemirror-rollup.css\">\n"
|
|
231
|
-
), function () {
|
|
232
|
-
return (
|
|
233
|
-
"\n<style>\n"
|
|
234
|
-
+ fileDict["asset-codemirror-rollup.css"].trim()
|
|
235
|
-
+ "\n</style>\n"
|
|
236
|
-
);
|
|
237
|
-
});
|
|
238
|
-
fileDict["index.html"] = fileDict["index.html"].replace((
|
|
239
|
-
"\n<style class=\"JSLINT_REPORT_STYLE\"></style>\n"
|
|
240
|
-
), function () {
|
|
241
|
-
return fileDict["browser.mjs"].match(
|
|
242
|
-
/\n<style\sclass="JSLINT_REPORT_STYLE">\n[\S\s]*?\n<\/style>\n/
|
|
243
|
-
)[0];
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
// Invalidate cached-assets.
|
|
247
|
-
|
|
248
|
-
fileDict["browser.mjs"] = fileDict["browser.mjs"].replace((
|
|
249
|
-
/^import\u0020.+?\u0020from\u0020".+?\.(?:js|mjs)\b/gm
|
|
250
|
-
), function (match0) {
|
|
251
|
-
return `${match0}?cc=${cacheKey}`;
|
|
252
|
-
});
|
|
253
|
-
fileDict["index.html"] = fileDict["index.html"].replace((
|
|
254
|
-
/\b(?:href|src)=".+?\.(?:css|js|mjs)\b/g
|
|
255
|
-
), function (match0) {
|
|
256
|
-
return `${match0}?cc=${cacheKey}`;
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
// Write file.
|
|
260
|
-
|
|
261
|
-
await Promise.all(Object.entries(fileDict).map(function ([
|
|
262
|
-
file, data
|
|
263
|
-
]) {
|
|
264
|
-
moduleFs.promises.writeFile(file, data);
|
|
265
|
-
}));
|
|
266
|
-
}());
|
|
267
|
-
' # '
|
|
268
|
-
# add dir .build
|
|
269
|
-
git add -f .build jslint.cjs jslint.js
|
|
270
|
-
git commit -am "add dir .build"
|
|
271
|
-
# checkout branch-gh-pages
|
|
272
|
-
git checkout -b gh-pages
|
|
273
|
-
git fetch origin gh-pages
|
|
274
|
-
git reset --hard origin/gh-pages
|
|
275
|
-
# update dir branch-$BRANCH
|
|
276
|
-
rm -rf "branch-$BRANCH"
|
|
277
|
-
mkdir "branch-$BRANCH"
|
|
278
|
-
(set -e
|
|
279
|
-
cd "branch-$BRANCH"
|
|
280
|
-
git init -b branch1
|
|
281
|
-
git pull --depth=1 .. "$BRANCH"
|
|
282
|
-
rm -rf .git
|
|
283
|
-
git add -f .
|
|
284
|
-
)
|
|
285
|
-
# update root-dir with branch-beta
|
|
286
|
-
if [ "$BRANCH" = beta ]
|
|
287
|
-
then
|
|
288
|
-
git rm -rf .build
|
|
289
|
-
git checkout beta .
|
|
290
|
-
fi
|
|
291
|
-
# update README.md with branch-$BRANCH and $GITHUB_REPOSITORY
|
|
292
|
-
sed -i \
|
|
293
|
-
-e "s|/branch-[0-9A-Z_a-z]*/|/branch-$BRANCH/|g" \
|
|
294
|
-
-e "s|\bjslint-org/jslint\b|$GITHUB_REPOSITORY|g" \
|
|
295
|
-
-e "s|\bjslint-org\.github\.io/jslint\b|$(
|
|
296
|
-
printf "$GITHUB_REPOSITORY" | sed -e "s|/|.github.io/|"
|
|
297
|
-
)|g" \
|
|
298
|
-
"branch-$BRANCH/README.md"
|
|
299
|
-
git status
|
|
300
|
-
git commit -am "update dir branch-$BRANCH" || true
|
|
301
|
-
# if branch-gh-pages has more than 100 commits,
|
|
302
|
-
# then backup and squash commits
|
|
303
|
-
if [ "$(git rev-list --count gh-pages)" -gt 100 ]
|
|
304
|
-
then
|
|
305
|
-
# backup
|
|
306
|
-
shGitCmdWithGithubToken push origin -f gh-pages:gh-pages-backup
|
|
307
|
-
# squash commits
|
|
308
|
-
git checkout --orphan squash1
|
|
309
|
-
git commit --quiet -am squash || true
|
|
310
|
-
# reset branch-gh-pages to squashed-commit
|
|
311
|
-
git push . -f squash1:gh-pages
|
|
312
|
-
git checkout gh-pages
|
|
313
|
-
# force-push squashed-commit
|
|
314
|
-
shGitCmdWithGithubToken push origin -f gh-pages
|
|
315
|
-
fi
|
|
316
|
-
# list files
|
|
317
|
-
shGitLsTree
|
|
318
|
-
# push branch-gh-pages
|
|
319
|
-
shGitCmdWithGithubToken push origin gh-pages
|
|
320
|
-
# validate http-links
|
|
321
|
-
(set -e
|
|
322
|
-
cd "branch-$BRANCH"
|
|
323
|
-
sleep 15
|
|
324
|
-
shDirHttplinkValidate
|
|
325
|
-
)
|
|
326
|
-
)}
|
|
327
|
-
|
|
328
|
-
shCiBase() {(set -e
|
|
329
|
-
# this function will run base-ci
|
|
330
|
-
)}
|
|
331
|
-
|
|
332
|
-
shCiBranchPromote() {(set -e
|
|
333
|
-
# this function will promote branch $REMOTE/$BRANCH1 to branch $REMOTE/$BRANCH2
|
|
334
|
-
local BRANCH1
|
|
335
|
-
local BRANCH2
|
|
336
|
-
local REMOTE
|
|
337
|
-
REMOTE="$1"
|
|
338
|
-
shift
|
|
339
|
-
BRANCH1="$1"
|
|
340
|
-
shift
|
|
341
|
-
BRANCH2="$1"
|
|
342
|
-
shift
|
|
343
|
-
git fetch "$REMOTE" "$BRANCH1"
|
|
344
|
-
git push "$REMOTE" "$REMOTE/$BRANCH1:$BRANCH2" "$@"
|
|
345
|
-
)}
|
|
346
|
-
|
|
347
|
-
shDirHttplinkValidate() {(set -e
|
|
348
|
-
# this function will validate http-links embedded in .html and .md files
|
|
349
|
-
node --input-type=module -e '
|
|
350
|
-
import moduleFs from "fs";
|
|
351
|
-
import moduleHttps from "https";
|
|
352
|
-
import moduleUrl from "url";
|
|
353
|
-
(async function () {
|
|
354
|
-
let dict = {};
|
|
355
|
-
Array.from(
|
|
356
|
-
await moduleFs.promises.readdir(".")
|
|
357
|
-
).forEach(async function (file) {
|
|
358
|
-
let data;
|
|
359
|
-
if (!(
|
|
360
|
-
/.\.html$|.\.md$/m
|
|
361
|
-
).test(file)) {
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
data = await moduleFs.promises.readFile(file, "utf8");
|
|
365
|
-
data.replace((
|
|
366
|
-
/\bhttps?:\/\/.*?(?:[\s")\]]|\W?$)/gm
|
|
367
|
-
), function (url) {
|
|
368
|
-
let req;
|
|
369
|
-
url = url.slice(0, -1).replace((
|
|
370
|
-
/[\u0022\u0027]/g
|
|
371
|
-
), "").replace((
|
|
372
|
-
/\/branch-\w+?\//g
|
|
373
|
-
), "/branch-alpha/").replace((
|
|
374
|
-
/\bjslint-org\/jslint\b/g
|
|
375
|
-
), process.env.GITHUB_REPOSITORY || "jslint-org/jslint").replace((
|
|
376
|
-
/\bjslint-org\.github\.io\/jslint\b/g
|
|
377
|
-
), String(
|
|
378
|
-
process.env.GITHUB_REPOSITORY || "jslint-org/jslint"
|
|
379
|
-
).replace("/", ".github.io/"));
|
|
380
|
-
if (url.startsWith("http://")) {
|
|
381
|
-
throw new Error("shDirHttplinkValidate - insecure link " + url);
|
|
382
|
-
}
|
|
383
|
-
// ignore duplicate-link
|
|
384
|
-
if (dict.hasOwnProperty(url)) {
|
|
385
|
-
return "";
|
|
386
|
-
}
|
|
387
|
-
dict[url] = true;
|
|
388
|
-
req = moduleHttps.request(moduleUrl.parse(
|
|
389
|
-
url
|
|
390
|
-
), function (res) {
|
|
391
|
-
console.error(
|
|
392
|
-
"shDirHttplinkValidate " + res.statusCode + " " + url
|
|
393
|
-
);
|
|
394
|
-
if (!(res.statusCode < 400)) {
|
|
395
|
-
throw new Error(
|
|
396
|
-
"shDirHttplinkValidate - " + file
|
|
397
|
-
+ " - unreachable link " + url
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
req.abort();
|
|
401
|
-
res.destroy();
|
|
402
|
-
});
|
|
403
|
-
req.setTimeout(30000);
|
|
404
|
-
req.end();
|
|
405
|
-
return "";
|
|
406
|
-
});
|
|
407
|
-
data.replace((
|
|
408
|
-
/(\bhref=|\bsrc=|\burl\(|\[[^]*?\]\()("?.*?)(?:[")\]]|$)/gm
|
|
409
|
-
), function (ignore, linkType, url) {
|
|
410
|
-
if (!linkType.startsWith("[")) {
|
|
411
|
-
url = url.slice(1);
|
|
412
|
-
}
|
|
413
|
-
if (url.length === 0 || url.startsWith("data:")) {
|
|
414
|
-
return;
|
|
415
|
-
}
|
|
416
|
-
// ignore duplicate-link
|
|
417
|
-
if (dict.hasOwnProperty(url)) {
|
|
418
|
-
return "";
|
|
419
|
-
}
|
|
420
|
-
dict[url] = true;
|
|
421
|
-
if (!(
|
|
422
|
-
/^https?|^mailto:|^[#\/]/m
|
|
423
|
-
).test(url)) {
|
|
424
|
-
moduleFs.stat(url.split("?")[0], function (ignore, exists) {
|
|
425
|
-
console.error(
|
|
426
|
-
"shDirHttplinkValidate " + Boolean(exists) + " " + url
|
|
427
|
-
);
|
|
428
|
-
if (!exists) {
|
|
429
|
-
throw new Error(
|
|
430
|
-
"shDirHttplinkValidate - " + file
|
|
431
|
-
+ " - unreachable link " + url
|
|
432
|
-
);
|
|
433
|
-
}
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
return "";
|
|
437
|
-
});
|
|
438
|
-
});
|
|
439
|
-
}());
|
|
440
|
-
' # "'
|
|
441
|
-
)}
|
|
442
|
-
|
|
443
|
-
shGitCmdWithGithubToken() {(set -e
|
|
444
|
-
# this function will run git $CMD with $GITHUB_TOKEN
|
|
445
|
-
local CMD
|
|
446
|
-
local EXIT_CODE
|
|
447
|
-
local REMOTE
|
|
448
|
-
local URL
|
|
449
|
-
printf "shGitCmdWithGithubToken $*\n"
|
|
450
|
-
CMD="$1"
|
|
451
|
-
shift
|
|
452
|
-
REMOTE="$1"
|
|
453
|
-
shift
|
|
454
|
-
URL="$(
|
|
455
|
-
git config "remote.$REMOTE.url" \
|
|
456
|
-
| sed -e "s|https://|https://x-access-token:$GITHUB_TOKEN@|"
|
|
457
|
-
)"
|
|
458
|
-
EXIT_CODE=0
|
|
459
|
-
# hide $GITHUB_TOKEN in case of err
|
|
460
|
-
git "$CMD" "$URL" "$@" 2>/dev/null || EXIT_CODE="$?"
|
|
461
|
-
printf "shGitCmdWithGithubToken - EXIT_CODE=$EXIT_CODE\n" 1>&2
|
|
462
|
-
return "$EXIT_CODE"
|
|
463
|
-
)}
|
|
464
|
-
|
|
465
|
-
shGitLsTree() {(set -e
|
|
466
|
-
# this function will "git ls-tree" all files committed in HEAD
|
|
467
|
-
# example use:
|
|
468
|
-
# shGitLsTree | sort -rk3 # sort by date
|
|
469
|
-
# shGitLsTree | sort -rk4 # sort by size
|
|
470
|
-
node --input-type=module -e '
|
|
471
|
-
import moduleChildProcess from "child_process";
|
|
472
|
-
(async function () {
|
|
473
|
-
let result;
|
|
474
|
-
// get file, mode, size
|
|
475
|
-
result = await new Promise(function (resolve) {
|
|
476
|
-
result = "";
|
|
477
|
-
moduleChildProcess.spawn("git", [
|
|
478
|
-
"ls-tree", "-lr", "HEAD"
|
|
479
|
-
], {
|
|
480
|
-
encoding: "utf8",
|
|
481
|
-
stdio: [
|
|
482
|
-
"ignore", "pipe", 2
|
|
483
|
-
]
|
|
484
|
-
}).on("exit", function () {
|
|
485
|
-
resolve(result);
|
|
486
|
-
}).stdout.on("data", function (chunk) {
|
|
487
|
-
result += chunk;
|
|
488
|
-
}).setEncoding("utf8");
|
|
489
|
-
});
|
|
490
|
-
result = Array.from(result.matchAll(
|
|
491
|
-
/^(\S+?)\u0020+?\S+?\u0020+?\S+?\u0020+?(\S+?)\t(\S+?)$/gm
|
|
492
|
-
)).map(function ([
|
|
493
|
-
ignore, mode, size, file
|
|
494
|
-
]) {
|
|
495
|
-
return {
|
|
496
|
-
file,
|
|
497
|
-
mode: mode.slice(-3),
|
|
498
|
-
size: Number(size)
|
|
499
|
-
};
|
|
500
|
-
});
|
|
501
|
-
result = result.sort(function (aa, bb) {
|
|
502
|
-
return aa.file > bb.file || -1;
|
|
503
|
-
});
|
|
504
|
-
result = result.slice(0, 1000);
|
|
505
|
-
result.unshift({
|
|
506
|
-
file: ".",
|
|
507
|
-
mode: "755",
|
|
508
|
-
size: 0
|
|
509
|
-
});
|
|
510
|
-
// get date
|
|
511
|
-
result.forEach(function (elem) {
|
|
512
|
-
result[0].size += elem.size;
|
|
513
|
-
moduleChildProcess.spawn("git", [
|
|
514
|
-
"log", "--max-count=1", "--format=%at", elem.file
|
|
515
|
-
], {
|
|
516
|
-
stdio: [
|
|
517
|
-
"ignore", "pipe", 2
|
|
518
|
-
]
|
|
519
|
-
}).stdout.on("data", function (chunk) {
|
|
520
|
-
elem.date = new Date(
|
|
521
|
-
Number(chunk) * 1000
|
|
522
|
-
).toISOString().slice(0, 19) + "Z";
|
|
523
|
-
});
|
|
524
|
-
});
|
|
525
|
-
process.on("exit", function () {
|
|
526
|
-
let iiPad;
|
|
527
|
-
let sizePad;
|
|
528
|
-
iiPad = String(result.length).length + 1;
|
|
529
|
-
sizePad = String(Math.ceil(result[0].size / 1024)).length;
|
|
530
|
-
process.stdout.write(result.map(function (elem, ii) {
|
|
531
|
-
return (
|
|
532
|
-
String(ii + ".").padStart(iiPad, " ")
|
|
533
|
-
+ " " + elem.mode
|
|
534
|
-
+ " " + elem.date
|
|
535
|
-
+ " " + String(
|
|
536
|
-
Math.ceil(elem.size / 1024)
|
|
537
|
-
).padStart(sizePad, " ") + " KB"
|
|
538
|
-
+ " " + elem.file
|
|
539
|
-
+ "\n"
|
|
540
|
-
);
|
|
541
|
-
}).join(""));
|
|
542
|
-
});
|
|
543
|
-
}());
|
|
544
|
-
' # "'
|
|
545
|
-
)}
|
|
546
|
-
|
|
547
|
-
shHttpFileServer() {(set -e
|
|
548
|
-
# this function will run simple node http-file-server on port $PORT
|
|
549
|
-
if [ ! "$npm_config_mode_auto_restart" ]
|
|
550
|
-
then
|
|
551
|
-
local EXIT_CODE
|
|
552
|
-
EXIT_CODE=0
|
|
553
|
-
export npm_config_mode_auto_restart=1
|
|
554
|
-
while true
|
|
555
|
-
do
|
|
556
|
-
printf "\n"
|
|
557
|
-
git diff --color 2>/dev/null | cat || true
|
|
558
|
-
printf "\nshHttpFileServer - (re)starting $*\n"
|
|
559
|
-
(shHttpFileServer "$@") || EXIT_CODE="$?"
|
|
560
|
-
printf "process exited with code $EXIT_CODE\n"
|
|
561
|
-
# if $EXIT_CODE != 77, then exit process
|
|
562
|
-
# http://en.wikipedia.org/wiki/Unix_signal
|
|
563
|
-
if [ "$EXIT_CODE" != 77 ]
|
|
564
|
-
then
|
|
565
|
-
break
|
|
566
|
-
fi
|
|
567
|
-
# else restart process after 1 second
|
|
568
|
-
sleep 1
|
|
569
|
-
done
|
|
570
|
-
return
|
|
571
|
-
fi
|
|
572
|
-
node --input-type=module -e '
|
|
573
|
-
import moduleChildProcess from "child_process";
|
|
574
|
-
import moduleFs from "fs";
|
|
575
|
-
import moduleHttp from "http";
|
|
576
|
-
import modulePath from "path";
|
|
577
|
-
import moduleRepl from "repl";
|
|
578
|
-
import moduleUrl from "url";
|
|
579
|
-
// init debugInline
|
|
580
|
-
(function () {
|
|
581
|
-
let consoleError = console.error;
|
|
582
|
-
globalThis.debugInline = globalThis.debugInline || function (...argList) {
|
|
583
|
-
|
|
584
|
-
// this function will both print <argList> to stderr and return <argList>[0]
|
|
585
|
-
|
|
586
|
-
consoleError("\n\ndebugInline");
|
|
587
|
-
consoleError(...argList);
|
|
588
|
-
consoleError("\n");
|
|
589
|
-
return argList[0];
|
|
590
|
-
};
|
|
591
|
-
}());
|
|
592
|
-
(async function httpFileServer() {
|
|
593
|
-
/*
|
|
594
|
-
* this function will start http-file-server
|
|
595
|
-
*/
|
|
596
|
-
let contentTypeDict = {
|
|
597
|
-
".bmp": "image/bmp",
|
|
598
|
-
".cjs": "application/javascript; charset=utf-8",
|
|
599
|
-
".css": "text/css; charset=utf-8",
|
|
600
|
-
".gif": "image/gif",
|
|
601
|
-
".htm": "text/html; charset=utf-8",
|
|
602
|
-
".html": "text/html; charset=utf-8",
|
|
603
|
-
".jpe": "image/jpeg",
|
|
604
|
-
".jpeg": "image/jpeg",
|
|
605
|
-
".jpg": "image/jpeg",
|
|
606
|
-
".js": "application/javascript; charset=utf-8",
|
|
607
|
-
".json": "application/json; charset=utf-8",
|
|
608
|
-
".md": "text/markdown; charset=utf-8",
|
|
609
|
-
".mjs": "application/javascript; charset=utf-8",
|
|
610
|
-
".pdf": "application/pdf",
|
|
611
|
-
".png": "image/png",
|
|
612
|
-
".svg": "image/svg+xml; charset=utf-8",
|
|
613
|
-
".txt": "text/plain; charset=utf-8",
|
|
614
|
-
".wasm": "application/wasm",
|
|
615
|
-
".woff": "font/woff",
|
|
616
|
-
".woff2": "font/woff2",
|
|
617
|
-
".xml": "application/xml; charset=utf-8",
|
|
618
|
-
"/": "text/html; charset=utf-8"
|
|
619
|
-
};
|
|
620
|
-
if (process.argv[1]) {
|
|
621
|
-
await import("file://" + modulePath.resolve(process.argv[1]));
|
|
622
|
-
}
|
|
623
|
-
process.env.PORT = process.env.PORT || "8080";
|
|
624
|
-
console.error("http-file-server listening on port " + process.env.PORT);
|
|
625
|
-
moduleHttp.createServer(function (req, res) {
|
|
626
|
-
let file;
|
|
627
|
-
let pathname;
|
|
628
|
-
let timeStart;
|
|
629
|
-
// init timeStart
|
|
630
|
-
timeStart = Date.now();
|
|
631
|
-
// init pathname
|
|
632
|
-
pathname = moduleUrl.parse(req.url).pathname;
|
|
633
|
-
// debug - serverLog
|
|
634
|
-
res.on("close", function () {
|
|
635
|
-
if (pathname === "/favicon.ico") {
|
|
636
|
-
return;
|
|
637
|
-
}
|
|
638
|
-
console.error(
|
|
639
|
-
"serverLog - " +
|
|
640
|
-
new Date(timeStart).toISOString() + " - " +
|
|
641
|
-
(Date.now() - timeStart) + "ms - " +
|
|
642
|
-
(res.statusCode || 0) + " " + req.method + " " + pathname
|
|
643
|
-
);
|
|
644
|
-
});
|
|
645
|
-
// debug - echo request
|
|
646
|
-
if (pathname === "/echo") {
|
|
647
|
-
res.write(JSON.stringify(req.headers, undefined, 4) + "\n");
|
|
648
|
-
req.pipe(res);
|
|
649
|
-
return;
|
|
650
|
-
}
|
|
651
|
-
// replace trailing "/" with "/index.html"
|
|
652
|
-
file = pathname.slice(1).replace((
|
|
653
|
-
/\/$/
|
|
654
|
-
), "/index.html");
|
|
655
|
-
// resolve file
|
|
656
|
-
file = modulePath.resolve(file);
|
|
657
|
-
// security - disable parent-directory lookup
|
|
658
|
-
if (!file.startsWith(process.cwd() + modulePath.sep)) {
|
|
659
|
-
res.statusCode = 404;
|
|
660
|
-
res.end();
|
|
661
|
-
return;
|
|
662
|
-
}
|
|
663
|
-
moduleFs.readFile(file, function (err, data) {
|
|
664
|
-
let contentType;
|
|
665
|
-
if (err) {
|
|
666
|
-
res.statusCode = 404;
|
|
667
|
-
res.end();
|
|
668
|
-
return;
|
|
669
|
-
}
|
|
670
|
-
contentType = contentTypeDict[(
|
|
671
|
-
/^\/$|\.[^.]*?$|$/m
|
|
672
|
-
).exec(file)[0]];
|
|
673
|
-
if (contentType) {
|
|
674
|
-
res.setHeader("content-type", contentType);
|
|
675
|
-
}
|
|
676
|
-
res.end(data);
|
|
677
|
-
});
|
|
678
|
-
}).listen(process.env.PORT);
|
|
679
|
-
}());
|
|
680
|
-
(function jslintDir() {
|
|
681
|
-
/*
|
|
682
|
-
* this function will jslint current-directory
|
|
683
|
-
*/
|
|
684
|
-
moduleFs.stat((
|
|
685
|
-
process.env.HOME + "/jslint.mjs"
|
|
686
|
-
), function (ignore, exists) {
|
|
687
|
-
if (exists) {
|
|
688
|
-
moduleChildProcess.spawn("node", [
|
|
689
|
-
process.env.HOME + "/jslint.mjs", "."
|
|
690
|
-
], {
|
|
691
|
-
stdio: [
|
|
692
|
-
"ignore", 1, 2
|
|
693
|
-
]
|
|
694
|
-
});
|
|
695
|
-
}
|
|
696
|
-
});
|
|
697
|
-
}());
|
|
698
|
-
(function replStart() {
|
|
699
|
-
/*
|
|
700
|
-
* this function will start repl-debugger
|
|
701
|
-
*/
|
|
702
|
-
let that;
|
|
703
|
-
// start repl
|
|
704
|
-
that = moduleRepl.start({
|
|
705
|
-
useGlobal: true
|
|
706
|
-
});
|
|
707
|
-
// init history
|
|
708
|
-
that.setupHistory(modulePath.resolve(
|
|
709
|
-
process.env.HOME + "/.node_repl_history"
|
|
710
|
-
), function () {
|
|
711
|
-
return;
|
|
712
|
-
});
|
|
713
|
-
// save eval-function
|
|
714
|
-
that.evalDefault = that.eval;
|
|
715
|
-
// hook custom-eval-function
|
|
716
|
-
that.eval = function (script, context, file, onError) {
|
|
717
|
-
script.replace((
|
|
718
|
-
/^(\S+)\u0020(.*?)\n/
|
|
719
|
-
), function (ignore, match1, match2) {
|
|
720
|
-
switch (match1) {
|
|
721
|
-
// syntax-sugar - run shell-cmd
|
|
722
|
-
case "$":
|
|
723
|
-
switch (match2.split(" ").slice(0, 2).join(" ")) {
|
|
724
|
-
// syntax-sugar - run git diff
|
|
725
|
-
case "git diff":
|
|
726
|
-
match2 += " --color";
|
|
727
|
-
break;
|
|
728
|
-
// syntax-sugar - run git log
|
|
729
|
-
case "git log":
|
|
730
|
-
match2 += " -n 10";
|
|
731
|
-
break;
|
|
732
|
-
// syntax-sugar - run ll
|
|
733
|
-
case "ll":
|
|
734
|
-
match2 = "ls -Fal";
|
|
735
|
-
break;
|
|
736
|
-
}
|
|
737
|
-
match2 = match2.replace((
|
|
738
|
-
/^git\u0020/
|
|
739
|
-
), "git --no-pager ");
|
|
740
|
-
// run shell-cmd
|
|
741
|
-
console.error("$ " + match2);
|
|
742
|
-
moduleChildProcess.spawn(match2, {
|
|
743
|
-
shell: true,
|
|
744
|
-
stdio: [
|
|
745
|
-
"ignore", 1, 2
|
|
746
|
-
]
|
|
747
|
-
// print exitCode
|
|
748
|
-
}).on("exit", function (exitCode) {
|
|
749
|
-
console.error("$ EXIT_CODE=" + exitCode);
|
|
750
|
-
that.evalDefault("\n", context, file, onError);
|
|
751
|
-
});
|
|
752
|
-
script = "\n";
|
|
753
|
-
break;
|
|
754
|
-
// syntax-sugar - map text with charCodeAt
|
|
755
|
-
case "charCode":
|
|
756
|
-
console.error(
|
|
757
|
-
match2.split("").map(function (chr) {
|
|
758
|
-
return (
|
|
759
|
-
"\\u" +
|
|
760
|
-
chr.charCodeAt(0).toString(16).padStart(4, 0)
|
|
761
|
-
);
|
|
762
|
-
}).join("")
|
|
763
|
-
);
|
|
764
|
-
script = "\n";
|
|
765
|
-
break;
|
|
766
|
-
// syntax-sugar - sort chr
|
|
767
|
-
case "charSort":
|
|
768
|
-
console.error(JSON.stringify(match2.split("").sort().join("")));
|
|
769
|
-
script = "\n";
|
|
770
|
-
break;
|
|
771
|
-
// syntax-sugar - list obj-keys, sorted by item-type
|
|
772
|
-
// console.error(Object.keys(global).map(function(key){return(typeof global[key]===\u0027object\u0027&&global[key]&&global[key]===global[key]?\u0027global\u0027:typeof global[key])+\u0027 \u0027+key;}).sort().join(\u0027\n\u0027)) //jslint-quiet
|
|
773
|
-
case "keys":
|
|
774
|
-
script = (
|
|
775
|
-
"console.error(Object.keys(" + match2 +
|
|
776
|
-
").map(function(key){return(" +
|
|
777
|
-
"typeof " + match2 + "[key]===\u0027object\u0027&&" +
|
|
778
|
-
match2 + "[key]&&" +
|
|
779
|
-
match2 + "[key]===global[key]" +
|
|
780
|
-
"?\u0027global\u0027" +
|
|
781
|
-
":typeof " + match2 + "[key]" +
|
|
782
|
-
")+\u0027 \u0027+key;" +
|
|
783
|
-
"}).sort().join(\u0027\\n\u0027))\n"
|
|
784
|
-
);
|
|
785
|
-
break;
|
|
786
|
-
// syntax-sugar - print String(val)
|
|
787
|
-
case "print":
|
|
788
|
-
script = "console.error(String(" + match2 + "))\n";
|
|
789
|
-
break;
|
|
790
|
-
}
|
|
791
|
-
});
|
|
792
|
-
// eval script
|
|
793
|
-
that.evalDefault(script, context, file, onError);
|
|
794
|
-
};
|
|
795
|
-
}());
|
|
796
|
-
(function watchDir() {
|
|
797
|
-
/*
|
|
798
|
-
* this function will watch current-directory for changes
|
|
799
|
-
*/
|
|
800
|
-
moduleFs.readdir(".", function (ignore, fileList) {
|
|
801
|
-
fileList.forEach(function (file) {
|
|
802
|
-
if (file[0] === ".") {
|
|
803
|
-
return;
|
|
804
|
-
}
|
|
805
|
-
moduleFs.stat(file, function (ignore, stats) {
|
|
806
|
-
if (!(stats && stats.isFile())) {
|
|
807
|
-
return;
|
|
808
|
-
}
|
|
809
|
-
moduleFs.watchFile(file, {
|
|
810
|
-
interval: 1000,
|
|
811
|
-
persistent: false
|
|
812
|
-
}, function () {
|
|
813
|
-
console.error("watchFile - modified - " + file);
|
|
814
|
-
setTimeout(process.exit.bind(undefined, 77), 1000);
|
|
815
|
-
});
|
|
816
|
-
});
|
|
817
|
-
});
|
|
818
|
-
});
|
|
819
|
-
}());
|
|
820
|
-
' "$@" # '
|
|
821
|
-
)}
|
|
822
|
-
|
|
823
|
-
shImageJslintCreate() {(set -e
|
|
824
|
-
# this function will create .png logo of jslint
|
|
825
|
-
echo '
|
|
826
|
-
<!DOCTYPE html>
|
|
827
|
-
<html lang="en">
|
|
828
|
-
<head>
|
|
829
|
-
<title>logo</title>
|
|
830
|
-
<style>
|
|
831
|
-
/* sh jslint_ci.sh shBrowserScreenshot asset-image-jslint.html --window-size=512x512 */
|
|
832
|
-
/* csslint box-model:false */
|
|
833
|
-
/* csslint ignore:start */
|
|
834
|
-
*,
|
|
835
|
-
*:after,
|
|
836
|
-
*:before {
|
|
837
|
-
box-sizing: border-box;
|
|
838
|
-
}
|
|
839
|
-
@font-face {
|
|
840
|
-
font-family: Daley;
|
|
841
|
-
font-weight: bold;
|
|
842
|
-
src: url("asset-font-daley-bold.woff2") format("woff2");
|
|
843
|
-
}
|
|
844
|
-
/* csslint ignore:end */
|
|
845
|
-
body,
|
|
846
|
-
div {
|
|
847
|
-
margin: 0;
|
|
848
|
-
}
|
|
849
|
-
.container1 {
|
|
850
|
-
background: antiquewhite;
|
|
851
|
-
border: 24px solid darkslategray;
|
|
852
|
-
border-radius: 96px;
|
|
853
|
-
color: darkslategray;
|
|
854
|
-
font-family: Daley;
|
|
855
|
-
height: 512px;
|
|
856
|
-
margin: 0;
|
|
857
|
-
position: relative;
|
|
858
|
-
width: 512px;
|
|
859
|
-
zoom: 100%;
|
|
860
|
-
/*
|
|
861
|
-
background: transparent;
|
|
862
|
-
border: 24px solid black;
|
|
863
|
-
color: black;
|
|
864
|
-
*/
|
|
865
|
-
}
|
|
866
|
-
.text1 {
|
|
867
|
-
font-size: 256px;
|
|
868
|
-
left: 44px;
|
|
869
|
-
position: absolute;
|
|
870
|
-
top: 32px;
|
|
871
|
-
}
|
|
872
|
-
.text2 {
|
|
873
|
-
bottom: 8px;
|
|
874
|
-
font-size: 192px;
|
|
875
|
-
left: 44px;
|
|
876
|
-
position: absolute;
|
|
877
|
-
}
|
|
878
|
-
</style>
|
|
879
|
-
</head>
|
|
880
|
-
<body>
|
|
881
|
-
<div class="container1">
|
|
882
|
-
<div class="text1">JS</div>
|
|
883
|
-
<div class="text2">Lint</div>
|
|
884
|
-
</div>
|
|
885
|
-
</body>
|
|
886
|
-
</html>
|
|
887
|
-
' > .build/asset-image-jslint-512.html
|
|
888
|
-
cp asset-font-daley-bold.woff2 .build
|
|
889
|
-
# screenshot asset-image-jslint-512.png
|
|
890
|
-
shBrowserScreenshot .build/asset-image-jslint-512.html \
|
|
891
|
-
--window-size=512x512 \
|
|
892
|
-
-screenshot=.build/asset-image-jslint-512.png
|
|
893
|
-
# create various smaller thumbnails
|
|
894
|
-
for SIZE in 32 64 128 256
|
|
895
|
-
do
|
|
896
|
-
convert -resize "${SIZE}x${SIZE}" .build/asset-image-jslint-512.png \
|
|
897
|
-
".build/asset-image-jslint-$SIZE.png"
|
|
898
|
-
printf \
|
|
899
|
-
"shImageJslintCreate - wrote - .build/asset-image-jslint-$SIZE.png\n" 1>&2
|
|
900
|
-
done
|
|
901
|
-
# convert to svg @ https://convertio.co/png-svg/
|
|
902
|
-
)}
|
|
903
|
-
|
|
904
|
-
shImageToDataUri() {(set -e
|
|
905
|
-
# this function will convert image $1 to data-uri string
|
|
906
|
-
node --input-type=module -e '
|
|
907
|
-
import moduleFs from "fs";
|
|
908
|
-
import moduleHttps from "https";
|
|
909
|
-
(async function () {
|
|
910
|
-
let file;
|
|
911
|
-
let result;
|
|
912
|
-
file = process.argv[1];
|
|
913
|
-
if ((
|
|
914
|
-
/^https:\/\//
|
|
915
|
-
).test(file)) {
|
|
916
|
-
result = await new Promise(function (resolve) {
|
|
917
|
-
moduleHttps.get(file, function (res) {
|
|
918
|
-
let chunkList;
|
|
919
|
-
chunkList = [];
|
|
920
|
-
res.on("data", function (chunk) {
|
|
921
|
-
chunkList.push(chunk);
|
|
922
|
-
}).on("end", function () {
|
|
923
|
-
resolve(Buffer.concat(chunkList));
|
|
924
|
-
});
|
|
925
|
-
});
|
|
926
|
-
});
|
|
927
|
-
} else {
|
|
928
|
-
result = await moduleFs.promises.readFile(file);
|
|
929
|
-
}
|
|
930
|
-
result = String(
|
|
931
|
-
"data:image/" + file.match(
|
|
932
|
-
/\.[^.]*?$|$/m
|
|
933
|
-
)[0].slice(1) + ";base64," + result.toString("base64")
|
|
934
|
-
).replace((
|
|
935
|
-
/.{72}/g
|
|
936
|
-
), "$&\\\n");
|
|
937
|
-
console.log(result);
|
|
938
|
-
}());
|
|
939
|
-
' "$@" # '
|
|
940
|
-
)}
|
|
941
|
-
|
|
942
|
-
shJsonNormalize() {(set -e
|
|
943
|
-
# this function will
|
|
944
|
-
# 1. read json-data from file $1
|
|
945
|
-
# 2. normalize json-data
|
|
946
|
-
# 3. write normalized json-data back to file $1
|
|
947
|
-
node --input-type=module -e '
|
|
948
|
-
import moduleFs from "fs";
|
|
949
|
-
(async function () {
|
|
950
|
-
function identity(val) {
|
|
951
|
-
|
|
952
|
-
// This function will return <val>.
|
|
953
|
-
|
|
954
|
-
return val;
|
|
955
|
-
}
|
|
956
|
-
function objectDeepCopyWithKeysSorted(obj) {
|
|
957
|
-
|
|
958
|
-
// this function will recursively deep-copy <obj> with keys sorted
|
|
959
|
-
|
|
960
|
-
let sorted;
|
|
961
|
-
if (typeof obj !== "object" || !obj) {
|
|
962
|
-
return obj;
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
// recursively deep-copy list with child-keys sorted
|
|
966
|
-
|
|
967
|
-
if (Array.isArray(obj)) {
|
|
968
|
-
return obj.map(objectDeepCopyWithKeysSorted);
|
|
969
|
-
}
|
|
970
|
-
|
|
971
|
-
// recursively deep-copy obj with keys sorted
|
|
972
|
-
|
|
973
|
-
sorted = {};
|
|
974
|
-
Object.keys(obj).sort().forEach(function (key) {
|
|
975
|
-
sorted[key] = objectDeepCopyWithKeysSorted(obj[key]);
|
|
976
|
-
});
|
|
977
|
-
return sorted;
|
|
978
|
-
}
|
|
979
|
-
console.error("shJsonNormalize - " + process.argv[1]);
|
|
980
|
-
moduleFs.promises.writeFile(
|
|
981
|
-
process.argv[1],
|
|
982
|
-
JSON.stringify(
|
|
983
|
-
objectDeepCopyWithKeysSorted(
|
|
984
|
-
JSON.parse(
|
|
985
|
-
identity(
|
|
986
|
-
await moduleFs.promises.readFile(
|
|
987
|
-
process.argv[1],
|
|
988
|
-
"utf8"
|
|
989
|
-
)
|
|
990
|
-
).replace((
|
|
991
|
-
/^\ufeff/
|
|
992
|
-
), "")
|
|
993
|
-
)
|
|
994
|
-
),
|
|
995
|
-
undefined,
|
|
996
|
-
4
|
|
997
|
-
) + "\n"
|
|
998
|
-
);
|
|
999
|
-
}());
|
|
1000
|
-
' "$@" # '
|
|
1001
|
-
)}
|
|
1002
|
-
|
|
1003
|
-
shRawLibFetch() {(set -e
|
|
1004
|
-
# this function will fetch raw-lib from $1
|
|
1005
|
-
node --input-type=module -e '
|
|
1006
|
-
import moduleChildProcess from "child_process";
|
|
1007
|
-
import moduleFs from "fs";
|
|
1008
|
-
import moduleHttps from "https";
|
|
1009
|
-
import modulePath from "path";
|
|
1010
|
-
// init debugInline
|
|
1011
|
-
(function () {
|
|
1012
|
-
let consoleError = console.error;
|
|
1013
|
-
globalThis.debugInline = globalThis.debugInline || function (...argList) {
|
|
1014
|
-
|
|
1015
|
-
// this function will both print <argList> to stderr and return <argList>[0]
|
|
1016
|
-
|
|
1017
|
-
consoleError("\n\ndebugInline");
|
|
1018
|
-
consoleError(...argList);
|
|
1019
|
-
consoleError("\n");
|
|
1020
|
-
return argList[0];
|
|
1021
|
-
};
|
|
1022
|
-
}());
|
|
1023
|
-
(async function () {
|
|
1024
|
-
let fetchList;
|
|
1025
|
-
let matchObj;
|
|
1026
|
-
let replaceList;
|
|
1027
|
-
let repoDict;
|
|
1028
|
-
function pipeToBuffer(res, dict, key) {
|
|
1029
|
-
|
|
1030
|
-
// This function will concat data from <res> to <dict>[<key>].
|
|
1031
|
-
|
|
1032
|
-
let data;
|
|
1033
|
-
data = [];
|
|
1034
|
-
res.on("data", function (chunk) {
|
|
1035
|
-
data.push(chunk);
|
|
1036
|
-
}).on("end", function () {
|
|
1037
|
-
dict[key] = Buffer.concat(data);
|
|
1038
|
-
});
|
|
1039
|
-
}
|
|
1040
|
-
// init matchObj
|
|
1041
|
-
matchObj = (
|
|
1042
|
-
/^\/\*jslint-disable\*\/\n\/\*\nshRawLibFetch\n(\{\n[\S\s]*?\n\})([\S\s]*?)\n\*\/\n/m
|
|
1043
|
-
).exec(await moduleFs.promises.readFile(process.argv[1], "utf8"));
|
|
1044
|
-
// JSON.parse match1 with comment
|
|
1045
|
-
fetchList = JSON.parse(matchObj[1]).fetchList;
|
|
1046
|
-
replaceList = JSON.parse(matchObj[1]).replaceList || [];
|
|
1047
|
-
// init repoDict, fetchList
|
|
1048
|
-
repoDict = {};
|
|
1049
|
-
fetchList.forEach(function (elem) {
|
|
1050
|
-
if (!elem.url) {
|
|
1051
|
-
return;
|
|
1052
|
-
}
|
|
1053
|
-
elem.prefix = elem.url.split("/").slice(0, 7).join("/");
|
|
1054
|
-
// fetch dateCommitted
|
|
1055
|
-
if (!repoDict.hasOwnProperty(elem.prefix)) {
|
|
1056
|
-
repoDict[elem.prefix] = true;
|
|
1057
|
-
moduleHttps.request(elem.prefix.replace(
|
|
1058
|
-
"/blob/",
|
|
1059
|
-
"/commits/"
|
|
1060
|
-
), function (res) {
|
|
1061
|
-
pipeToBuffer(res, elem, "dateCommitted");
|
|
1062
|
-
}).end();
|
|
1063
|
-
}
|
|
1064
|
-
// fetch file
|
|
1065
|
-
if (elem.node) {
|
|
1066
|
-
pipeToBuffer(moduleChildProcess.spawn("node", [
|
|
1067
|
-
"-e", elem.node
|
|
1068
|
-
], {
|
|
1069
|
-
stdio: [
|
|
1070
|
-
"ignore", "pipe", 2
|
|
1071
|
-
]
|
|
1072
|
-
}).stdout, elem, "data");
|
|
1073
|
-
return;
|
|
1074
|
-
}
|
|
1075
|
-
if (elem.sh) {
|
|
1076
|
-
pipeToBuffer(moduleChildProcess.spawn(elem.sh, {
|
|
1077
|
-
shell: true,
|
|
1078
|
-
stdio: [
|
|
1079
|
-
"ignore", "pipe", 2
|
|
1080
|
-
]
|
|
1081
|
-
}).stdout, elem, "data");
|
|
1082
|
-
return;
|
|
1083
|
-
}
|
|
1084
|
-
moduleHttps.get(elem.url2 || elem.url.replace(
|
|
1085
|
-
"https://github.com/",
|
|
1086
|
-
"https://raw.githubusercontent.com/"
|
|
1087
|
-
).replace("/blob/", "/"), function (res) {
|
|
1088
|
-
// http-redirect
|
|
1089
|
-
if (res.statusCode === 302) {
|
|
1090
|
-
moduleHttps.get(res.headers.location, function (res) {
|
|
1091
|
-
pipeToBuffer(res, elem, "data");
|
|
1092
|
-
});
|
|
1093
|
-
return;
|
|
1094
|
-
}
|
|
1095
|
-
pipeToBuffer(res, elem, "data");
|
|
1096
|
-
});
|
|
1097
|
-
});
|
|
1098
|
-
// parse fetched data
|
|
1099
|
-
process.on("exit", function () {
|
|
1100
|
-
let header;
|
|
1101
|
-
let result;
|
|
1102
|
-
let result0;
|
|
1103
|
-
result = "";
|
|
1104
|
-
fetchList.forEach(function (elem, ii, list) {
|
|
1105
|
-
let prefix;
|
|
1106
|
-
if (!elem.url) {
|
|
1107
|
-
return;
|
|
1108
|
-
}
|
|
1109
|
-
// init prefix
|
|
1110
|
-
prefix = "exports_" + modulePath.dirname(elem.url).replace(
|
|
1111
|
-
"https://github.com/",
|
|
1112
|
-
""
|
|
1113
|
-
).replace((
|
|
1114
|
-
/\/blob\/[^\/]*/
|
|
1115
|
-
), "/").replace((
|
|
1116
|
-
/\W/g
|
|
1117
|
-
), "_").replace((
|
|
1118
|
-
/(_)_+|_+$/g
|
|
1119
|
-
), "$1");
|
|
1120
|
-
list[ii].exports = prefix + "_" + modulePath.basename(
|
|
1121
|
-
elem.url
|
|
1122
|
-
).replace((
|
|
1123
|
-
/\.js$/
|
|
1124
|
-
), "").replace((
|
|
1125
|
-
/\W/g
|
|
1126
|
-
), "_");
|
|
1127
|
-
if (elem.dataUriType) {
|
|
1128
|
-
return;
|
|
1129
|
-
}
|
|
1130
|
-
if (elem.dateCommitted) {
|
|
1131
|
-
result += (
|
|
1132
|
-
"\n\n\n/*\n" +
|
|
1133
|
-
"repo " + elem.prefix.replace("/blob/", "/tree/") + "\n" +
|
|
1134
|
-
"committed " + (
|
|
1135
|
-
/\b\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ\b/
|
|
1136
|
-
).exec(elem.dateCommitted.toString())[0] + "\n" +
|
|
1137
|
-
"*/"
|
|
1138
|
-
);
|
|
1139
|
-
}
|
|
1140
|
-
// comment /*...*/
|
|
1141
|
-
if (elem.comment) {
|
|
1142
|
-
elem.data = "/*\n" + elem.data.toString().trim().replace((
|
|
1143
|
-
/\/\*/g
|
|
1144
|
-
), "/\\*").replace((
|
|
1145
|
-
/\*\//g
|
|
1146
|
-
), "*\\/") + "\n*/";
|
|
1147
|
-
}
|
|
1148
|
-
// mangle module.exports
|
|
1149
|
-
result += (
|
|
1150
|
-
"\n\n\n/*\nfile " + elem.url + "\n*/\n" +
|
|
1151
|
-
elem.data.toString().trim()
|
|
1152
|
-
);
|
|
1153
|
-
});
|
|
1154
|
-
result = (
|
|
1155
|
-
"\n" + result.trim() +
|
|
1156
|
-
"\n\n\n/*\nfile none\n*/\n/*jslint-enable*/\n"
|
|
1157
|
-
);
|
|
1158
|
-
// comment #!
|
|
1159
|
-
result = result.replace((
|
|
1160
|
-
/^#!/gm
|
|
1161
|
-
), "// $&");
|
|
1162
|
-
// normalize newline
|
|
1163
|
-
result = result.replace((
|
|
1164
|
-
/\r\n|\r/g
|
|
1165
|
-
), "\n");
|
|
1166
|
-
// remove trailing-whitespace
|
|
1167
|
-
result = result.replace((
|
|
1168
|
-
/[\t\u0020]+$/gm
|
|
1169
|
-
), "");
|
|
1170
|
-
// remove leading-newline before ket
|
|
1171
|
-
result = result.replace((
|
|
1172
|
-
/\n+?(\n\u0020*?\})/g
|
|
1173
|
-
), "$1");
|
|
1174
|
-
// eslint - no-multiple-empty-lines
|
|
1175
|
-
// https://github.com/eslint/eslint/blob/v7.2.0/docs/rules/no-multiple-empty-lines.md //jslint-quiet
|
|
1176
|
-
result = result.replace((
|
|
1177
|
-
/\n{4,}/g
|
|
1178
|
-
), "\n\n\n");
|
|
1179
|
-
// replace from replaceList
|
|
1180
|
-
replaceList.forEach(function ({
|
|
1181
|
-
aa,
|
|
1182
|
-
bb,
|
|
1183
|
-
flags
|
|
1184
|
-
}) {
|
|
1185
|
-
result0 = result;
|
|
1186
|
-
result = result.replace(new RegExp(aa, flags), bb);
|
|
1187
|
-
if (result0 === result) {
|
|
1188
|
-
throw new Error(
|
|
1189
|
-
"shRawLibFetch - cannot find-and-replace snippet " +
|
|
1190
|
-
JSON.stringify(aa)
|
|
1191
|
-
);
|
|
1192
|
-
}
|
|
1193
|
-
});
|
|
1194
|
-
// init header
|
|
1195
|
-
header = (
|
|
1196
|
-
matchObj.input.slice(0, matchObj.index) +
|
|
1197
|
-
"/*jslint-disable*/\n/*\nshRawLibFetch\n" +
|
|
1198
|
-
JSON.stringify(JSON.parse(matchObj[1]), undefined, 4) + "\n" +
|
|
1199
|
-
matchObj[2].split("\n\n").filter(function (elem) {
|
|
1200
|
-
return elem.trim();
|
|
1201
|
-
}).map(function (elem) {
|
|
1202
|
-
return elem.trim().replace((
|
|
1203
|
-
/\*\//g
|
|
1204
|
-
), "*\\\\/").replace((
|
|
1205
|
-
/\/\*/g
|
|
1206
|
-
), "/\\\\*") + "\n";
|
|
1207
|
-
}).sort().join("\n") + "*/\n\n"
|
|
1208
|
-
);
|
|
1209
|
-
// replace from header-diff
|
|
1210
|
-
header.replace((
|
|
1211
|
-
/((?:^-.*?\n)+?)((?:^\+.*?\n)+)/gm
|
|
1212
|
-
), function (ignore, aa, bb) {
|
|
1213
|
-
aa = "\n" + aa.replace((
|
|
1214
|
-
/^-/gm
|
|
1215
|
-
), "").replace((
|
|
1216
|
-
/\*\\\\\//g
|
|
1217
|
-
), "*/").replace((
|
|
1218
|
-
/\/\\\\\*/g
|
|
1219
|
-
), "/*");
|
|
1220
|
-
bb = "\n" + bb.replace((
|
|
1221
|
-
/^\+/gm
|
|
1222
|
-
), "").replace((
|
|
1223
|
-
/\*\\\\\//g
|
|
1224
|
-
), "*/").replace((
|
|
1225
|
-
/\/\\\\\*/g
|
|
1226
|
-
), "/*");
|
|
1227
|
-
result0 = result;
|
|
1228
|
-
// disable $-escape in replacement-string
|
|
1229
|
-
result = result.replace(aa, function () {
|
|
1230
|
-
return bb;
|
|
1231
|
-
});
|
|
1232
|
-
if (result0 === result) {
|
|
1233
|
-
throw new Error(
|
|
1234
|
-
"shRawLibFetch - cannot find-and-replace snippet " +
|
|
1235
|
-
JSON.stringify(aa)
|
|
1236
|
-
);
|
|
1237
|
-
}
|
|
1238
|
-
return "";
|
|
1239
|
-
});
|
|
1240
|
-
// inline dataUri
|
|
1241
|
-
fetchList.forEach(function ({
|
|
1242
|
-
data,
|
|
1243
|
-
dataUriType,
|
|
1244
|
-
exports
|
|
1245
|
-
}) {
|
|
1246
|
-
if (!dataUriType) {
|
|
1247
|
-
return;
|
|
1248
|
-
}
|
|
1249
|
-
data = (
|
|
1250
|
-
"data:" + dataUriType + ";base64," +
|
|
1251
|
-
data.toString("base64")
|
|
1252
|
-
);
|
|
1253
|
-
result0 = result;
|
|
1254
|
-
result = result.replace(
|
|
1255
|
-
new RegExp("^" + exports + "$", "gm"),
|
|
1256
|
-
// disable $-escape in replacement-string
|
|
1257
|
-
function () {
|
|
1258
|
-
return data;
|
|
1259
|
-
}
|
|
1260
|
-
);
|
|
1261
|
-
if (result0 === result) {
|
|
1262
|
-
throw new Error(
|
|
1263
|
-
"shRawLibFetch - cannot find-and-replace snippet " +
|
|
1264
|
-
JSON.stringify(exports)
|
|
1265
|
-
);
|
|
1266
|
-
}
|
|
1267
|
-
});
|
|
1268
|
-
// init footer
|
|
1269
|
-
result = header + result;
|
|
1270
|
-
matchObj.input.replace((
|
|
1271
|
-
/\n\/\*\nfile\u0020none\n\*\/\n\/\*jslint-enable\*\/\n([\S\s]+)/
|
|
1272
|
-
), function (ignore, match1) {
|
|
1273
|
-
result += "\n\n" + match1.trim() + "\n";
|
|
1274
|
-
});
|
|
1275
|
-
// write to file
|
|
1276
|
-
moduleFs.writeFileSync(process.argv[1], result); //jslint-quiet
|
|
1277
|
-
});
|
|
1278
|
-
}());
|
|
1279
|
-
' "$@" # '
|
|
1280
|
-
git diff 2>/dev/null || true
|
|
1281
|
-
)}
|
|
1282
|
-
|
|
1283
|
-
shRunWithCoverage() {(set -e
|
|
1284
|
-
# this function will run nodejs command $@ with v8-coverage
|
|
1285
|
-
# and create coverage-report .build/coverage/index.html
|
|
1286
|
-
local EXIT_CODE
|
|
1287
|
-
EXIT_CODE=0
|
|
1288
|
-
export DIR_COVERAGE=.build/coverage/
|
|
1289
|
-
rm -rf "$DIR_COVERAGE"
|
|
1290
|
-
(set -e
|
|
1291
|
-
export NODE_V8_COVERAGE="$DIR_COVERAGE"
|
|
1292
|
-
"$@"
|
|
1293
|
-
) || EXIT_CODE="$?"
|
|
1294
|
-
if [ "$EXIT_CODE" = 0 ]
|
|
1295
|
-
then
|
|
1296
|
-
node --input-type=module -e '
|
|
1297
|
-
import moduleFs from "fs";
|
|
1298
|
-
import modulePath from "path";
|
|
1299
|
-
// init debugInline
|
|
1300
|
-
(function () {
|
|
1301
|
-
let consoleError = console.error;
|
|
1302
|
-
globalThis.debugInline = globalThis.debugInline || function (...argList) {
|
|
1303
|
-
|
|
1304
|
-
// this function will both print <argList> to stderr and return <argList>[0]
|
|
1305
|
-
|
|
1306
|
-
consoleError("\n\ndebugInline");
|
|
1307
|
-
consoleError(...argList);
|
|
1308
|
-
consoleError("\n");
|
|
1309
|
-
return argList[0];
|
|
1310
|
-
};
|
|
1311
|
-
}());
|
|
1312
|
-
(async function () {
|
|
1313
|
-
let DIR_COVERAGE = process.env.DIR_COVERAGE;
|
|
1314
|
-
let cwd;
|
|
1315
|
-
let data;
|
|
1316
|
-
let fileDict;
|
|
1317
|
-
async function htmlRender({
|
|
1318
|
-
fileList,
|
|
1319
|
-
lineList,
|
|
1320
|
-
pathname
|
|
1321
|
-
}) {
|
|
1322
|
-
let html;
|
|
1323
|
-
let padLines;
|
|
1324
|
-
let padPathname;
|
|
1325
|
-
let txt;
|
|
1326
|
-
let txtBorder;
|
|
1327
|
-
function stringHtmlSafe(str) {
|
|
1328
|
-
/*
|
|
1329
|
-
* this function will make <str> html-safe
|
|
1330
|
-
* https://stackoverflow.com/questions/7381974/which-characters-need-to-be-escaped-on-html //jslint-quiet
|
|
1331
|
-
*/
|
|
1332
|
-
return str.replace((
|
|
1333
|
-
/&/gu
|
|
1334
|
-
), "&").replace((
|
|
1335
|
-
/"/gu
|
|
1336
|
-
), """).replace((
|
|
1337
|
-
/\u0027/gu
|
|
1338
|
-
), "'").replace((
|
|
1339
|
-
/</gu
|
|
1340
|
-
), "<").replace((
|
|
1341
|
-
/>/gu
|
|
1342
|
-
), ">").replace((
|
|
1343
|
-
/&(amp;|apos;|gt;|lt;|quot;)/igu
|
|
1344
|
-
), "&$1");
|
|
1345
|
-
}
|
|
1346
|
-
html = "";
|
|
1347
|
-
html += `<!DOCTYPE html>
|
|
1348
|
-
<html lang="en">
|
|
1349
|
-
<head>
|
|
1350
|
-
<title>coverage-report</title>
|
|
1351
|
-
<style>
|
|
1352
|
-
/* csslint ignore:start */
|
|
1353
|
-
* {
|
|
1354
|
-
box-sizing: border-box;
|
|
1355
|
-
font-family: consolas, menlo, monospace;
|
|
1356
|
-
}
|
|
1357
|
-
/* csslint ignore:end */
|
|
1358
|
-
body {
|
|
1359
|
-
margin: 0;
|
|
1360
|
-
}
|
|
1361
|
-
.coverage pre {
|
|
1362
|
-
margin: 5px 0;
|
|
1363
|
-
}
|
|
1364
|
-
.coverage table {
|
|
1365
|
-
border-collapse: collapse;
|
|
1366
|
-
}
|
|
1367
|
-
.coverage td,
|
|
1368
|
-
.coverage th {
|
|
1369
|
-
border: 1px solid #777;
|
|
1370
|
-
margin: 0;
|
|
1371
|
-
padding: 5px;
|
|
1372
|
-
}
|
|
1373
|
-
.coverage td span {
|
|
1374
|
-
display: inline-block;
|
|
1375
|
-
width: 100%;
|
|
1376
|
-
}
|
|
1377
|
-
.coverage .content {
|
|
1378
|
-
padding: 0 5px;
|
|
1379
|
-
}
|
|
1380
|
-
.coverage .content a {
|
|
1381
|
-
text-decoration: none;
|
|
1382
|
-
}
|
|
1383
|
-
.coverage .count {
|
|
1384
|
-
margin: 0 5px;
|
|
1385
|
-
padding: 0 5px;
|
|
1386
|
-
}
|
|
1387
|
-
.coverage .footer,
|
|
1388
|
-
.coverage .header {
|
|
1389
|
-
padding: 20px;
|
|
1390
|
-
}
|
|
1391
|
-
.coverage .percentbar {
|
|
1392
|
-
height: 12px;
|
|
1393
|
-
margin: 2px 0;
|
|
1394
|
-
min-width: 200px;
|
|
1395
|
-
position: relative;
|
|
1396
|
-
width: 100%;
|
|
1397
|
-
}
|
|
1398
|
-
.coverage .percentbar div {
|
|
1399
|
-
height: 100%;
|
|
1400
|
-
position: absolute;
|
|
1401
|
-
}
|
|
1402
|
-
.coverage .title {
|
|
1403
|
-
font-size: large;
|
|
1404
|
-
font-weight: bold;
|
|
1405
|
-
margin-bottom: 10px;
|
|
1406
|
-
}
|
|
1407
|
-
|
|
1408
|
-
.coverage td,
|
|
1409
|
-
.coverage th {
|
|
1410
|
-
background: #fff;
|
|
1411
|
-
}
|
|
1412
|
-
.coverage .count {
|
|
1413
|
-
background: #9d9;
|
|
1414
|
-
color: #777;
|
|
1415
|
-
}
|
|
1416
|
-
.coverage .coverageHigh{
|
|
1417
|
-
background: #9d9;
|
|
1418
|
-
}
|
|
1419
|
-
.coverage .coverageLow{
|
|
1420
|
-
background: #ebb;
|
|
1421
|
-
}
|
|
1422
|
-
.coverage .coverageMedium{
|
|
1423
|
-
background: #fd7;
|
|
1424
|
-
}
|
|
1425
|
-
.coverage .header {
|
|
1426
|
-
background: #ddd;
|
|
1427
|
-
}
|
|
1428
|
-
.coverage .lineno {
|
|
1429
|
-
background: #ddd;
|
|
1430
|
-
}
|
|
1431
|
-
.coverage .percentbar {
|
|
1432
|
-
background: #999;
|
|
1433
|
-
}
|
|
1434
|
-
.coverage .percentbar div {
|
|
1435
|
-
background: #666;
|
|
1436
|
-
}
|
|
1437
|
-
.coverage .uncovered {
|
|
1438
|
-
background: #dbb;
|
|
1439
|
-
}
|
|
1440
|
-
|
|
1441
|
-
.coverage pre:hover span,
|
|
1442
|
-
.coverage tr:hover td {
|
|
1443
|
-
background: #7d7;
|
|
1444
|
-
}
|
|
1445
|
-
.coverage pre:hover span.uncovered,
|
|
1446
|
-
.coverage tr:hover td.coverageLow {
|
|
1447
|
-
background: #d99;
|
|
1448
|
-
}
|
|
1449
|
-
</style>
|
|
1450
|
-
</head>
|
|
1451
|
-
<body class="coverage">
|
|
1452
|
-
<div class="header">
|
|
1453
|
-
<div class="title">coverage-report</div>
|
|
1454
|
-
<table>
|
|
1455
|
-
<thead>
|
|
1456
|
-
<tr>
|
|
1457
|
-
<th>files covered</th>
|
|
1458
|
-
<th>lines</th>
|
|
1459
|
-
</tr>
|
|
1460
|
-
</thead>
|
|
1461
|
-
<tbody>`;
|
|
1462
|
-
if (!lineList) {
|
|
1463
|
-
padLines = String("100.00 %").length;
|
|
1464
|
-
padPathname = 32;
|
|
1465
|
-
fileList.unshift({
|
|
1466
|
-
linesCovered: 0,
|
|
1467
|
-
linesTotal: 0,
|
|
1468
|
-
pathname: "./"
|
|
1469
|
-
});
|
|
1470
|
-
fileList.slice(1).forEach(function ({
|
|
1471
|
-
linesCovered,
|
|
1472
|
-
linesTotal,
|
|
1473
|
-
pathname
|
|
1474
|
-
}) {
|
|
1475
|
-
fileList[0].linesCovered += linesCovered;
|
|
1476
|
-
fileList[0].linesTotal += linesTotal;
|
|
1477
|
-
padPathname = Math.max(padPathname, pathname.length + 2);
|
|
1478
|
-
padLines = Math.max(
|
|
1479
|
-
padLines,
|
|
1480
|
-
String(linesCovered + " / " + linesTotal).length
|
|
1481
|
-
);
|
|
1482
|
-
});
|
|
1483
|
-
}
|
|
1484
|
-
txtBorder = (
|
|
1485
|
-
"+" + "-".repeat(padPathname + 2) + "+"
|
|
1486
|
-
+ "-".repeat(padLines + 2) + "+\n"
|
|
1487
|
-
);
|
|
1488
|
-
txt = "";
|
|
1489
|
-
txt += "coverage-report\n";
|
|
1490
|
-
txt += txtBorder;
|
|
1491
|
-
txt += (
|
|
1492
|
-
"| " + String("files covered").padEnd(padPathname, " ") + " | "
|
|
1493
|
-
+ String("lines").padStart(padLines, " ") + " |\n"
|
|
1494
|
-
);
|
|
1495
|
-
txt += txtBorder;
|
|
1496
|
-
fileList.forEach(function ({
|
|
1497
|
-
linesCovered,
|
|
1498
|
-
linesTotal,
|
|
1499
|
-
pathname
|
|
1500
|
-
}, ii) {
|
|
1501
|
-
let coverageLevel;
|
|
1502
|
-
let coveragePct;
|
|
1503
|
-
let fill;
|
|
1504
|
-
let str1;
|
|
1505
|
-
let str2;
|
|
1506
|
-
let xx1;
|
|
1507
|
-
let xx2;
|
|
1508
|
-
coveragePct = Math.floor(10000 * linesCovered / linesTotal || 0);
|
|
1509
|
-
coverageLevel = (
|
|
1510
|
-
coveragePct >= 8000
|
|
1511
|
-
? "coverageHigh"
|
|
1512
|
-
: coveragePct >= 5000
|
|
1513
|
-
? "coverageMedium"
|
|
1514
|
-
: "coverageLow"
|
|
1515
|
-
);
|
|
1516
|
-
coveragePct = String(coveragePct).replace((
|
|
1517
|
-
/..$/m
|
|
1518
|
-
), ".$&");
|
|
1519
|
-
if (!lineList && ii === 0) {
|
|
1520
|
-
fill = (
|
|
1521
|
-
// red
|
|
1522
|
-
"#" + Math.round(
|
|
1523
|
-
(100 - Number(coveragePct)) * 2.21
|
|
1524
|
-
).toString(16).padStart(2, "0")
|
|
1525
|
-
// green
|
|
1526
|
-
+ Math.round(
|
|
1527
|
-
Number(coveragePct) * 2.21
|
|
1528
|
-
).toString(16).padStart(2, "0")
|
|
1529
|
-
+ // blue
|
|
1530
|
-
"00"
|
|
1531
|
-
);
|
|
1532
|
-
str1 = "coverage";
|
|
1533
|
-
str2 = coveragePct + " %";
|
|
1534
|
-
xx1 = 6 * str1.length + 20;
|
|
1535
|
-
xx2 = 6 * str2.length + 20;
|
|
1536
|
-
// fs - write coverage-badge.svg
|
|
1537
|
-
moduleFs.promises.writeFile((
|
|
1538
|
-
DIR_COVERAGE + "/coverage-badge.svg"
|
|
1539
|
-
), String(`
|
|
1540
|
-
<svg height="20" width="${xx1 + xx2}" xmlns="http://www.w3.org/2000/svg">
|
|
1541
|
-
<rect fill="#555" height="20" width="${xx1 + xx2}"/>
|
|
1542
|
-
<rect fill="${fill}" height="20" width="${xx2}" x="${xx1}"/>
|
|
1543
|
-
<g
|
|
1544
|
-
fill="#fff"
|
|
1545
|
-
font-family="dejavu sans, verdana, geneva, sans-serif"
|
|
1546
|
-
font-size="11"
|
|
1547
|
-
font-weight="bold"
|
|
1548
|
-
text-anchor="middle"
|
|
1549
|
-
>
|
|
1550
|
-
<text x="${0.5 * xx1}" y="14">${str1}</text>
|
|
1551
|
-
<text x="${xx1 + 0.5 * xx2}" y="14">${str2}</text>
|
|
1552
|
-
</g>
|
|
1553
|
-
</svg>
|
|
1554
|
-
`).trim() + "\n");
|
|
1555
|
-
pathname = "";
|
|
1556
|
-
}
|
|
1557
|
-
txt += (
|
|
1558
|
-
"| "
|
|
1559
|
-
+ String("./" + pathname).padEnd(padPathname, " ") + " | "
|
|
1560
|
-
+ String(coveragePct + " %").padStart(padLines, " ") + " |\n"
|
|
1561
|
-
);
|
|
1562
|
-
txt += (
|
|
1563
|
-
"| " + "*".repeat(
|
|
1564
|
-
Math.round(0.01 * coveragePct * padPathname)
|
|
1565
|
-
).padEnd(padPathname, "_") + " | "
|
|
1566
|
-
+ String(
|
|
1567
|
-
linesCovered + " / " + linesTotal
|
|
1568
|
-
).padStart(padLines, " ") + " |\n"
|
|
1569
|
-
);
|
|
1570
|
-
txt += txtBorder;
|
|
1571
|
-
pathname = stringHtmlSafe(pathname);
|
|
1572
|
-
html += `<tr>
|
|
1573
|
-
<td class="${coverageLevel}">
|
|
1574
|
-
${(
|
|
1575
|
-
lineList
|
|
1576
|
-
? (
|
|
1577
|
-
"<a href=\"index.html\">./ </a>"
|
|
1578
|
-
+ pathname + "<br>"
|
|
1579
|
-
)
|
|
1580
|
-
: (
|
|
1581
|
-
"<a href=\"" + (pathname || "index") + ".html\">./ "
|
|
1582
|
-
+ pathname + "</a><br>"
|
|
1583
|
-
)
|
|
1584
|
-
)}
|
|
1585
|
-
<div class="percentbar">
|
|
1586
|
-
<div style="width: ${coveragePct}%;"></div>
|
|
1587
|
-
</div>
|
|
1588
|
-
</td>
|
|
1589
|
-
<td style="text-align: right;">
|
|
1590
|
-
${coveragePct} %<br>
|
|
1591
|
-
${linesCovered} / ${linesTotal}
|
|
1592
|
-
</td>
|
|
1593
|
-
</tr>`;
|
|
1594
|
-
});
|
|
1595
|
-
if (lineList) {
|
|
1596
|
-
html += `</tbody>
|
|
1597
|
-
</table>
|
|
1598
|
-
</div>
|
|
1599
|
-
<div class="content">
|
|
1600
|
-
`;
|
|
1601
|
-
lineList.forEach(function ({
|
|
1602
|
-
count,
|
|
1603
|
-
holeList,
|
|
1604
|
-
line,
|
|
1605
|
-
startOffset
|
|
1606
|
-
}, ii) {
|
|
1607
|
-
let chunk;
|
|
1608
|
-
let inHole;
|
|
1609
|
-
let lineHtml;
|
|
1610
|
-
let lineId;
|
|
1611
|
-
lineHtml = "";
|
|
1612
|
-
lineId = "line_" + (ii + 1);
|
|
1613
|
-
switch (count) {
|
|
1614
|
-
case -1:
|
|
1615
|
-
case 0:
|
|
1616
|
-
if (holeList.length === 0) {
|
|
1617
|
-
lineHtml += "</span>";
|
|
1618
|
-
lineHtml += "<span class=\"uncovered\">";
|
|
1619
|
-
lineHtml += stringHtmlSafe(line);
|
|
1620
|
-
break;
|
|
1621
|
-
}
|
|
1622
|
-
line = line.split("").map(function (chr) {
|
|
1623
|
-
return {
|
|
1624
|
-
chr,
|
|
1625
|
-
isHole: undefined
|
|
1626
|
-
};
|
|
1627
|
-
});
|
|
1628
|
-
holeList.forEach(function ([
|
|
1629
|
-
aa, bb
|
|
1630
|
-
]) {
|
|
1631
|
-
aa = Math.max(aa - startOffset, 0);
|
|
1632
|
-
bb = Math.min(bb - startOffset, line.length);
|
|
1633
|
-
while (aa < bb) {
|
|
1634
|
-
line[aa].isHole = true;
|
|
1635
|
-
aa += 1;
|
|
1636
|
-
}
|
|
1637
|
-
});
|
|
1638
|
-
chunk = "";
|
|
1639
|
-
line.forEach(function ({
|
|
1640
|
-
chr,
|
|
1641
|
-
isHole
|
|
1642
|
-
}) {
|
|
1643
|
-
if (inHole !== isHole) {
|
|
1644
|
-
lineHtml += stringHtmlSafe(chunk);
|
|
1645
|
-
lineHtml += (
|
|
1646
|
-
isHole
|
|
1647
|
-
? "</span><span class=\"uncovered\">"
|
|
1648
|
-
: "</span><span>"
|
|
1649
|
-
);
|
|
1650
|
-
chunk = "";
|
|
1651
|
-
inHole = isHole;
|
|
1652
|
-
}
|
|
1653
|
-
chunk += chr;
|
|
1654
|
-
});
|
|
1655
|
-
lineHtml += stringHtmlSafe(chunk);
|
|
1656
|
-
break;
|
|
1657
|
-
default:
|
|
1658
|
-
lineHtml += stringHtmlSafe(line);
|
|
1659
|
-
}
|
|
1660
|
-
html += String(`
|
|
1661
|
-
<pre>
|
|
1662
|
-
<span class="lineno">
|
|
1663
|
-
<a href="#${lineId}" id="${lineId}">${String(ii + 1).padStart(5, " ")}.</a>
|
|
1664
|
-
</span>
|
|
1665
|
-
<span class="count
|
|
1666
|
-
${(
|
|
1667
|
-
count <= 0
|
|
1668
|
-
? "uncovered"
|
|
1669
|
-
: ""
|
|
1670
|
-
)}"
|
|
1671
|
-
>
|
|
1672
|
-
${String(count).padStart(7, " ")}
|
|
1673
|
-
</span>
|
|
1674
|
-
<span>${lineHtml}</span>
|
|
1675
|
-
</pre>
|
|
1676
|
-
`).replace((
|
|
1677
|
-
/\n/g
|
|
1678
|
-
), "").trim() + "\n";
|
|
1679
|
-
});
|
|
1680
|
-
}
|
|
1681
|
-
html += `
|
|
1682
|
-
</div>
|
|
1683
|
-
<div class="coverageFooter">
|
|
1684
|
-
</div>
|
|
1685
|
-
</body>
|
|
1686
|
-
</html>`;
|
|
1687
|
-
html += "\n";
|
|
1688
|
-
await moduleFs.promises.mkdir(modulePath.dirname(pathname), {
|
|
1689
|
-
recursive: true
|
|
1690
|
-
});
|
|
1691
|
-
// fs - write *.html
|
|
1692
|
-
moduleFs.promises.writeFile(pathname + ".html", html);
|
|
1693
|
-
if (lineList) {
|
|
1694
|
-
return;
|
|
1695
|
-
}
|
|
1696
|
-
// fs - write coverage.txt
|
|
1697
|
-
console.error("\n" + txt);
|
|
1698
|
-
moduleFs.promises.writeFile((
|
|
1699
|
-
DIR_COVERAGE + "/coverage-report.txt"
|
|
1700
|
-
), txt);
|
|
1701
|
-
}
|
|
1702
|
-
data = await moduleFs.promises.readdir(DIR_COVERAGE);
|
|
1703
|
-
await Promise.all(data.map(async function (file) {
|
|
1704
|
-
if ((
|
|
1705
|
-
/^coverage-.*?\.json$/
|
|
1706
|
-
).test(file)) {
|
|
1707
|
-
data = await moduleFs.promises.readFile((
|
|
1708
|
-
DIR_COVERAGE + file
|
|
1709
|
-
), "utf8");
|
|
1710
|
-
// fs - rename to coverage-v8.json
|
|
1711
|
-
moduleFs.promises.rename(
|
|
1712
|
-
DIR_COVERAGE + file,
|
|
1713
|
-
DIR_COVERAGE + "coverage-v8.json"
|
|
1714
|
-
);
|
|
1715
|
-
}
|
|
1716
|
-
}));
|
|
1717
|
-
fileDict = {};
|
|
1718
|
-
cwd = process.cwd().replace((
|
|
1719
|
-
/\\/g
|
|
1720
|
-
), "/") + "/";
|
|
1721
|
-
await Promise.all(JSON.parse(data).result.map(async function ({
|
|
1722
|
-
functions,
|
|
1723
|
-
url
|
|
1724
|
-
}) {
|
|
1725
|
-
let lineList;
|
|
1726
|
-
let linesCovered;
|
|
1727
|
-
let linesTotal;
|
|
1728
|
-
let pathname;
|
|
1729
|
-
let src;
|
|
1730
|
-
if (!url.startsWith("file:///")) {
|
|
1731
|
-
return;
|
|
1732
|
-
}
|
|
1733
|
-
pathname = url.replace((
|
|
1734
|
-
process.platform === "win32"
|
|
1735
|
-
? "file:///"
|
|
1736
|
-
: "file://"
|
|
1737
|
-
), "").replace((
|
|
1738
|
-
/\\\\/g
|
|
1739
|
-
), "/");
|
|
1740
|
-
if (
|
|
1741
|
-
!pathname.startsWith(cwd)
|
|
1742
|
-
|| pathname.startsWith(cwd + "[")
|
|
1743
|
-
|| (
|
|
1744
|
-
process.env.npm_config_mode_coverage !== "all"
|
|
1745
|
-
&& pathname.indexOf("/node_modules/") >= 0
|
|
1746
|
-
)
|
|
1747
|
-
) {
|
|
1748
|
-
return;
|
|
1749
|
-
}
|
|
1750
|
-
pathname = pathname.replace(cwd, "");
|
|
1751
|
-
src = await moduleFs.promises.readFile(pathname, "utf8");
|
|
1752
|
-
lineList = [{}];
|
|
1753
|
-
src.replace((
|
|
1754
|
-
/^.*$/gm
|
|
1755
|
-
), function (line, startOffset) {
|
|
1756
|
-
lineList[lineList.length - 1].endOffset = startOffset - 1;
|
|
1757
|
-
lineList.push({
|
|
1758
|
-
count: -1,
|
|
1759
|
-
endOffset: 0,
|
|
1760
|
-
holeList: [],
|
|
1761
|
-
line,
|
|
1762
|
-
startOffset
|
|
1763
|
-
});
|
|
1764
|
-
return "";
|
|
1765
|
-
});
|
|
1766
|
-
lineList.shift();
|
|
1767
|
-
lineList[lineList.length - 1].endOffset = src.length;
|
|
1768
|
-
functions.reverse().forEach(function ({
|
|
1769
|
-
ranges
|
|
1770
|
-
}) {
|
|
1771
|
-
ranges.reverse().forEach(function ({
|
|
1772
|
-
count,
|
|
1773
|
-
endOffset,
|
|
1774
|
-
startOffset
|
|
1775
|
-
}, ii, list) {
|
|
1776
|
-
lineList.forEach(function (elem) {
|
|
1777
|
-
if (!(
|
|
1778
|
-
(
|
|
1779
|
-
elem.startOffset <= startOffset
|
|
1780
|
-
&& startOffset <= elem.endOffset
|
|
1781
|
-
) || (
|
|
1782
|
-
elem.startOffset <= endOffset
|
|
1783
|
-
&& endOffset <= elem.endOffset
|
|
1784
|
-
) || (
|
|
1785
|
-
startOffset <= elem.startOffset
|
|
1786
|
-
&& elem.endOffset <= endOffset
|
|
1787
|
-
)
|
|
1788
|
-
)) {
|
|
1789
|
-
return;
|
|
1790
|
-
}
|
|
1791
|
-
// handle root-range
|
|
1792
|
-
if (ii + 1 === list.length) {
|
|
1793
|
-
if (elem.count === -1) {
|
|
1794
|
-
elem.count = count;
|
|
1795
|
-
}
|
|
1796
|
-
return;
|
|
1797
|
-
}
|
|
1798
|
-
// handle non-root-range
|
|
1799
|
-
if (elem.count !== 0) {
|
|
1800
|
-
elem.count = Math.max(count, elem.count);
|
|
1801
|
-
}
|
|
1802
|
-
if (count === 0) {
|
|
1803
|
-
elem.count = 0;
|
|
1804
|
-
elem.holeList.push([
|
|
1805
|
-
startOffset, endOffset
|
|
1806
|
-
]);
|
|
1807
|
-
}
|
|
1808
|
-
});
|
|
1809
|
-
});
|
|
1810
|
-
});
|
|
1811
|
-
linesTotal = lineList.length;
|
|
1812
|
-
linesCovered = lineList.filter(function ({
|
|
1813
|
-
count
|
|
1814
|
-
}) {
|
|
1815
|
-
return count > 0;
|
|
1816
|
-
}).length;
|
|
1817
|
-
await moduleFs.promises.mkdir((
|
|
1818
|
-
modulePath.dirname(DIR_COVERAGE + pathname)
|
|
1819
|
-
), {
|
|
1820
|
-
recursive: true
|
|
1821
|
-
});
|
|
1822
|
-
await htmlRender({
|
|
1823
|
-
fileList: [
|
|
1824
|
-
{
|
|
1825
|
-
linesCovered,
|
|
1826
|
-
linesTotal,
|
|
1827
|
-
pathname
|
|
1828
|
-
}
|
|
1829
|
-
],
|
|
1830
|
-
lineList,
|
|
1831
|
-
pathname: DIR_COVERAGE + pathname
|
|
1832
|
-
});
|
|
1833
|
-
fileDict[pathname] = {
|
|
1834
|
-
lineList,
|
|
1835
|
-
linesCovered,
|
|
1836
|
-
linesTotal,
|
|
1837
|
-
pathname,
|
|
1838
|
-
src
|
|
1839
|
-
};
|
|
1840
|
-
}));
|
|
1841
|
-
await htmlRender({
|
|
1842
|
-
fileList: Object.keys(fileDict).sort().map(function (pathname) {
|
|
1843
|
-
return fileDict[pathname];
|
|
1844
|
-
}),
|
|
1845
|
-
pathname: DIR_COVERAGE + "index"
|
|
1846
|
-
});
|
|
1847
|
-
}());
|
|
1848
|
-
' # "'
|
|
1849
|
-
find "$DIR_COVERAGE"
|
|
1850
|
-
fi
|
|
1851
|
-
printf "shRunWithCoverage - EXIT_CODE=$EXIT_CODE\n" 1>&2
|
|
1852
|
-
return "$EXIT_CODE"
|
|
1853
|
-
)}
|
|
1854
|
-
|
|
1855
|
-
shRunWithScreenshotTxt() {(set -e
|
|
1856
|
-
# this function will run cmd $@ and screenshot text-output
|
|
1857
|
-
# https://www.cnx-software.com/2011/09/22/how-to-convert-a-command-line-result-into-an-image-in-linux/
|
|
1858
|
-
local EXIT_CODE
|
|
1859
|
-
EXIT_CODE=0
|
|
1860
|
-
export SCREENSHOT_SVG="$1"
|
|
1861
|
-
shift
|
|
1862
|
-
printf "0\n" > "$SCREENSHOT_SVG.exit_code"
|
|
1863
|
-
printf "shRunWithScreenshotTxt - ($* 2>&1)\n" 1>&2
|
|
1864
|
-
# run "$@" with screenshot
|
|
1865
|
-
(set -e
|
|
1866
|
-
"$@" 2>&1 || printf "$?\n" > "$SCREENSHOT_SVG.exit_code"
|
|
1867
|
-
) | tee "$SCREENSHOT_SVG.txt"
|
|
1868
|
-
EXIT_CODE="$(cat "$SCREENSHOT_SVG.exit_code")"
|
|
1869
|
-
printf "shRunWithScreenshotTxt - EXIT_CODE=$EXIT_CODE\n" 1>&2
|
|
1870
|
-
# format text-output
|
|
1871
|
-
node --input-type=module -e '
|
|
1872
|
-
import moduleFs from "fs";
|
|
1873
|
-
(async function () {
|
|
1874
|
-
let result = await moduleFs.promises.readFile(
|
|
1875
|
-
process.argv[1] + ".txt",
|
|
1876
|
-
"utf8"
|
|
1877
|
-
);
|
|
1878
|
-
let yy = 10;
|
|
1879
|
-
// remove ansi escape-code
|
|
1880
|
-
result = result.replace((
|
|
1881
|
-
/\u001b.*?m/g
|
|
1882
|
-
), "");
|
|
1883
|
-
/*
|
|
1884
|
-
// format unicode
|
|
1885
|
-
result = result.replace((
|
|
1886
|
-
/\\u[0-9a-f]{4}/g
|
|
1887
|
-
), function (match0) {
|
|
1888
|
-
return String.fromCharCode("0x" + match0.slice(-4));
|
|
1889
|
-
});
|
|
1890
|
-
*/
|
|
1891
|
-
// normalize "\r\n"
|
|
1892
|
-
result = result.replace((
|
|
1893
|
-
/\r\n?/
|
|
1894
|
-
), "\n").trimEnd();
|
|
1895
|
-
// 96-column wordwrap
|
|
1896
|
-
result = result.split("\n").map(function (line) {
|
|
1897
|
-
let wordwrap = line.slice(0, 96).padEnd(96, " ");
|
|
1898
|
-
line = line.slice(96);
|
|
1899
|
-
while (line) {
|
|
1900
|
-
wordwrap += "\\\n " + line.slice(0, 96 - 2).padEnd(96 - 2, " ");
|
|
1901
|
-
line = line.slice(96 - 2);
|
|
1902
|
-
}
|
|
1903
|
-
return wordwrap + " ";
|
|
1904
|
-
}).join("\n");
|
|
1905
|
-
// html-escape
|
|
1906
|
-
result = result.replace((
|
|
1907
|
-
/&/g
|
|
1908
|
-
), "&").replace((
|
|
1909
|
-
/</g
|
|
1910
|
-
), "<").replace((
|
|
1911
|
-
/>/g
|
|
1912
|
-
), ">");
|
|
1913
|
-
// convert text to svg-tspan
|
|
1914
|
-
result = result.split("\n").map(function (line) {
|
|
1915
|
-
yy += 22;
|
|
1916
|
-
return `<tspan
|
|
1917
|
-
lengthAdjust="spacingAndGlyphs"
|
|
1918
|
-
textLength="${96 * 8}"
|
|
1919
|
-
x="10"
|
|
1920
|
-
y="${yy}"
|
|
1921
|
-
>${line}</tspan>\n`;
|
|
1922
|
-
}).join("");
|
|
1923
|
-
result = String(`
|
|
1924
|
-
<svg height="${yy + 20}" width="800" xmlns="http://www.w3.org/2000/svg">
|
|
1925
|
-
<rect height="${yy + 20}" fill="#222" width="800"></rect>
|
|
1926
|
-
<text
|
|
1927
|
-
fill="#7f7"
|
|
1928
|
-
font-family="consolas, menlo, monospace"
|
|
1929
|
-
font-size="14"
|
|
1930
|
-
xml:space="preserve"
|
|
1931
|
-
>
|
|
1932
|
-
${result}
|
|
1933
|
-
</text>
|
|
1934
|
-
</svg>
|
|
1935
|
-
`).trim() + "\n";
|
|
1936
|
-
moduleFs.promises.writeFile(process.argv[1], result);
|
|
1937
|
-
}());
|
|
1938
|
-
' "$SCREENSHOT_SVG" # "'
|
|
1939
|
-
printf "shRunWithScreenshotTxt - wrote - $SCREENSHOT_SVG\n"
|
|
1940
|
-
# cleanup
|
|
1941
|
-
rm "$SCREENSHOT_SVG.exit_code" "$SCREENSHOT_SVG.txt"
|
|
1942
|
-
return "$EXIT_CODE"
|
|
1943
|
-
)}
|
|
1944
|
-
|
|
1945
|
-
shCiMain() {(set -e
|
|
1946
|
-
# run $@
|
|
1947
|
-
# run "$@" with winpty
|
|
1948
|
-
export CI_UNAME="${CI_UNAME:-$(uname)}"
|
|
1949
|
-
case "$CI_UNAME" in
|
|
1950
|
-
MSYS*)
|
|
1951
|
-
if [ ! "$CI_WINPTY" ] && [ "$1" != shHttpFileServer ]
|
|
1952
|
-
then
|
|
1953
|
-
export CI_WINPTY=1
|
|
1954
|
-
winpty -Xallow-non-tty -Xplain sh jslint_ci.sh "$@"
|
|
1955
|
-
return
|
|
1956
|
-
fi
|
|
1957
|
-
;;
|
|
1958
|
-
esac
|
|
1959
|
-
# run "$@"
|
|
1960
|
-
export NODE_OPTIONS="--unhandled-rejections=strict"
|
|
1961
|
-
if [ -f ./.ci.sh ]
|
|
1962
|
-
then
|
|
1963
|
-
. ./.ci.sh "$@"
|
|
1964
|
-
fi
|
|
1965
|
-
"$@"
|
|
1966
|
-
)}
|
|
1967
|
-
|
|
1968
|
-
shCiMain "$@"
|