sqlmath 0.0.4 → 2022.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/jslint_ci.sh DELETED
@@ -1,2795 +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
- # git add .; npm run test2; git checkout .
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 .artifact/screenshot_changelog.svg head -n50 CHANGELOG.md
22
- # vim rgx-lowercase \L\1\e
23
-
24
- shBashrcDebianInit() {
25
- # this function will init debian:stable /etc/skel/.bashrc
26
- # https://sources.debian.org/src/bash/4.4-5/debian/skel.bashrc/
27
- # ~/.bashrc: executed by bash(1) for non-login shells.
28
- # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
29
- # for examples
30
-
31
- # If not running interactively, don't do anything
32
- case $- in
33
- *i*) ;;
34
- *) return;;
35
- esac
36
-
37
- # don't put duplicate lines or lines starting with space in the history.
38
- # See bash(1) for more options
39
- HISTCONTROL=ignoreboth
40
-
41
- # append to the history file, don't overwrite it
42
- shopt -s histappend
43
-
44
- # for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
45
- HISTSIZE=1000
46
- HISTFILESIZE=2000
47
-
48
- # check the window size after each command and, if necessary,
49
- # update the values of LINES and COLUMNS.
50
- shopt -s checkwinsize
51
-
52
- # If set, the pattern "**" used in a pathname expansion context will
53
- # match all files and zero or more directories and subdirectories.
54
- #shopt -s globstar
55
-
56
- # make less more friendly for non-text input files, see lesspipe(1)
57
- [ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
58
-
59
- # set variable identifying the chroot you work in (used in the prompt below)
60
- if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
61
- debian_chroot=$(cat /etc/debian_chroot)
62
- fi
63
-
64
- # set a fancy prompt (non-color, unless we know we "want" color)
65
- case "$TERM" in
66
- xterm-color|*-256color) color_prompt=yes;;
67
- esac
68
-
69
- # uncomment for a colored prompt, if the terminal has the capability; turned
70
- # off by default to not distract the user: the focus in a terminal window
71
- # should be on the output of commands, not on the prompt
72
- #force_color_prompt=yes
73
-
74
- if [ -n "$force_color_prompt" ]; then
75
- if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
76
- # We have color support; assume it's compliant with Ecma-48
77
- # (ISO/IEC-6429). (Lack of such support is extremely rare, and such
78
- # a case would tend to support setf rather than setaf.)
79
- color_prompt=yes
80
- else
81
- color_prompt=
82
- fi
83
- fi
84
-
85
- if [ "$color_prompt" = yes ]; then
86
- PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
87
- else
88
- PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
89
- fi
90
- unset color_prompt force_color_prompt
91
-
92
- # If this is an xterm set the title to user@host:dir
93
- case "$TERM" in
94
- xterm*|rxvt*)
95
- PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
96
- ;;
97
- *)
98
- ;;
99
- esac
100
-
101
- # enable color support of ls and also add handy aliases
102
- if [ -x /usr/bin/dircolors ]; then
103
- test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
104
- alias ls='ls --color=auto'
105
- #alias dir='dir --color=auto'
106
- #alias vdir='vdir --color=auto'
107
-
108
- alias grep='grep --color=auto'
109
- #alias fgrep='fgrep --color=auto'
110
- #alias egrep='egrep --color=auto'
111
- fi
112
-
113
- # colored GCC warnings and errors
114
- #export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
115
-
116
- # some more ls aliases
117
- alias ll='ls -alF'
118
- #alias la='ls -A'
119
- #alias l='ls -CF'
120
-
121
- # Alias definitions.
122
- # You may want to put all your additions into a separate file like
123
- # ~/.bash_aliases, instead of adding them here directly.
124
- # See /usr/share/doc/bash-doc/examples in the bash-doc package.
125
-
126
- if [ -f ~/.bash_aliases ]; then
127
- . ~/.bash_aliases
128
- fi
129
-
130
- # enable programmable completion features (you don't need to enable
131
- # this, if it's already enabled in /etc/bash.bashrc and /etc/profile
132
- # sources /etc/bash.bashrc).
133
- if ! shopt -oq posix; then
134
- if [ -f /usr/share/bash-completion/bash_completion ]; then
135
- . /usr/share/bash-completion/bash_completion
136
- elif [ -f /etc/bash_completion ]; then
137
- . /etc/bash_completion
138
- fi
139
- fi
140
- }
141
-
142
- shBrowserScreenshot() {(set -e
143
- # this function will run headless-chrome to screenshot url $1 with
144
- # window-size $2
145
- node --input-type=module --eval '
146
- import moduleChildProcess from "child_process";
147
- import modulePath from "path";
148
- import moduleUrl from "url";
149
- // init debugInline
150
- (function () {
151
- let consoleError = console.error;
152
- globalThis.debugInline = globalThis.debugInline || function (...argList) {
153
-
154
- // this function will both print <argList> to stderr and return <argList>[0]
155
-
156
- consoleError("\n\ndebugInline");
157
- consoleError(...argList);
158
- consoleError("\n");
159
- return argList[0];
160
- };
161
- }());
162
- (async function () {
163
- let child;
164
- let exitCode;
165
- let file;
166
- let timeStart;
167
- let url;
168
- if (process.platform !== "linux") {
169
- return;
170
- }
171
- timeStart = Date.now();
172
- url = process.argv[1];
173
- if (!(
174
- /^\w+?:/
175
- ).test(url)) {
176
- url = modulePath.resolve(url);
177
- }
178
- file = moduleUrl.parse(url).pathname;
179
- // remove prefix $PWD from file
180
- if (String(file + "/").startsWith(process.cwd() + "/")) {
181
- file = file.replace(process.cwd(), "");
182
- }
183
- file = ".artifact/screenshot_browser_" + encodeURIComponent(file).replace((
184
- /%/g
185
- ), "_").toLowerCase() + ".png";
186
- child = moduleChildProcess.spawn(
187
- (
188
- process.platform === "darwin"
189
- ? "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
190
- : process.platform === "win32"
191
- ? "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"
192
- : "/usr/bin/google-chrome-stable"
193
- ),
194
- [
195
- "--headless",
196
- "--ignore-certificate-errors",
197
- "--incognito",
198
- "--screenshot",
199
- "--timeout=30000",
200
- "--user-data-dir=/dev/null",
201
- "--window-size=800x600",
202
- "-screenshot=" + file,
203
- (
204
- (process.getuid && process.getuid() === 0)
205
- ? "--no-sandbox"
206
- : ""
207
- ),
208
- url
209
- ].concat(process.argv.filter(function (elem) {
210
- return elem.startsWith("-");
211
- })).filter(function (elem) {
212
- return elem;
213
- }),
214
- {
215
- stdio: [
216
- "ignore", 1, 2
217
- ]
218
- }
219
- );
220
- exitCode = await new Promise(function (resolve) {
221
- child.on("exit", resolve);
222
- });
223
- console.error(
224
- "shBrowserScreenshot"
225
- + "\n - url - " + url
226
- + "\n - wrote - " + file
227
- + "\n - timeElapsed - " + (Date.now() - timeStart) + " ms"
228
- + "\n - EXIT_CODE=" + exitCode
229
- );
230
- }());
231
- ' "$@" # '
232
- )}
233
-
234
- shCiArtifactUpload() {(set -e
235
- # this function will upload build-artifacts to branch-gh-pages
236
- local BRANCH
237
- local FILE
238
- node --input-type=module --eval '
239
- process.exit(Number(
240
- `${process.version.split(".")[0]}.${process.arch}.${process.platform}`
241
- !== process.env.CI_NODE_VERSION_ARCH_PLATFORM
242
- ));
243
- ' || return 0
244
- # init .git/config
245
- git config --local user.email "github-actions@users.noreply.github.com"
246
- git config --local user.name "github-actions"
247
- # init $BRANCH
248
- BRANCH="$(git rev-parse --abbrev-ref HEAD)"
249
- git pull --unshallow origin "$BRANCH"
250
- # init $UPSTREAM_OWNER
251
- export UPSTREAM_OWNER="${UPSTREAM_OWNER:-jslint-org}"
252
- # init $UPSTREAM_REPO
253
- export UPSTREAM_REPO="${UPSTREAM_REPO:-jslint}"
254
- # screenshot changelog and files
255
- node --input-type=module --eval '
256
- import moduleChildProcess from "child_process";
257
- (function () {
258
- [
259
- // parallel-task - screenshot changelog
260
- [
261
- "jslint_ci.sh",
262
- "shRunWithScreenshotTxt",
263
- ".artifact/screenshot_changelog.svg",
264
- "head",
265
- "-n50",
266
- "CHANGELOG.md"
267
- ],
268
- // parallel-task - screenshot files
269
- [
270
- "jslint_ci.sh",
271
- "shRunWithScreenshotTxt",
272
- ".artifact/screenshot_package_listing.svg",
273
- "shGitLsTree"
274
- ]
275
- ].forEach(function (argList) {
276
- moduleChildProcess.spawn("sh", argList, {
277
- stdio: [
278
- "ignore", 1, 2
279
- ]
280
- }).on("exit", function (exitCode) {
281
- if (exitCode) {
282
- process.exit(exitCode);
283
- }
284
- });
285
- });
286
- }());
287
- ' "$@" # '
288
- shCiArtifactUploadCustom
289
- # 1px-border around browser-screenshot
290
- if (ls .artifact/screenshot_browser_*.png 2>/dev/null \
291
- && mogrify -version 2>&1 | grep -i imagemagick)
292
- then
293
- mogrify -shave 1x1 -bordercolor black -border 1 \
294
- .artifact/screenshot_browser_*.png
295
- fi
296
- # add dir .artifact
297
- git add -f .artifact
298
- git rm --cached -r .artifact/tmp 2>/dev/null || true
299
- git commit -am "add dir .artifact"
300
- # checkout branch-gh-pages
301
- git fetch origin gh-pages
302
- git checkout -b gh-pages origin/gh-pages
303
- # update dir branch-$BRANCH
304
- rm -rf "branch-$BRANCH"
305
- mkdir -p "branch-$BRANCH"
306
- (set -e
307
- cd "branch-$BRANCH"
308
- git init -b branch1
309
- git pull --depth=1 .. "$BRANCH"
310
- rm -rf .git
311
- git add -f .
312
- )
313
- # update root-dir with branch-beta
314
- if [ "$BRANCH" = beta ]
315
- then
316
- rm -rf .artifact
317
- git checkout beta .
318
- # update apidoc.html
319
- for FILE in apidoc.html
320
- do
321
- if [ -f ".artifact/$FILE" ]
322
- then
323
- cp -a ".artifact/$FILE" .
324
- git add -f "$FILE"
325
- fi
326
- done
327
- fi
328
- # update README.md with branch-$BRANCH and $GITHUB_REPOSITORY
329
- sed -i \
330
- -e "s|/branch-[0-9A-Z_a-z]*/|/branch-$BRANCH/|g" \
331
- -e "s|\b$UPSTREAM_OWNER/$UPSTREAM_REPO\b|$GITHUB_REPOSITORY|g" \
332
- -e "s|\b$UPSTREAM_OWNER\.github\.io/$UPSTREAM_REPO\b|$(
333
- printf "$GITHUB_REPOSITORY" | sed -e "s|/|.github.io/|"
334
- )|g" \
335
- "branch-$BRANCH/README.md"
336
- git status
337
- git commit -am "update dir branch-$BRANCH" || true
338
- # if branch-gh-pages has more than 50 commits,
339
- # then backup and squash commits
340
- if [ "$(git rev-list --count gh-pages)" -gt 50 ]
341
- then
342
- # backup
343
- shGitCmdWithGithubToken push origin -f gh-pages:gh-pages-backup
344
- # squash commits
345
- git checkout --orphan squash1
346
- git commit --quiet -am squash || true
347
- # reset branch-gh-pages to squashed-commit
348
- git push . -f squash1:gh-pages
349
- git checkout gh-pages
350
- # force-push squashed-commit
351
- shGitCmdWithGithubToken push origin -f gh-pages
352
- fi
353
- # list files
354
- shGitLsTree
355
- # push branch-gh-pages
356
- shGitCmdWithGithubToken push origin gh-pages
357
- # validate http-links
358
- (set -e
359
- cd "branch-$BRANCH"
360
- sleep 15
361
- shDirHttplinkValidate
362
- )
363
- )}
364
-
365
- shCiArtifactUploadCustom() {(set -e
366
- # this function will run custom-code to upload build-artifacts
367
- return
368
- )}
369
-
370
- shCiBase() {(set -e
371
- # this function will run base-ci
372
- # update table-of-contents in README.md
373
- node --input-type=module --eval '
374
- import moduleFs from "fs";
375
- (async function () {
376
- let data = await moduleFs.promises.readFile("README.md", "utf8");
377
- data = data.replace((
378
- /\n# Table of Contents$[\S\s]*?\n\n\n/m
379
- ), function () {
380
- let ii = -1;
381
- let toc = "\n# Table of Contents\n";
382
- data.replace((
383
- // /(\n{3,}#|\n+?<br><br>\n#|\n+?###) (\S.*)/g
384
- /((?:\n{3,}|\n+?(?:<br>)+?\n)(?:#|###)) (\S.*)/g
385
- ), function (match0, level, title) {
386
- if (title === "Table of Contents") {
387
- ii += 1;
388
- return "";
389
- }
390
- if (ii < 0) {
391
- return "";
392
- }
393
- switch (level) {
394
- case "\n\n\n<br><br>\n#":
395
- ii += 1;
396
- toc += "\n" + ii + ". [" + title + "](#";
397
- break;
398
- case "\n\n\n<br><br>\n###":
399
- toc += " - [" + title + "](#";
400
- break;
401
- default:
402
- throw new Error(JSON.stringify(match0));
403
- }
404
- toc += title.toLowerCase().replace((
405
- /[^ \-0-9A-Z_a-z]/g
406
- ), "").replace((
407
- / /g
408
- ), "-") + ")\n";
409
- return "";
410
- });
411
- toc += "\n\n";
412
- return toc;
413
- });
414
- await moduleFs.promises.writeFile("README.md", data);
415
- }());
416
- ' "$@" # '
417
- shCiBaseCustom
418
- git diff
419
- )}
420
-
421
- shCiBaseCustom() {(set -e
422
- # this function will run custom-ci
423
- return
424
- )}
425
-
426
- shCiBranchPromote() {(set -e
427
- # this function will promote branch $REMOTE/$BRANCH1 to branch $REMOTE/$BRANCH2
428
- local BRANCH1
429
- local BRANCH2
430
- local REMOTE
431
- REMOTE="$1"
432
- shift
433
- BRANCH1="$1"
434
- shift
435
- BRANCH2="$1"
436
- shift
437
- git fetch "$REMOTE" "$BRANCH1"
438
- git push "$REMOTE" "$REMOTE/$BRANCH1:$BRANCH2" "$@"
439
- )}
440
-
441
- shCiNpmPublish() {(set -e
442
- # this function will npm-publish package
443
- # init package.json for npm-publish
444
- npm install
445
- # update package-name
446
- if [ "$NPM_REGISTRY" = github ]
447
- then
448
- sed -i \
449
- "s|^ \"name\":.*| \"name\": \"@$GITHUB_REPOSITORY\",|" \
450
- package.json
451
- fi
452
- shCiNpmPublishCustom
453
- )}
454
-
455
- shCiNpmPublishCustom() {(set -e
456
- # this function will run custom-code to npm-publish package
457
- # npm publish --access public
458
- )}
459
-
460
- shDirHttplinkValidate() {(set -e
461
- # this function will validate http-links embedded in .html and .md files
462
- node --input-type=module --eval '
463
- import moduleFs from "fs";
464
- import moduleHttps from "https";
465
- import moduleUrl from "url";
466
- (async function () {
467
- let dict = {};
468
- Array.from(
469
- await moduleFs.promises.readdir(".")
470
- ).forEach(async function (file) {
471
- let data;
472
- if (file === "CHANGELOG.md" || !(
473
- /.\.html$|.\.md$/m
474
- ).test(file)) {
475
- return;
476
- }
477
- data = await moduleFs.promises.readFile(file, "utf8");
478
- data.replace((
479
- /\bhttps?:\/\/.*?(?:[\s")\]]|\W?$)/gm
480
- ), function (url) {
481
- let req;
482
- url = url.slice(0, -1).replace((
483
- /[\u0022\u0027]/g
484
- ), "").replace((
485
- /\/branch-\w+?\//g
486
- ), "/branch-alpha/").replace((
487
- /\bjslint-org\/jslint\b/g
488
- ), process.env.GITHUB_REPOSITORY || "jslint-org/jslint").replace((
489
- /\bjslint-org\.github\.io\/jslint\b/g
490
- ), String(
491
- process.env.GITHUB_REPOSITORY || "jslint-org/jslint"
492
- ).replace("/", ".github.io/"));
493
- if (url.startsWith("http://")) {
494
- throw new Error("shDirHttplinkValidate - insecure link " + url);
495
- }
496
- // ignore duplicate-link
497
- if (dict.hasOwnProperty(url)) {
498
- return "";
499
- }
500
- dict[url] = true;
501
- req = moduleHttps.request(moduleUrl.parse(
502
- url
503
- ), function (res) {
504
- console.error(
505
- "shDirHttplinkValidate " + res.statusCode + " " + url
506
- );
507
- if (!(res.statusCode < 400)) {
508
- throw new Error(
509
- "shDirHttplinkValidate - " + file
510
- + " - unreachable link " + url
511
- );
512
- }
513
- req.abort();
514
- res.destroy();
515
- });
516
- req.setTimeout(30000);
517
- req.end();
518
- return "";
519
- });
520
- data.replace((
521
- /(\bhref=|\bsrc=|\burl\(|\[[^]*?\]\()("?.*?)(?:[")\]]|$)/gm
522
- ), function (ignore, linkType, url) {
523
- if (!linkType.startsWith("[")) {
524
- url = url.slice(1);
525
- }
526
- if (url.length === 0 || url.startsWith("data:")) {
527
- return;
528
- }
529
- // ignore duplicate-link
530
- if (dict.hasOwnProperty(url)) {
531
- return "";
532
- }
533
- dict[url] = true;
534
- if (!(
535
- /^https?|^mailto:|^[#\/]/m
536
- ).test(url)) {
537
- moduleFs.stat(url.split("?")[0], function (ignore, exists) {
538
- console.error(
539
- "shDirHttplinkValidate " + Boolean(exists) + " " + url
540
- );
541
- if (!exists) {
542
- throw new Error(
543
- "shDirHttplinkValidate - " + file
544
- + " - unreachable link " + url
545
- );
546
- }
547
- });
548
- }
549
- return "";
550
- });
551
- });
552
- }());
553
- ' "$@" # '
554
- )}
555
-
556
- shDuList() {(set -e
557
- # this function will du $1 and sort its subdir by size
558
- du -md1 "$1" | sort -nr
559
- )}
560
-
561
- shGitCmdWithGithubToken() {(set -e
562
- # this function will run git $CMD with $GITHUB_TOKEN
563
- local CMD
564
- local EXIT_CODE
565
- local REMOTE
566
- local URL
567
- printf "shGitCmdWithGithubToken $*\n"
568
- CMD="$1"
569
- shift
570
- REMOTE="$1"
571
- shift
572
- URL="$(
573
- git config "remote.$REMOTE.url" \
574
- | sed -e "s|https://|https://x-access-token:$GITHUB_TOKEN@|"
575
- )"
576
- EXIT_CODE=0
577
- # hide $GITHUB_TOKEN in case of err
578
- git "$CMD" "$URL" "$@" 2>/dev/null || EXIT_CODE="$?"
579
- printf "shGitCmdWithGithubToken - EXIT_CODE=$EXIT_CODE\n" 1>&2
580
- return "$EXIT_CODE"
581
- )}
582
-
583
- shGitGc() {(set -e
584
- # this function will gc unreachable .git objects
585
- # http://stackoverflow.com/questions/3797907/how-to-remove-unused-objects-from-a-git-repository
586
- git \
587
- -c gc.reflogExpire=0 \
588
- -c gc.reflogExpireUnreachable=0 \
589
- -c gc.rerereresolved=0 \
590
- -c gc.rerereunresolved=0 \
591
- -c gc.pruneExpire=now \
592
- gc
593
- )}
594
-
595
- shGitInitBase() {(set -e
596
- # this function will git init && create basic git-template from jslint-org/base
597
- local BRANCH
598
- git init
599
- git config core.autocrlf input
600
- git remote remove base 2>/dev/null || true
601
- git remote add base https://github.com/jslint-org/base
602
- git fetch base base
603
- for BRANCH in base alpha
604
- do
605
- git branch -D "$BRANCH" 2>/dev/null || true
606
- git checkout -b "$BRANCH" base/base
607
- done
608
- sed -i.bak "s|owner/repo|${1:-owner/repo}|" .gitconfig
609
- rm .gitconfig.bak
610
- cp .gitconfig .git/config
611
- git commit -am "update owner/repo to $1" || true
612
- )}
613
-
614
-
615
- shGitLsTree() {(set -e
616
- # this function will "git ls-tree" all files committed in HEAD
617
- # example use:
618
- # shGitLsTree | sort -rk3 # sort by date
619
- # shGitLsTree | sort -rk4 # sort by size
620
- node --input-type=module --eval '
621
- import moduleChildProcess from "child_process";
622
- (async function () {
623
- let result;
624
- // get file, mode, size
625
- result = await new Promise(function (resolve) {
626
- result = "";
627
- moduleChildProcess.spawn("git", [
628
- "ls-tree", "-lr", "HEAD"
629
- ], {
630
- encoding: "utf8",
631
- stdio: [
632
- "ignore", "pipe", 2
633
- ]
634
- }).on("exit", function () {
635
- resolve(result);
636
- }).stdout.on("data", function (chunk) {
637
- result += chunk;
638
- }).setEncoding("utf8");
639
- });
640
- result = Array.from(result.matchAll(
641
- /^(\S+?) +?\S+? +?\S+? +?(\S+?)\t(\S+?)$/gm
642
- )).map(function ([
643
- ignore, mode, size, file
644
- ]) {
645
- return {
646
- file,
647
- mode: mode.slice(-3),
648
- size: Number(size)
649
- };
650
- });
651
- result = result.sort(function (aa, bb) {
652
- return aa.file > bb.file || -1;
653
- });
654
- result = result.slice(0, 1000);
655
- result.unshift({
656
- file: ".",
657
- mode: "755",
658
- size: 0
659
- });
660
- // get date
661
- result.forEach(function (elem) {
662
- result[0].size += elem.size;
663
- moduleChildProcess.spawn("git", [
664
- "log", "--max-count=1", "--format=%at", elem.file
665
- ], {
666
- stdio: [
667
- "ignore", "pipe", 2
668
- ]
669
- }).stdout.on("data", function (chunk) {
670
- elem.date = new Date(
671
- Number(chunk) * 1000
672
- ).toISOString().slice(0, 19) + "Z";
673
- });
674
- });
675
- process.on("exit", function () {
676
- let iiPad;
677
- let sizePad;
678
- iiPad = String(result.length).length + 1;
679
- sizePad = String(Math.ceil(result[0].size / 1024)).length;
680
- process.stdout.write(result.map(function (elem, ii) {
681
- return (
682
- String(ii + ".").padStart(iiPad, " ")
683
- + " " + elem.mode
684
- + " " + elem.date
685
- + " " + String(
686
- Math.ceil(elem.size / 1024)
687
- ).padStart(sizePad, " ") + " KB"
688
- + " " + elem.file
689
- + "\n"
690
- );
691
- }).join(""));
692
- });
693
- }());
694
- ' "$@" # '
695
- )}
696
-
697
- shGitSquashPop() {(set -e
698
- # this function will squash HEAD to given $COMMIT
699
- # http://stackoverflow.com/questions/5189560
700
- # /how-can-i-squash-my-last-x-commits-together-using-git
701
- COMMIT="$1"
702
- MESSAGE="$2"
703
- # reset git to previous $COMMIT
704
- git reset "$COMMIT"
705
- git add .
706
- # commit HEAD immediately after previous $COMMIT
707
- git commit -am "$MESSAGE" || true
708
- )}
709
-
710
- shGrep() {(set -e
711
- # this function will recursively grep . for $REGEXP
712
- REGEXP="$1"
713
- shift
714
- FILE_FILTER="\
715
- /\\.|~$|/(obj|release)/|(\\b|_)(\\.\\d|\
716
- archive|artifact|\
717
- bower_component|build|\
718
- coverage|\
719
- doc|\
720
- external|\
721
- fixture|\
722
- git_module|\
723
- jquery|\
724
- log|\
725
- min|misc|mock|\
726
- node_module|\
727
- old|\
728
- raw|\rollup|\
729
- swp|\
730
- tmp|\
731
- vendor)s{0,1}(\\b|_)\
732
- "
733
- find . -type f |
734
- grep -v -E "$FILE_FILTER" |
735
- tr "\n" "\000" |
736
- xargs -0 grep -HIin -E "$REGEXP" "$@" |
737
- tee /tmp/shGrep.txt || true
738
- )}
739
-
740
- shGrepReplace() {(set -e
741
- # this function will inline grep-and-replace /tmp/shGrep.txt
742
- node --input-type=module --eval '
743
- import moduleFs from "fs";
744
- import moduleOs from "os";
745
- import modulePath from "path";
746
- (async function () {
747
- "use strict";
748
- let data;
749
- let dict = {};
750
- data = await moduleFs.promises.readFile((
751
- moduleOs.tmpdir() + "/shGrep.txt"
752
- ), "utf8");
753
- data = data.replace((
754
- /^(.+?):(\d+?):(.*?)$/gm
755
- ), function (ignore, file, lineno, str) {
756
- dict[file] = dict[file] || moduleFs.readFileSync( //jslint-quiet
757
- modulePath.resolve(file),
758
- "utf8"
759
- ).split("\n");
760
- dict[file][lineno - 1] = str;
761
- return "";
762
- });
763
- Object.entries(dict).forEach(function ([
764
- file, data
765
- ]) {
766
- moduleFs.promises.writeFile(file, data.join("\n"));
767
- });
768
- }());
769
- ' "$@" # '
770
- )}
771
-
772
- shHttpFileServer() {(set -e
773
- # this function will run simple node http-file-server on port $PORT
774
- if [ ! "$npm_config_mode_auto_restart" ]
775
- then
776
- local EXIT_CODE
777
- EXIT_CODE=0
778
- export npm_config_mode_auto_restart=1
779
- while true
780
- do
781
- printf "\n"
782
- git diff --color 2>/dev/null | cat || true
783
- printf "\nshHttpFileServer - (re)starting $*\n"
784
- (shHttpFileServer "$@") || EXIT_CODE="$?"
785
- printf "process exited with code $EXIT_CODE\n"
786
- # if $EXIT_CODE != 77, then exit process
787
- # http://en.wikipedia.org/wiki/Unix_signal
788
- if [ "$EXIT_CODE" != 77 ]
789
- then
790
- break
791
- fi
792
- # else restart process after 1 second
793
- sleep 1
794
- done
795
- return
796
- fi
797
- node --input-type=module --eval '
798
- import moduleChildProcess from "child_process";
799
- import moduleFs from "fs";
800
- import moduleHttp from "http";
801
- import modulePath from "path";
802
- import moduleRepl from "repl";
803
- import moduleUrl from "url";
804
- // init debugInline
805
- (function () {
806
- let consoleError = console.error;
807
- globalThis.debugInline = globalThis.debugInline || function (...argList) {
808
-
809
- // this function will both print <argList> to stderr and return <argList>[0]
810
-
811
- consoleError("\n\ndebugInline");
812
- consoleError(...argList);
813
- consoleError("\n");
814
- return argList[0];
815
- };
816
- }());
817
- (async function httpFileServer() {
818
-
819
- // this function will start http-file-server
820
-
821
- let contentTypeDict = {
822
- ".bmp": "image/bmp",
823
- ".cjs": "application/javascript; charset=utf-8",
824
- ".css": "text/css; charset=utf-8",
825
- ".gif": "image/gif",
826
- ".htm": "text/html; charset=utf-8",
827
- ".html": "text/html; charset=utf-8",
828
- ".jpe": "image/jpeg",
829
- ".jpeg": "image/jpeg",
830
- ".jpg": "image/jpeg",
831
- ".js": "application/javascript; charset=utf-8",
832
- ".json": "application/json; charset=utf-8",
833
- ".md": "text/markdown; charset=utf-8",
834
- ".mjs": "application/javascript; charset=utf-8",
835
- ".pdf": "application/pdf",
836
- ".png": "image/png",
837
- ".svg": "image/svg+xml; charset=utf-8",
838
- ".txt": "text/plain; charset=utf-8",
839
- ".wasm": "application/wasm",
840
- ".woff": "font/woff",
841
- ".woff2": "font/woff2",
842
- ".xml": "application/xml; charset=utf-8",
843
- "/": "text/html; charset=utf-8"
844
- };
845
- if (process.argv[1]) {
846
- await import("file://" + modulePath.resolve(process.argv[1]));
847
- }
848
- process.env.PORT = process.env.PORT || "8080";
849
- console.error("http-file-server listening on port " + process.env.PORT);
850
- moduleHttp.createServer(function (req, res) {
851
- let file;
852
- let pathname;
853
- let timeStart;
854
- // init timeStart
855
- timeStart = Date.now();
856
- // init pathname
857
- pathname = moduleUrl.parse(req.url).pathname;
858
- // debug - serverLog
859
- res.on("close", function () {
860
- if (pathname === "/favicon.ico") {
861
- return;
862
- }
863
- console.error(
864
- "serverLog - "
865
- + new Date(timeStart).toISOString() + " - "
866
- + (Date.now() - timeStart) + "ms - "
867
- + (res.statusCode || 0) + " " + req.method + " " + pathname
868
- );
869
- });
870
- // debug - echo request
871
- if (pathname === "/echo") {
872
- res.write(JSON.stringify(req.headers, undefined, 4) + "\n");
873
- req.pipe(res);
874
- return;
875
- }
876
- // replace trailing "/" with "/index.html"
877
- file = pathname.slice(1).replace((
878
- /\/$/
879
- ), "/index.html");
880
- // resolve file
881
- file = modulePath.resolve(file);
882
- // security - disable parent-directory lookup
883
- if (!file.startsWith(process.cwd() + modulePath.sep)) {
884
- res.statusCode = 404;
885
- res.end();
886
- return;
887
- }
888
- moduleFs.readFile(file, function (err, data) {
889
- let contentType;
890
- if (err) {
891
- res.statusCode = 404;
892
- res.end();
893
- return;
894
- }
895
- contentType = contentTypeDict[(
896
- /^\/$|\.[^.]*?$|$/m
897
- ).exec(file)[0]];
898
- if (contentType) {
899
- res.setHeader("content-type", contentType);
900
- }
901
- res.end(data);
902
- });
903
- }).listen(process.env.PORT);
904
- }());
905
- (function jslintDir() {
906
-
907
- // this function will jslint current-directory
908
-
909
- moduleFs.stat((
910
- process.env.HOME + "/jslint.mjs"
911
- ), function (ignore, exists) {
912
- if (exists) {
913
- moduleChildProcess.spawn("node", [
914
- process.env.HOME + "/jslint.mjs", "."
915
- ], {
916
- stdio: [
917
- "ignore", 1, 2
918
- ]
919
- });
920
- }
921
- });
922
- }());
923
- (function replStart() {
924
-
925
- // this function will start repl-debugger
926
-
927
- let that;
928
- // start repl
929
- that = moduleRepl.start({
930
- useGlobal: true
931
- });
932
- // init history
933
- that.setupHistory(modulePath.resolve(
934
- process.env.HOME + "/.node_repl_history"
935
- ), function () {
936
- return;
937
- });
938
- // save eval-function
939
- that.evalDefault = that.eval;
940
- // hook custom-eval-function
941
- that.eval = function (script, context, file, onError) {
942
- script.replace((
943
- /^(\S+) (.*?)\n/
944
- ), function (ignore, match1, match2) {
945
- switch (match1) {
946
- // syntax-sugar - run shell-cmd
947
- case "$":
948
- switch (match2.split(" ").slice(0, 2).join(" ")) {
949
- // syntax-sugar - run git diff
950
- case "git diff":
951
- match2 += " --color";
952
- break;
953
- // syntax-sugar - run git log
954
- case "git log":
955
- match2 += " -n 10";
956
- break;
957
- // syntax-sugar - run ll
958
- case "ll":
959
- match2 = "ls -Fal";
960
- break;
961
- }
962
- match2 = match2.replace((
963
- /^git /
964
- ), "git --no-pager ");
965
- // run shell-cmd
966
- console.error("$ " + match2);
967
- moduleChildProcess.spawn(match2, {
968
- shell: true,
969
- stdio: [
970
- "ignore", 1, 2
971
- ]
972
- // print exitCode
973
- }).on("exit", function (exitCode) {
974
- console.error("$ EXIT_CODE=" + exitCode);
975
- that.evalDefault("\n", context, file, onError);
976
- });
977
- script = "\n";
978
- break;
979
- // syntax-sugar - map text with charCodeAt
980
- case "charCode":
981
- console.error(
982
- match2.split("").map(function (chr) {
983
- return (
984
- "\\u"
985
- + chr.charCodeAt(0).toString(16).padStart(4, 0)
986
- );
987
- }).join("")
988
- );
989
- script = "\n";
990
- break;
991
- // syntax-sugar - sort chr
992
- case "charSort":
993
- console.error(JSON.stringify(match2.split("").sort().join("")));
994
- script = "\n";
995
- break;
996
- // syntax-sugar - list obj-keys, sorted by item-type
997
- // 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
998
- case "keys":
999
- script = (
1000
- "console.error(Object.keys(" + match2
1001
- + ").map(function(key){return("
1002
- + "typeof " + match2 + "[key]===\u0027object\u0027&&"
1003
- + match2 + "[key]&&"
1004
- + match2 + "[key]===global[key]"
1005
- + "?\u0027global\u0027"
1006
- + ":typeof " + match2 + "[key]"
1007
- + ")+\u0027 \u0027+key;"
1008
- + "}).sort().join(\u0027\\n\u0027))\n"
1009
- );
1010
- break;
1011
- // syntax-sugar - print String(val)
1012
- case "print":
1013
- script = "console.error(String(" + match2 + "))\n";
1014
- break;
1015
- }
1016
- });
1017
- // eval script
1018
- that.evalDefault(script, context, file, onError);
1019
- };
1020
- }());
1021
- (function watchDir() {
1022
-
1023
- // this function will watch current-directory for changes
1024
-
1025
- moduleFs.readdir(".", function (ignore, fileList) {
1026
- fileList.forEach(function (file) {
1027
- if (file[0] === ".") {
1028
- return;
1029
- }
1030
- moduleFs.stat(file, function (ignore, stats) {
1031
- if (!(stats && stats.isFile())) {
1032
- return;
1033
- }
1034
- moduleFs.watchFile(file, {
1035
- interval: 1000,
1036
- persistent: false
1037
- }, function () {
1038
- console.error("watchFile - modified - " + file);
1039
- setTimeout(process.exit.bind(undefined, 77), 1000);
1040
- });
1041
- });
1042
- });
1043
- });
1044
- }());
1045
- ' "$@" # '
1046
- )}
1047
-
1048
- shImageLogoCreate() {(set -e
1049
- # this function will create .png logo
1050
- local SIZE
1051
- echo '
1052
- <!DOCTYPE html>
1053
- <html lang="en">
1054
- <head>
1055
- <title>logo</title>
1056
- <style>
1057
- /* sh jslint_ci.sh shBrowserScreenshot asset_image_logo.html --window-size=512x512 */
1058
- /* csslint box-model:false */
1059
- /* csslint ignore:start */
1060
- *,
1061
- *:after,
1062
- *:before {
1063
- box-sizing: border-box;
1064
- }
1065
- @font-face {
1066
- font-family: Daley;
1067
- font-weight: bold;
1068
- src: url("asset_font_daley_bold.woff2") format("woff2");
1069
- }
1070
- /* csslint ignore:end */
1071
- body,
1072
- div {
1073
- margin: 0;
1074
- }
1075
- .container1 {
1076
- background: antiquewhite;
1077
- border: 24px solid darkslategray;
1078
- border-radius: 96px;
1079
- color: darkslategray;
1080
- font-family: Daley;
1081
- height: 512px;
1082
- margin: 0;
1083
- position: relative;
1084
- width: 512px;
1085
- zoom: 100%;
1086
- /*
1087
- background: transparent;
1088
- border: 24px solid black;
1089
- color: black;
1090
- */
1091
- }
1092
- .text1 {
1093
- font-size: 256px;
1094
- left: 44px;
1095
- position: absolute;
1096
- top: 32px;
1097
- }
1098
- .text2 {
1099
- bottom: 8px;
1100
- font-size: 192px;
1101
- left: 44px;
1102
- position: absolute;
1103
- }
1104
- </style>
1105
- </head>
1106
- <body>
1107
- <div class="container1">
1108
- <div class="text1">JS</div>
1109
- <div class="text2">Lint</div>
1110
- </div>
1111
- </body>
1112
- </html>
1113
- ' > .artifact/asset_image_logo_512.html
1114
- cp asset_font_daley_bold.woff2 .artifact || true
1115
- # screenshot asset_image_logo_512.png
1116
- shBrowserScreenshot .artifact/asset_image_logo_512.html \
1117
- --window-size=512x512 \
1118
- -screenshot=.artifact/asset_image_logo_512.png
1119
- # create various smaller thumbnails
1120
- for SIZE in 32 64 128 256
1121
- do
1122
- convert -resize "${SIZE}x${SIZE}" .artifact/asset_image_logo_512.png \
1123
- ".artifact/asset_image_logo_$SIZE.png"
1124
- printf \
1125
- "shImageLogoCreate - wrote - .artifact/asset_image_logo_$SIZE.png\n" 1>&2
1126
- done
1127
- # convert to svg @ https://convertio.co/png-svg/
1128
- )}
1129
-
1130
- shImageToDataUri() {(set -e
1131
- # this function will convert image $1 to data-uri string
1132
- node --input-type=module --eval '
1133
- import moduleFs from "fs";
1134
- import moduleHttps from "https";
1135
- (async function () {
1136
- let file;
1137
- let result;
1138
- file = process.argv[1];
1139
- if ((
1140
- /^https:\/\//
1141
- ).test(file)) {
1142
- result = await new Promise(function (resolve) {
1143
- moduleHttps.get(file, function (res) {
1144
- let chunkList;
1145
- chunkList = [];
1146
- res.on("data", function (chunk) {
1147
- chunkList.push(chunk);
1148
- }).on("end", function () {
1149
- resolve(Buffer.concat(chunkList));
1150
- });
1151
- });
1152
- });
1153
- } else {
1154
- result = await moduleFs.promises.readFile(file);
1155
- }
1156
- result = String(
1157
- "data:image/" + file.match(
1158
- /\.[^.]*?$|$/m
1159
- )[0].slice(1) + ";base64," + result.toString("base64")
1160
- ).replace((
1161
- /.{72}/g
1162
- ), "$&\\\n");
1163
- console.log(result);
1164
- }());
1165
- ' "$@" # '
1166
- )}
1167
-
1168
- shJsonNormalize() {(set -e
1169
- # this function will
1170
- # 1. read json-data from file $1
1171
- # 2. normalize json-data
1172
- # 3. write normalized json-data back to file $1
1173
- node --input-type=module --eval '
1174
- import moduleFs from "fs";
1175
- function noop(val) {
1176
-
1177
- // This function will do nothing except return <val>.
1178
-
1179
- return val;
1180
- }
1181
- function objectDeepCopyWithKeysSorted(obj) {
1182
-
1183
- // This function will recursively deep-copy <obj> with keys sorted.
1184
-
1185
- let sorted;
1186
- if (typeof obj !== "object" || !obj) {
1187
- return obj;
1188
- }
1189
-
1190
- // Recursively deep-copy list with child-keys sorted.
1191
-
1192
- if (Array.isArray(obj)) {
1193
- return obj.map(objectDeepCopyWithKeysSorted);
1194
- }
1195
-
1196
- // Recursively deep-copy obj with keys sorted.
1197
-
1198
- sorted = {};
1199
- Object.keys(obj).sort().forEach(function (key) {
1200
- sorted[key] = objectDeepCopyWithKeysSorted(obj[key]);
1201
- });
1202
- return sorted;
1203
- }
1204
- (async function () {
1205
- console.error("shJsonNormalize - " + process.argv[1]);
1206
- await moduleFs.promises.writeFile(
1207
- process.argv[1],
1208
- JSON.stringify(
1209
- objectDeepCopyWithKeysSorted(
1210
- JSON.parse(
1211
- noop(
1212
- await moduleFs.promises.readFile(
1213
- process.argv[1],
1214
- "utf8"
1215
- )
1216
- ).replace((
1217
- /^\ufeff/
1218
- ), "")
1219
- )
1220
- ),
1221
- undefined,
1222
- Number(process.argv[2]) || 4
1223
- ) + "\n"
1224
- );
1225
- }());
1226
- ' "$@" # '
1227
- )}
1228
-
1229
- shNpmPublishV0() {(set -e
1230
- # this function will npm-publish name $1 with bare package.json
1231
- local DIR
1232
- DIR=/tmp/shNpmPublishV0
1233
- rm -rf "$DIR" && mkdir -p "$DIR" && cd "$DIR"
1234
- printf "{\"name\":\"$1\",\"version\":\"0.0.1\"}\n" > package.json
1235
- shift
1236
- npm publish "$@"
1237
- )}
1238
-
1239
- shRawLibFetch() {(set -e
1240
- # this function will fetch raw-lib from $1
1241
- node --input-type=module --eval '
1242
- import moduleChildProcess from "child_process";
1243
- import moduleFs from "fs";
1244
- import moduleHttps from "https";
1245
- import modulePath from "path";
1246
- // init debugInline
1247
- (function () {
1248
- let consoleError = console.error;
1249
- globalThis.debugInline = globalThis.debugInline || function (...argList) {
1250
-
1251
- // this function will both print <argList> to stderr and return <argList>[0]
1252
-
1253
- consoleError("\n\ndebugInline");
1254
- consoleError(...argList);
1255
- consoleError("\n");
1256
- return argList[0];
1257
- };
1258
- }());
1259
- (async function () {
1260
- let fetchList;
1261
- let matchObj;
1262
- let replaceList;
1263
- let repoDict;
1264
- function pipeToBuffer(res, dict, key) {
1265
-
1266
- // This function will concat data from <res> to <dict>[<key>].
1267
-
1268
- let data;
1269
- data = [];
1270
- res.on("data", function (chunk) {
1271
- data.push(chunk);
1272
- }).on("end", function () {
1273
- dict[key] = Buffer.concat(data);
1274
- });
1275
- }
1276
- // init matchObj
1277
- matchObj = (
1278
- /^\/\*jslint-disable\*\/\n\/\*\nshRawLibFetch\n(\{\n[\S\s]*?\n\})([\S\s]*?)\n\*\/\n/m
1279
- ).exec(await moduleFs.promises.readFile(process.argv[1], "utf8"));
1280
- // JSON.parse match1 with comment
1281
- fetchList = JSON.parse(matchObj[1]).fetchList;
1282
- replaceList = JSON.parse(matchObj[1]).replaceList || [];
1283
- // init repoDict, fetchList
1284
- repoDict = {};
1285
- fetchList.forEach(function (elem) {
1286
- if (!elem.url) {
1287
- return;
1288
- }
1289
- elem.prefix = elem.url.split("/").slice(0, 7).join("/");
1290
- // fetch dateCommitted
1291
- if (!repoDict.hasOwnProperty(elem.prefix)) {
1292
- repoDict[elem.prefix] = true;
1293
- moduleHttps.request(elem.prefix.replace(
1294
- "/blob/",
1295
- "/commits/"
1296
- ), function (res) {
1297
- pipeToBuffer(res, elem, "dateCommitted");
1298
- }).end();
1299
- }
1300
- // fetch file
1301
- if (elem.node) {
1302
- pipeToBuffer(moduleChildProcess.spawn("node", [
1303
- "-e", elem.node
1304
- ], {
1305
- stdio: [
1306
- "ignore", "pipe", 2
1307
- ]
1308
- }).stdout, elem, "data");
1309
- return;
1310
- }
1311
- if (elem.sh) {
1312
- pipeToBuffer(moduleChildProcess.spawn(elem.sh, {
1313
- shell: true,
1314
- stdio: [
1315
- "ignore", "pipe", 2
1316
- ]
1317
- }).stdout, elem, "data");
1318
- return;
1319
- }
1320
- moduleHttps.get(elem.url2 || elem.url.replace(
1321
- "https://github.com/",
1322
- "https://raw.githubusercontent.com/"
1323
- ).replace("/blob/", "/"), function (res) {
1324
- // http-redirect
1325
- if (res.statusCode === 302) {
1326
- moduleHttps.get(res.headers.location, function (res) {
1327
- pipeToBuffer(res, elem, "data");
1328
- });
1329
- return;
1330
- }
1331
- pipeToBuffer(res, elem, "data");
1332
- });
1333
- });
1334
- // parse fetched data
1335
- process.on("exit", function () {
1336
- let header;
1337
- let result;
1338
- let result0;
1339
- result = "";
1340
- fetchList.forEach(function (elem, ii, list) {
1341
- let prefix;
1342
- if (!elem.url) {
1343
- return;
1344
- }
1345
- // init prefix
1346
- prefix = "exports_" + modulePath.dirname(elem.url).replace(
1347
- "https://github.com/",
1348
- ""
1349
- ).replace((
1350
- /\/blob\/[^\/]*/
1351
- ), "/").replace((
1352
- /\W/g
1353
- ), "_").replace((
1354
- /(_)_+|_+$/g
1355
- ), "$1");
1356
- list[ii].exports = prefix + "_" + modulePath.basename(
1357
- elem.url
1358
- ).replace((
1359
- /\.js$/
1360
- ), "").replace((
1361
- /\W/g
1362
- ), "_");
1363
- if (elem.dataUriType) {
1364
- return;
1365
- }
1366
- if (elem.dateCommitted) {
1367
- result += (
1368
- "\n\n\n/*\n"
1369
- + "repo " + elem.prefix.replace("/blob/", "/tree/") + "\n"
1370
- + "committed " + (
1371
- /\b\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ\b|$/
1372
- ).exec(elem.dateCommitted.toString())[0] + "\n"
1373
- + "*/"
1374
- );
1375
- }
1376
- // comment /*...*/
1377
- if (elem.comment) {
1378
- elem.data = "/*\n" + elem.data.toString().trim().replace((
1379
- /\/\*/g
1380
- ), "/\\*").replace((
1381
- /\*\//g
1382
- ), "*\\/") + "\n*/";
1383
- }
1384
- // init header and footer
1385
- result += (
1386
- "\n\n\n/*\nfile " + elem.url + "\n*/\n"
1387
- + (elem.header || "")
1388
- + elem.data.toString().trim()
1389
- + (elem.footer || "")
1390
- );
1391
- });
1392
- result = (
1393
- "\n" + result.trim()
1394
- + "\n\n\n/*\nfile none\n*/\n/*jslint-enable*/\n"
1395
- );
1396
- // comment #!
1397
- result = result.replace((
1398
- /^#!/gm
1399
- ), "// $&");
1400
- // normalize newline
1401
- result = result.replace((
1402
- /\r\n|\r/g
1403
- ), "\n");
1404
- // remove trailing-whitespace
1405
- result = result.replace((
1406
- /[\t ]+$/gm
1407
- ), "");
1408
- // remove leading-newline before ket
1409
- result = result.replace((
1410
- /\n+?(\n *?\})/g
1411
- ), "$1");
1412
- // eslint - no-multiple-empty-lines
1413
- // https://github.com/eslint/eslint/blob/v7.2.0/docs/rules/no-multiple-empty-lines.md //jslint-quiet
1414
- result = result.replace((
1415
- /\n{4,}/g
1416
- ), "\n\n\n");
1417
- // replace from replaceList
1418
- replaceList.forEach(function ({
1419
- aa,
1420
- bb,
1421
- flags
1422
- }) {
1423
- result0 = result;
1424
- result = result.replace(new RegExp(aa, flags), bb);
1425
- if (result0 === result) {
1426
- throw new Error(
1427
- "shRawLibFetch - cannot find-and-replace snippet "
1428
- + JSON.stringify(aa)
1429
- );
1430
- }
1431
- });
1432
- // init header
1433
- header = (
1434
- matchObj.input.slice(0, matchObj.index)
1435
- + "/*jslint-disable*/\n/*\nshRawLibFetch\n"
1436
- + JSON.stringify(JSON.parse(matchObj[1]), undefined, 4) + "\n"
1437
- + matchObj[2].split("\n\n").filter(function (elem) {
1438
- return elem.trim();
1439
- }).map(function (elem) {
1440
- return elem.trim().replace((
1441
- /\*\//g
1442
- ), "*\\\\/").replace((
1443
- /\/\*/g
1444
- ), "/\\\\*") + "\n";
1445
- }).sort().join("\n") + "*/\n\n"
1446
- );
1447
- // replace from header-diff
1448
- header.replace((
1449
- /((?:^-.*?\n)+?)((?:^\+.*?\n)+)/gm
1450
- ), function (ignore, aa, bb) {
1451
- aa = "\n" + aa.replace((
1452
- /^-/gm
1453
- ), "").replace((
1454
- /\*\\\\\//g
1455
- ), "*/").replace((
1456
- /\/\\\\\*/g
1457
- ), "/*");
1458
- bb = "\n" + bb.replace((
1459
- /^\+/gm
1460
- ), "").replace((
1461
- /\*\\\\\//g
1462
- ), "*/").replace((
1463
- /\/\\\\\*/g
1464
- ), "/*");
1465
- result0 = result;
1466
- // disable $-escape in replacement-string
1467
- result = result.replace(aa, function () {
1468
- return bb;
1469
- });
1470
- if (result0 === result) {
1471
- throw new Error(
1472
- "shRawLibFetch - cannot find-and-replace snippet "
1473
- + JSON.stringify(aa)
1474
- );
1475
- }
1476
- return "";
1477
- });
1478
- // inline dataUri
1479
- fetchList.forEach(function ({
1480
- data,
1481
- dataUriType,
1482
- exports
1483
- }) {
1484
- if (!dataUriType) {
1485
- return;
1486
- }
1487
- data = (
1488
- "data:" + dataUriType + ";base64,"
1489
- + data.toString("base64")
1490
- );
1491
- result0 = result;
1492
- result = result.replace(
1493
- new RegExp("^" + exports + "$", "gm"),
1494
- // disable $-escape in replacement-string
1495
- function () {
1496
- return data;
1497
- }
1498
- );
1499
- if (result0 === result) {
1500
- throw new Error(
1501
- "shRawLibFetch - cannot find-and-replace snippet "
1502
- + JSON.stringify(exports)
1503
- );
1504
- }
1505
- });
1506
- // init footer
1507
- result = header + result;
1508
- matchObj.input.replace((
1509
- /\n\/\*\nfile none\n\*\/\n\/\*jslint-enable\*\/\n([\S\s]+)/
1510
- ), function (ignore, match1) {
1511
- result += "\n\n" + match1.trim() + "\n";
1512
- });
1513
- // write to file
1514
- moduleFs.writeFileSync(process.argv[1], result); //jslint-quiet
1515
- });
1516
- }());
1517
- ' "$@" # '
1518
- git diff
1519
- )}
1520
-
1521
- shRmDsStore() {(set -e
1522
- # this function will recursively rm .DS_Store from current-dir
1523
- # http://stackoverflow.com/questions/2016844/bash-recursively-remove-files
1524
- local NAME
1525
- for NAME in "._*" ".DS_Store" "desktop.ini" "npm-debug.log" "*~"
1526
- do
1527
- find . -iname "$NAME" -print0 | xargs -0 rm -f || true
1528
- done
1529
- )}
1530
-
1531
- shRunWithCoverage() {(set -e
1532
- # this function will run nodejs command $@ with v8-coverage
1533
- # and create coverage-report .artifact/coverage/index.html
1534
- node --input-type=module --eval '
1535
- /*jslint indent2*/
1536
- let moduleChildProcess;
1537
- let moduleFs;
1538
- let moduleFsInitResolveList;
1539
- let modulePath;
1540
- let moduleUrl;
1541
- function assertOrThrow(condition, message) {
1542
- if (!condition) {
1543
- throw (
1544
- (!message || typeof message === "string")
1545
- ? new Error(String(message).slice(0, 2048))
1546
- : message
1547
- );
1548
- }
1549
- }
1550
- async function fsWriteFileWithParents(pathname, data) {
1551
- await moduleFsInit();
1552
- try {
1553
- await moduleFs.promises.writeFile(pathname, data);
1554
- } catch (ignore) {
1555
- await moduleFs.promises.mkdir(modulePath.dirname(pathname), {
1556
- recursive: true
1557
- });
1558
- await moduleFs.promises.writeFile(pathname, data);
1559
- }
1560
- console.error("wrote file " + pathname);
1561
- }
1562
- function htmlEscape(str) {
1563
- return String(str).replace((
1564
- /&/g
1565
- ), "&amp;").replace((
1566
- /</g
1567
- ), "&lt;").replace((
1568
- />/g
1569
- ), "&gt;");
1570
- }
1571
- async function moduleFsInit() {
1572
-
1573
- if (moduleFs !== undefined) {
1574
- return;
1575
- }
1576
- if (moduleFsInitResolveList !== undefined) {
1577
- return new Promise(function (resolve) {
1578
- moduleFsInitResolveList.push(resolve);
1579
- });
1580
- }
1581
- moduleFsInitResolveList = [];
1582
- [
1583
- moduleChildProcess,
1584
- moduleFs,
1585
- modulePath,
1586
- moduleUrl
1587
- ] = await Promise.all([
1588
- import("child_process"),
1589
- import("fs"),
1590
- import("path"),
1591
- import("url")
1592
- ]);
1593
- while (moduleFsInitResolveList.length > 0) {
1594
- moduleFsInitResolveList.shift()();
1595
- }
1596
- }
1597
- function v8CoverageListMerge(processCovs) {
1598
- let resultMerged = []; // List of merged scripts from processCovs.
1599
- let urlToScriptDict = new Map(); // Map scriptCov.url to scriptCovs.
1600
-
1601
- function compareRangeList(aa, bb) {
1602
- if (aa.startOffset !== bb.startOffset) {
1603
- return aa.startOffset - bb.startOffset;
1604
- }
1605
- return bb.endOffset - aa.endOffset;
1606
- }
1607
-
1608
- function dictKeyValueAppend(dict, key, val) {
1609
- let list = dict.get(key);
1610
- if (list === undefined) {
1611
- list = [];
1612
- dict.set(key, list);
1613
- }
1614
- list.push(val);
1615
- }
1616
-
1617
- function mergeTreeList(parentTrees) {
1618
- if (parentTrees.length <= 1) {
1619
- return parentTrees[0];
1620
- }
1621
- return {
1622
- children: mergeTreeListToChildren(parentTrees),
1623
- delta: parentTrees.reduce(function (aa, bb) {
1624
- return aa + bb.delta;
1625
- }, 0),
1626
- end: parentTrees[0].end,
1627
- start: parentTrees[0].start
1628
- };
1629
- }
1630
-
1631
- function mergeTreeListToChildren(parentTrees) {
1632
- let openRange;
1633
- let parentToChildDict = new Map(); // Map parent to child.
1634
- let queueList;
1635
- let queueListIi = 0;
1636
- let queueOffset;
1637
- let queueTrees;
1638
- let resultChildren = [];
1639
- let startToTreeDict = new Map(); // Map tree.start to tree.
1640
- function nextXxx() {
1641
- let [
1642
- nextOffset, nextTrees
1643
- ] = queueList[queueListIi] || [];
1644
- let openRangeEnd;
1645
- if (queueTrees === undefined) {
1646
- queueListIi += 1;
1647
- } else if (nextOffset === undefined || nextOffset > queueOffset) {
1648
- nextOffset = queueOffset;
1649
- nextTrees = queueTrees;
1650
- queueTrees = undefined;
1651
- } else {
1652
- if (nextOffset === queueOffset) {
1653
- queueTrees.forEach(function (tree) {
1654
- nextTrees.push(tree);
1655
- });
1656
- queueTrees = undefined;
1657
- }
1658
- queueListIi += 1;
1659
- }
1660
- if (nextOffset === undefined) {
1661
- if (openRange !== undefined) {
1662
- resultAppendNextChild();
1663
- }
1664
- return true;
1665
- }
1666
- if (openRange !== undefined && openRange.end <= nextOffset) {
1667
- resultAppendNextChild();
1668
- openRange = undefined;
1669
- }
1670
- if (openRange === undefined) {
1671
- openRangeEnd = nextOffset + 1;
1672
- nextTrees.forEach(function ({
1673
- parentIi,
1674
- tree
1675
- }) {
1676
- openRangeEnd = Math.max(openRangeEnd, tree.end);
1677
- dictKeyValueAppend(parentToChildDict, parentIi, tree);
1678
- });
1679
- queueOffset = openRangeEnd;
1680
- openRange = {
1681
- end: openRangeEnd,
1682
- start: nextOffset
1683
- };
1684
- } else {
1685
- nextTrees.forEach(function ({
1686
- parentIi,
1687
- tree
1688
- }) {
1689
- let right;
1690
- if (tree.end > openRange.end) {
1691
- right = treeSplit(tree, openRange.end);
1692
- if (queueTrees === undefined) {
1693
- queueTrees = [];
1694
- }
1695
- queueTrees.push({
1696
- parentIi,
1697
- tree: right
1698
- });
1699
- }
1700
- dictKeyValueAppend(parentToChildDict, parentIi, tree);
1701
- });
1702
- }
1703
- }
1704
- function resultAppendNextChild() {
1705
- let treesMatching = [];
1706
- parentToChildDict.forEach(function (nested) {
1707
- if (
1708
- nested.length === 1
1709
- && nested[0].start === openRange.start
1710
- && nested[0].end === openRange.end
1711
- ) {
1712
- treesMatching.push(nested[0]);
1713
- } else {
1714
- treesMatching.push({
1715
- children: nested,
1716
- delta: 0,
1717
- end: openRange.end,
1718
- start: openRange.start
1719
- });
1720
- }
1721
- });
1722
- parentToChildDict.clear();
1723
- resultChildren.push(mergeTreeList(treesMatching));
1724
- }
1725
- function treeSplit(tree, offset) {
1726
- let child;
1727
- let ii = 0;
1728
- let leftChildLen = tree.children.length;
1729
- let mid;
1730
- let resultTree;
1731
- let rightChildren;
1732
- while (ii < tree.children.length) {
1733
- child = tree.children[ii];
1734
- if (child.start < offset && offset < child.end) {
1735
- mid = treeSplit(child, offset);
1736
- leftChildLen = ii + 1;
1737
- break;
1738
- }
1739
- if (child.start >= offset) {
1740
- leftChildLen = ii;
1741
- break;
1742
- }
1743
- ii += 1;
1744
- }
1745
- rightChildren = tree.children.splice(
1746
- leftChildLen,
1747
- tree.children.length - leftChildLen
1748
- );
1749
- if (mid !== undefined) {
1750
- rightChildren.unshift(mid);
1751
- }
1752
- resultTree = {
1753
- children: rightChildren,
1754
- delta: tree.delta,
1755
- end: tree.end,
1756
- start: offset
1757
- };
1758
- tree.end = offset;
1759
- return resultTree;
1760
- }
1761
- parentTrees.forEach(function (parentTree, parentIi) {
1762
- parentTree.children.forEach(function (child) {
1763
- dictKeyValueAppend(startToTreeDict, child.start, {
1764
- parentIi,
1765
- tree: child
1766
- });
1767
- });
1768
- });
1769
- queueList = Array.from(startToTreeDict).map(function ([
1770
- startOffset, trees
1771
- ]) {
1772
- return [
1773
- startOffset, trees
1774
- ];
1775
- }).sort(function (aa, bb) {
1776
- return aa[0] - bb[0];
1777
- });
1778
- while (true) {
1779
- if (nextXxx()) {
1780
- break;
1781
- }
1782
- }
1783
- return resultChildren;
1784
- }
1785
-
1786
- function sortFunc(funcCov) {
1787
- funcCov.ranges = treeToRanges(treeFromSortedRanges(
1788
- funcCov.ranges.sort(compareRangeList)
1789
- ));
1790
- return funcCov;
1791
- }
1792
-
1793
- function sortScript(scriptCov) {
1794
-
1795
- scriptCov.functions.forEach(function (funcCov) {
1796
- sortFunc(funcCov);
1797
- });
1798
- scriptCov.functions.sort(function (aa, bb) {
1799
- return compareRangeList(aa.ranges[0], bb.ranges[0]);
1800
- });
1801
- return scriptCov;
1802
- }
1803
-
1804
- function treeFromSortedRanges(ranges) {
1805
- let root;
1806
- let stack = []; // Stack of parent trees and parent counts.
1807
- ranges.forEach(function (range) {
1808
- let node = {
1809
- children: [],
1810
- delta: range.count,
1811
- end: range.endOffset,
1812
- start: range.startOffset
1813
- };
1814
- let parent;
1815
- let parentCount;
1816
- if (root === undefined) {
1817
- root = node;
1818
- stack.push([
1819
- node, range.count
1820
- ]);
1821
- return;
1822
- }
1823
- while (true) {
1824
- [
1825
- parent, parentCount
1826
- ] = stack[stack.length - 1];
1827
- if (range.startOffset < parent.end) {
1828
- break;
1829
- }
1830
- stack.pop();
1831
- }
1832
- node.delta -= parentCount;
1833
- parent.children.push(node);
1834
- stack.push([
1835
- node, range.count
1836
- ]);
1837
- });
1838
- return root;
1839
- }
1840
-
1841
- function treeToRanges(tree) {
1842
- let count;
1843
- let cur;
1844
- let ii;
1845
- let parentCount;
1846
- let ranges = [];
1847
- let stack = [ // Stack of parent trees and counts.
1848
- [
1849
- tree, 0
1850
- ]
1851
- ];
1852
- function normalizeRange(tree) {
1853
- let children = [];
1854
- let curEnd;
1855
- let head;
1856
- let tail = [];
1857
- function endChain() {
1858
- if (tail.length !== 0) {
1859
- head.end = tail[tail.length - 1].end;
1860
- tail.forEach(function (tailTree) {
1861
- tailTree.children.forEach(function (subChild) {
1862
- subChild.delta += tailTree.delta - head.delta;
1863
- head.children.push(subChild);
1864
- });
1865
- });
1866
- tail.length = 0;
1867
- }
1868
- normalizeRange(head);
1869
- children.push(head);
1870
- }
1871
- tree.children.forEach(function (child) {
1872
- if (head === undefined) {
1873
- head = child;
1874
- } else if (
1875
- child.delta === head.delta && child.start === curEnd
1876
- ) {
1877
- tail.push(child);
1878
- } else {
1879
- endChain();
1880
- head = child;
1881
- }
1882
- curEnd = child.end;
1883
- });
1884
- if (head !== undefined) {
1885
- endChain();
1886
- }
1887
- if (children.length === 1) {
1888
- if (
1889
- children[0].start === tree.start
1890
- && children[0].end === tree.end
1891
- ) {
1892
- tree.delta += children[0].delta;
1893
- tree.children = children[0].children;
1894
- return;
1895
- }
1896
- }
1897
- tree.children = children;
1898
- }
1899
- normalizeRange(tree);
1900
- while (stack.length > 0) {
1901
- [
1902
- cur, parentCount
1903
- ] = stack.pop();
1904
- count = parentCount + cur.delta;
1905
- ranges.push({
1906
- count,
1907
- endOffset: cur.end,
1908
- startOffset: cur.start
1909
- });
1910
- ii = cur.children.length - 1;
1911
- while (ii >= 0) {
1912
- stack.push([
1913
- cur.children[ii], count
1914
- ]);
1915
- ii -= 1;
1916
- }
1917
- }
1918
- return ranges;
1919
- }
1920
-
1921
- if (processCovs.length === 0) {
1922
- return {
1923
- result: []
1924
- };
1925
- }
1926
- processCovs.forEach(function ({
1927
- result
1928
- }) {
1929
- result.forEach(function (scriptCov) {
1930
- dictKeyValueAppend(urlToScriptDict, scriptCov.url, scriptCov);
1931
- });
1932
- });
1933
- urlToScriptDict.forEach(function (scriptCovs) {
1934
-
1935
- let functions = [];
1936
- let rangeToFuncDict = new Map();
1937
- if (scriptCovs.length === 1) {
1938
- resultMerged.push(sortScript(scriptCovs[0]));
1939
- return;
1940
- }
1941
- scriptCovs.forEach(function ({
1942
- functions
1943
- }) {
1944
- functions.forEach(function (funcCov) {
1945
- dictKeyValueAppend(
1946
- rangeToFuncDict,
1947
- (
1948
- funcCov.ranges[0].startOffset
1949
- + ";" + funcCov.ranges[0].endOffset
1950
- ),
1951
- funcCov
1952
- );
1953
- });
1954
- });
1955
- rangeToFuncDict.forEach(function (funcCovs) {
1956
-
1957
- let count = 0;
1958
- let isBlockCoverage;
1959
- let merged;
1960
- let ranges;
1961
- let trees = [];
1962
- if (funcCovs.length === 1) {
1963
- functions.push(sortFunc(funcCovs[0]));
1964
- return;
1965
- }
1966
- funcCovs.forEach(function (funcCov) {
1967
- count += (
1968
- funcCov.count !== undefined
1969
- ? funcCov.count
1970
- : funcCov.ranges[0].count
1971
- );
1972
- if (funcCov.isBlockCoverage) {
1973
- trees.push(treeFromSortedRanges(funcCov.ranges));
1974
- }
1975
- });
1976
- if (trees.length > 0) {
1977
- isBlockCoverage = true;
1978
- ranges = treeToRanges(mergeTreeList(trees));
1979
- } else {
1980
- isBlockCoverage = false;
1981
- ranges = [
1982
- {
1983
- count,
1984
- endOffset: funcCovs[0].ranges[0].endOffset,
1985
- startOffset: funcCovs[0].ranges[0].startOffset
1986
- }
1987
- ];
1988
- }
1989
- merged = {
1990
- functionName: funcCovs[0].functionName,
1991
- isBlockCoverage,
1992
- ranges
1993
- };
1994
- if (count !== ranges[0].count) {
1995
- merged.count = count;
1996
- }
1997
- functions.push(merged);
1998
- });
1999
- resultMerged.push(sortScript({
2000
- functions,
2001
- scriptId: scriptCovs[0].scriptId,
2002
- url: scriptCovs[0].url
2003
- }));
2004
- });
2005
- Object.entries(resultMerged.sort(function (aa, bb) {
2006
- return (
2007
- aa.url > bb.url
2008
- ? 1
2009
- : -1
2010
- );
2011
- })).forEach(function ([
2012
- scriptId, scriptCov
2013
- ]) {
2014
- scriptCov.scriptId = scriptId.toString(10);
2015
- });
2016
- return {
2017
- result: resultMerged
2018
- };
2019
- }
2020
- async function v8CoverageReportCreate({
2021
- consoleError,
2022
- coverageDir,
2023
- processArgv = []
2024
- }) {
2025
- let cwd;
2026
- let exitCode = 0;
2027
- let fileDict;
2028
- let fileExcludeList = [];
2029
- let fileIncludeList = [];
2030
- let fileIncludeNodeModules;
2031
- let processArgElem;
2032
- let promiseList = [];
2033
- let v8CoverageObj;
2034
-
2035
- function htmlRender({
2036
- fileList,
2037
- lineList,
2038
- modeIndex,
2039
- pathname
2040
- }) {
2041
- let html;
2042
- let padLines;
2043
- let padPathname;
2044
- let txt;
2045
- let txtBorder;
2046
- html = "";
2047
- html += String(`
2048
- <!DOCTYPE html>
2049
- <html lang="en">
2050
- <head>
2051
- <title>V8 Coverage Report</title>
2052
- <style>
2053
- /* jslint utility2:true */
2054
- /*csslint ignore:start*/
2055
- * {
2056
- box-sizing: border-box;
2057
- font-family: consolas, menlo, monospace;
2058
- }
2059
- /*csslint ignore:end*/
2060
-
2061
- /* css - coverage_report - general */
2062
- body {
2063
- margin: 0;
2064
- }
2065
- .coverage pre {
2066
- margin: 5px 0;
2067
- }
2068
- .coverage table {
2069
- border-collapse: collapse;
2070
- }
2071
- .coverage td,
2072
- .coverage th {
2073
- border: 1px solid #777;
2074
- line-height: 20px;
2075
- margin: 0;
2076
- padding: 5px 10px;
2077
- }
2078
- .coverage td span {
2079
- display: inline-block;
2080
- width: 100%;
2081
- }
2082
- .coverage .content {
2083
- padding: 0 5px;
2084
- }
2085
- .coverage .content a {
2086
- text-decoration: none;
2087
- }
2088
- .coverage .count {
2089
- margin: 0 5px;
2090
- padding: 0 5px;
2091
- }
2092
- .coverage .footer,
2093
- .coverage .header {
2094
- padding: 20px;
2095
- }
2096
- .coverage .footer {
2097
- text-align: center;
2098
- }
2099
- .coverage .percentbar {
2100
- height: 12px;
2101
- margin: 2px 0;
2102
- min-width: 200px;
2103
- position: relative;
2104
- width: 100%;
2105
- }
2106
- .coverage .percentbar div {
2107
- height: 100%;
2108
- position: absolute;
2109
- }
2110
- .coverage .title {
2111
- font-size: large;
2112
- font-weight: bold;
2113
- margin-bottom: 10px;
2114
- }
2115
-
2116
- /* css - coverage_report - color */
2117
- .coverage td,
2118
- .coverage th {
2119
- background: #fff;
2120
- }
2121
- .coverage .count,
2122
- .coverage .coverageHigh {
2123
- background: #9d9;
2124
- }
2125
- .coverage .count {
2126
- color: #666;
2127
- }
2128
- .coverage .coverageIgnore {
2129
- background: #ccc;
2130
- }
2131
- .coverage .coverageLow,
2132
- .coverage .uncovered {
2133
- background: #ebb;
2134
- }
2135
- .coverage .coverageMedium {
2136
- background: #fd7;
2137
- }
2138
- .coverage .footer,
2139
- .coverage .header,
2140
- .coverage .lineno {
2141
- background: #ddd;
2142
- }
2143
- .coverage .percentbar {
2144
- background: #999;
2145
- }
2146
- .coverage .percentbar div {
2147
- background: #666;
2148
- }
2149
-
2150
- /* css - coverage_report - important */
2151
- .coverage pre:hover span,
2152
- .coverage tr:hover td {
2153
- background: #7d7;
2154
- }
2155
- .coverage pre:hover span.uncovered,
2156
- .coverage tr:hover td.coverageLow {
2157
- background: #f99;
2158
- }
2159
- </style>
2160
- </head>
2161
- <body class="coverage">
2162
- <!-- header start -->
2163
- <div class="header">
2164
- <div class="title">V8 Coverage Report</div>
2165
- <table>
2166
- <thead>
2167
- <tr>
2168
- <th>Files covered</th>
2169
- <th>Lines</th>
2170
- <th>Remaining</th>
2171
- </tr>
2172
- </thead>
2173
- <tbody>
2174
- `).trim() + "\n";
2175
- if (modeIndex) {
2176
- padLines = String("(ignore) 100.00 %").length;
2177
- padPathname = 32;
2178
- fileList.unshift({
2179
- linesCovered: 0,
2180
- linesTotal: 0,
2181
- modeCoverageIgnoreFile: "",
2182
- pathname: "./"
2183
- });
2184
- fileList.slice(1).forEach(function ({
2185
- linesCovered,
2186
- linesTotal,
2187
- modeCoverageIgnoreFile,
2188
- pathname
2189
- }) {
2190
- if (!modeCoverageIgnoreFile) {
2191
- fileList[0].linesCovered += linesCovered;
2192
- fileList[0].linesTotal += linesTotal;
2193
- }
2194
- padPathname = Math.max(padPathname, pathname.length + 2);
2195
- padLines = Math.max(
2196
- padLines,
2197
- String(linesCovered + " / " + linesTotal).length
2198
- );
2199
- });
2200
- }
2201
- txtBorder = (
2202
- "+" + "-".repeat(padPathname + 2) + "+"
2203
- + "-".repeat(padLines + 2) + "+\n"
2204
- );
2205
- txt = "";
2206
- txt += "V8 Coverage Report\n";
2207
- txt += txtBorder;
2208
- txt += (
2209
- "| " + String("Files covered").padEnd(padPathname, " ") + " | "
2210
- + String("Lines").padStart(padLines, " ") + " |\n"
2211
- );
2212
- txt += txtBorder;
2213
- fileList.forEach(function ({
2214
- linesCovered,
2215
- linesTotal,
2216
- modeCoverageIgnoreFile,
2217
- pathname
2218
- }, ii) {
2219
- let coverageLevel;
2220
- let coveragePct;
2221
- let fill;
2222
- let str1;
2223
- let str2;
2224
- let xx1;
2225
- let xx2;
2226
- coveragePct = Math.floor(10000 * linesCovered / linesTotal || 0);
2227
- coverageLevel = (
2228
- modeCoverageIgnoreFile
2229
- ? "coverageIgnore"
2230
- : coveragePct >= 8000
2231
- ? "coverageHigh"
2232
- : coveragePct >= 5000
2233
- ? "coverageMedium"
2234
- : "coverageLow"
2235
- );
2236
- coveragePct = String(coveragePct).replace((
2237
- /..$/m
2238
- ), ".$&");
2239
- if (modeIndex && ii === 0) {
2240
- fill = (
2241
- "#" + Math.round(
2242
- (100 - Number(coveragePct)) * 2.21
2243
- ).toString(16).padStart(2, "0")
2244
- + Math.round(
2245
- Number(coveragePct) * 2.21
2246
- ).toString(16).padStart(2, "0")
2247
- + "00"
2248
- );
2249
- str1 = "coverage";
2250
- str2 = coveragePct + " %";
2251
- xx1 = 6 * str1.length + 20;
2252
- xx2 = 6 * str2.length + 20;
2253
- promiseList.push(fsWriteFileWithParents((
2254
- coverageDir + "coverage_badge.svg"
2255
- ), String(`
2256
- <svg height="20" width="${xx1 + xx2}" xmlns="http://www.w3.org/2000/svg">
2257
- <rect fill="#555" height="20" width="${xx1 + xx2}"/>
2258
- <rect fill="${fill}" height="20" width="${xx2}" x="${xx1}"/>
2259
- <g
2260
- fill="#fff"
2261
- font-family="verdana, geneva, dejavu sans, sans-serif"
2262
- font-size="11"
2263
- font-weight="bold"
2264
- text-anchor="middle"
2265
- >
2266
- <text x="${0.5 * xx1}" y="14">${str1}</text>
2267
- <text x="${xx1 + 0.5 * xx2}" y="14">${str2}</text>
2268
- </g>
2269
- </svg>
2270
- `).trim() + "\n"));
2271
- pathname = "";
2272
- }
2273
- txt += (
2274
- "| "
2275
- + String("./" + pathname).padEnd(padPathname, " ") + " | "
2276
- + String(
2277
- modeCoverageIgnoreFile + " " + coveragePct + " %"
2278
- ).padStart(padLines, " ") + " |\n"
2279
- );
2280
- txt += (
2281
- "| " + "*".repeat(
2282
- Math.round(0.01 * coveragePct * padPathname)
2283
- ).padEnd(padPathname, "_") + " | "
2284
- + String(
2285
- linesCovered + " / " + linesTotal
2286
- ).padStart(padLines, " ") + " |\n"
2287
- );
2288
- txt += txtBorder;
2289
- pathname = htmlEscape(pathname);
2290
- html += String(`
2291
- <tr>
2292
- <td class="${coverageLevel}">
2293
- ${(
2294
- modeIndex
2295
- ? (
2296
- "<a href=\"" + (pathname || "index") + ".html\">. / "
2297
- + pathname + "</a><br>"
2298
- )
2299
- : (
2300
- "<a href=\""
2301
- + "../".repeat(pathname.split("/").length - 1)
2302
- + "index.html\">. / </a>"
2303
- + pathname + "<br>"
2304
- )
2305
- )}
2306
- <div class="percentbar">
2307
- <div style="width: ${coveragePct}%;"></div>
2308
- </div>
2309
- </td>
2310
- <td style="text-align: right;">
2311
- ${modeCoverageIgnoreFile} ${coveragePct} %<br>
2312
- ${linesCovered} / ${linesTotal}
2313
- </td>
2314
- <td style="text-align: right;">
2315
- <br>
2316
- ${linesTotal - linesCovered} / ${linesTotal}
2317
- </td>
2318
- </tr>
2319
- `).trim() + "\n";
2320
- });
2321
- html += String(`
2322
- </tbody>
2323
- </table>
2324
- </div>
2325
- <!-- header end -->
2326
- `).trim() + "\n";
2327
- if (!modeIndex) {
2328
- html += String(`
2329
- <!-- content start -->
2330
- <div class="content">
2331
- `).trim() + "\n";
2332
- lineList.forEach(function ({
2333
- count,
2334
- holeList,
2335
- line,
2336
- startOffset
2337
- }, ii) {
2338
- let chunk;
2339
- let inHole;
2340
- let lineHtml;
2341
- let lineId;
2342
- lineHtml = "";
2343
- lineId = "line_" + (ii + 1);
2344
- switch (count) {
2345
- case -1:
2346
- case 0:
2347
- if (holeList.length === 0) {
2348
- lineHtml += "</span>";
2349
- lineHtml += "<span class=\"uncovered\">";
2350
- lineHtml += htmlEscape(line);
2351
- break;
2352
- }
2353
- line = line.split("").map(function (char) {
2354
- return {
2355
- char,
2356
- isHole: undefined
2357
- };
2358
- });
2359
- holeList.forEach(function ([
2360
- aa, bb
2361
- ]) {
2362
- aa = Math.max(aa - startOffset, 0);
2363
- bb = Math.min(bb - startOffset, line.length);
2364
- while (aa < bb) {
2365
- line[aa].isHole = true;
2366
- aa += 1;
2367
- }
2368
- });
2369
- chunk = "";
2370
- line.forEach(function ({
2371
- char,
2372
- isHole
2373
- }) {
2374
- if (inHole !== isHole) {
2375
- lineHtml += htmlEscape(chunk);
2376
- lineHtml += "</span><span";
2377
- if (isHole) {
2378
- lineHtml += " class=\"uncovered\"";
2379
- }
2380
- lineHtml += ">";
2381
- chunk = "";
2382
- inHole = isHole;
2383
- }
2384
- chunk += char;
2385
- });
2386
- lineHtml += htmlEscape(chunk);
2387
- break;
2388
- default:
2389
- lineHtml += htmlEscape(line);
2390
- }
2391
- html += String(`
2392
- <pre>
2393
- <span class="lineno">
2394
- <a href="#${lineId}" id="${lineId}">${String(ii + 1).padStart(5, " ")}.</a>
2395
- </span>
2396
- <span class="count
2397
- ${(
2398
- count <= 0
2399
- ? "uncovered"
2400
- : ""
2401
- )}"
2402
- >
2403
- ${String(count || "-0").padStart(7, " ")}
2404
- </span>
2405
- <span>${lineHtml}</span>
2406
- </pre>
2407
- `).replace((
2408
- /\n/g
2409
- ), "").trim() + "\n";
2410
- });
2411
- html += String(`
2412
- </div>
2413
- <!-- content end -->
2414
- `).trim() + "\n";
2415
- }
2416
- html += String(`
2417
- <div class="footer">
2418
- [
2419
- This document was created with
2420
- <a href="https://github.com/jslint-org/jslint">JSLint</a>
2421
- ]
2422
- </div>
2423
- </body>
2424
- </html>
2425
- `).trim() + "\n";
2426
- promiseList.push(fsWriteFileWithParents(pathname + ".html", html));
2427
- if (!modeIndex) {
2428
- return;
2429
- }
2430
- consoleError("\n" + txt);
2431
- promiseList.push(fsWriteFileWithParents((
2432
- coverageDir + "coverage_report.txt"
2433
- ), txt));
2434
- }
2435
-
2436
- function pathnameRelativeCwd(pathname) {
2437
- pathname = modulePath.resolve(pathname).replace((
2438
- /\\/g
2439
- ), "/");
2440
- if (!pathname.startsWith(cwd)) {
2441
- return;
2442
- }
2443
- pathname = pathname.slice(cwd.length);
2444
- return pathname;
2445
- }
2446
-
2447
- /*
2448
- function sentinel() {}
2449
- */
2450
-
2451
- await moduleFsInit();
2452
- consoleError = consoleError || console.error;
2453
- cwd = process.cwd().replace((
2454
- /\\/g
2455
- ), "/") + "/";
2456
- assertOrThrow(coverageDir, "invalid coverageDir " + coverageDir);
2457
- coverageDir = modulePath.resolve(coverageDir).replace((
2458
- /\\/g
2459
- ), "/") + "/";
2460
-
2461
- processArgv = processArgv.slice();
2462
- while (processArgv[0] && processArgv[0][0] === "-") {
2463
- processArgElem = processArgv.shift().split("=");
2464
- processArgElem[1] = processArgElem.slice(1).join("=");
2465
- switch (processArgElem[0]) {
2466
- case "--exclude":
2467
- fileExcludeList = fileExcludeList.concat(
2468
- processArgElem[1].split(",")
2469
- );
2470
- break;
2471
- case "--exclude-node-modules":
2472
- fileIncludeNodeModules = (
2473
- /0|false|null|undefined/
2474
- ).test(processArgElem[1]);
2475
- break;
2476
- case "--include":
2477
- fileIncludeList = fileIncludeList.concat(
2478
- processArgElem[1].split(",")
2479
- );
2480
- break;
2481
- }
2482
- }
2483
- if (processArgv.length > 0) {
2484
- await fsWriteFileWithParents(coverageDir + "/touch.txt", "");
2485
- await Promise.all(Array.from(
2486
- await moduleFs.promises.readdir(coverageDir)
2487
- ).map(async function (file) {
2488
- if ((
2489
- /^coverage-\d+?-\d+?-\d+?\.json$/
2490
- ).test(file)) {
2491
- console.error("rm file " + coverageDir + file);
2492
- await moduleFs.promises.unlink(coverageDir + file);
2493
- }
2494
- }));
2495
- exitCode = await new Promise(function (resolve) {
2496
- moduleChildProcess.spawn((
2497
- processArgv[0] === "npm"
2498
- ? process.platform.replace("win32", "npm.cmd").replace(
2499
- process.platform,
2500
- "npm"
2501
- )
2502
- : processArgv[0]
2503
- ), processArgv.slice(1), {
2504
- env: Object.assign({}, process.env, {
2505
- NODE_V8_COVERAGE: coverageDir
2506
- }),
2507
- stdio: [
2508
- "ignore", 1, 2
2509
- ]
2510
- }).on("exit", resolve);
2511
- });
2512
- }
2513
- v8CoverageObj = await moduleFs.promises.readdir(coverageDir);
2514
- v8CoverageObj = v8CoverageObj.filter(function (file) {
2515
- return (
2516
- /^coverage-\d+?-\d+?-\d+?\.json$/
2517
- ).test(file);
2518
- });
2519
- v8CoverageObj = await Promise.all(v8CoverageObj.map(async function (file) {
2520
- let data = await moduleFs.promises.readFile(coverageDir + file, "utf8");
2521
- data = JSON.parse(data);
2522
- data.result = data.result.filter(function (scriptCov) {
2523
- let pathname = scriptCov.url;
2524
- if (!pathname.startsWith("file:///")) {
2525
- return;
2526
- }
2527
- pathname = pathnameRelativeCwd(moduleUrl.fileURLToPath(pathname));
2528
- if (
2529
- !pathname
2530
- || pathname.startsWith("[")
2531
- || (
2532
- !fileIncludeNodeModules
2533
- && (
2534
- /(?:^|\/)node_modules\//m
2535
- ).test(pathname)
2536
- )
2537
- || fileExcludeList.indexOf(pathname) >= 0
2538
- || (
2539
- fileIncludeList.length > 0
2540
- && fileIncludeList.indexOf(pathname) === -1
2541
- )
2542
- ) {
2543
- return;
2544
- }
2545
- scriptCov.url = pathname;
2546
- return true;
2547
- });
2548
- return data;
2549
- }));
2550
- v8CoverageObj = v8CoverageListMerge(v8CoverageObj);
2551
- await fsWriteFileWithParents(
2552
- coverageDir + "v8_coverage_merged.json",
2553
- JSON.stringify(v8CoverageObj, undefined, 1)
2554
- );
2555
- fileDict = {};
2556
- await Promise.all(v8CoverageObj.result.map(async function ({
2557
- functions,
2558
- url: pathname
2559
- }) {
2560
- let lineList;
2561
- let linesCovered;
2562
- let linesTotal;
2563
- let source;
2564
- source = await moduleFs.promises.readFile(pathname, "utf8");
2565
- lineList = [{}];
2566
- source.replace((
2567
- /^.*$/gm
2568
- ), function (line, startOffset) {
2569
- lineList[lineList.length - 1].endOffset = startOffset - 1;
2570
- lineList.push({
2571
- count: -1,
2572
- endOffset: 0,
2573
- holeList: [],
2574
- line,
2575
- startOffset
2576
- });
2577
- return "";
2578
- });
2579
- lineList.shift();
2580
- lineList[lineList.length - 1].endOffset = source.length;
2581
- functions.reverse().forEach(function ({
2582
- ranges
2583
- }) {
2584
- ranges.reverse().forEach(function ({
2585
- count,
2586
- endOffset,
2587
- startOffset
2588
- }, ii, list) {
2589
- lineList.forEach(function (elem) {
2590
- if (!(
2591
- (
2592
- elem.startOffset <= startOffset
2593
- && startOffset <= elem.endOffset
2594
- ) || (
2595
- elem.startOffset <= endOffset
2596
- && endOffset <= elem.endOffset
2597
- ) || (
2598
- startOffset <= elem.startOffset
2599
- && elem.endOffset <= endOffset
2600
- )
2601
- )) {
2602
- return;
2603
- }
2604
- if (ii + 1 === list.length) {
2605
- if (elem.count === -1) {
2606
- elem.count = count;
2607
- }
2608
- return;
2609
- }
2610
- if (elem.count !== 0) {
2611
- elem.count = Math.max(count, elem.count);
2612
- }
2613
- if (count === 0) {
2614
- elem.count = 0;
2615
- elem.holeList.push([
2616
- startOffset, endOffset
2617
- ]);
2618
- }
2619
- });
2620
- });
2621
- });
2622
- linesTotal = lineList.length;
2623
- linesCovered = lineList.filter(function ({
2624
- count
2625
- }) {
2626
- return count > 0;
2627
- }).length;
2628
- await moduleFs.promises.mkdir((
2629
- modulePath.dirname(coverageDir + pathname)
2630
- ), {
2631
- recursive: true
2632
- });
2633
- fileDict[pathname] = {
2634
- lineList,
2635
- linesCovered,
2636
- linesTotal,
2637
- modeCoverageIgnoreFile: (
2638
- (
2639
- /^\/\*coverage-ignore-file\*\/$/m
2640
- ).test(source.slice(0, 65536))
2641
- ? "(ignore)"
2642
- : ""
2643
- ),
2644
- pathname
2645
- };
2646
- htmlRender({
2647
- fileList: [
2648
- fileDict[pathname]
2649
- ],
2650
- lineList,
2651
- pathname: coverageDir + pathname
2652
- });
2653
- }));
2654
- htmlRender({
2655
- fileList: Object.keys(fileDict).sort().map(function (pathname) {
2656
- return fileDict[pathname];
2657
- }),
2658
- modeIndex: true,
2659
- pathname: coverageDir + "index"
2660
- });
2661
- await Promise.all(promiseList);
2662
- assertOrThrow(
2663
- exitCode === 0,
2664
- "v8CoverageReportCreate - nonzero exitCode " + exitCode
2665
- );
2666
- }
2667
- v8CoverageReportCreate({
2668
- coverageDir: ".artifact/coverage",
2669
- processArgv: process.argv.slice(2)
2670
- });
2671
- ' 0 "$@" # '
2672
- )}
2673
-
2674
- shRunWithScreenshotTxt() {(set -e
2675
- # this function will run cmd $@ and screenshot text-output
2676
- # https://www.cnx-software.com/2011/09/22/how-to-convert-a-command-line-result-into-an-image-in-linux/
2677
- local EXIT_CODE
2678
- EXIT_CODE=0
2679
- export SCREENSHOT_SVG="$1"
2680
- shift
2681
- printf "0\n" > "$SCREENSHOT_SVG.exit_code"
2682
- printf "shRunWithScreenshotTxt - ($* 2>&1)\n" 1>&2
2683
- # run "$@" with screenshot
2684
- (set -e
2685
- "$@" 2>&1 || printf "$?\n" > "$SCREENSHOT_SVG.exit_code"
2686
- ) | tee "$SCREENSHOT_SVG.txt"
2687
- EXIT_CODE="$(cat "$SCREENSHOT_SVG.exit_code")"
2688
- printf "shRunWithScreenshotTxt - EXIT_CODE=$EXIT_CODE - $SCREENSHOT_SVG\n" \
2689
- 1>&2
2690
- # format text-output
2691
- node --input-type=module --eval '
2692
- import moduleFs from "fs";
2693
- (async function () {
2694
- let result = await moduleFs.promises.readFile(
2695
- process.argv[1] + ".txt",
2696
- "utf8"
2697
- );
2698
- let yy = 10;
2699
- // remove ansi escape-code
2700
- result = result.replace((
2701
- /\u001b.*?m/g
2702
- ), "");
2703
- /*
2704
- // format unicode
2705
- result = result.replace((
2706
- /\\u[0-9a-f]{4}/g
2707
- ), function (match0) {
2708
- return String.fromCharCode("0x" + match0.slice(-4));
2709
- });
2710
- */
2711
- // normalize "\r\n"
2712
- result = result.replace((
2713
- /\r\n?/
2714
- ), "\n").trimEnd();
2715
- // 96-column wordwrap
2716
- result = result.split("\n").map(function (line) {
2717
- let wordwrap = line.slice(0, 96).padEnd(96, " ");
2718
- line = line.slice(96);
2719
- while (line) {
2720
- wordwrap += "\\\n " + line.slice(0, 96 - 2).padEnd(96 - 2, " ");
2721
- line = line.slice(96 - 2);
2722
- }
2723
- return wordwrap + " ";
2724
- }).join("\n");
2725
- // html-escape
2726
- result = result.replace((
2727
- /&/g
2728
- ), "&amp;").replace((
2729
- /</g
2730
- ), "&lt;").replace((
2731
- />/g
2732
- ), "&gt;");
2733
- // convert text to svg-tspan
2734
- result = result.split("\n").map(function (line) {
2735
- yy += 22;
2736
- return `<tspan
2737
- lengthAdjust="spacingAndGlyphs"
2738
- textLength="${96 * 8}"
2739
- x="10"
2740
- y="${yy}"
2741
- >${line}</tspan>\n`;
2742
- }).join("");
2743
- result = String(`
2744
- <svg height="${yy + 20}" width="800" xmlns="http://www.w3.org/2000/svg">
2745
- <rect height="${yy + 20}" fill="#222" width="800"></rect>
2746
- <text
2747
- fill="#7f7"
2748
- font-family="consolas, menlo, monospace"
2749
- font-size="14"
2750
- xml:space="preserve"
2751
- >
2752
- ${result}
2753
- </text>
2754
- </svg>
2755
- `).trim() + "\n";
2756
- moduleFs.promises.writeFile(process.argv[1], result);
2757
- }());
2758
- ' "$SCREENSHOT_SVG" # '
2759
- printf "shRunWithScreenshotTxt - wrote - $SCREENSHOT_SVG\n"
2760
- # cleanup
2761
- rm "$SCREENSHOT_SVG.exit_code" "$SCREENSHOT_SVG.txt"
2762
- return "$EXIT_CODE"
2763
- )}
2764
-
2765
- shCiMain() {(set -e
2766
- # this function will run $@
2767
- if [ "$1" = "" ]
2768
- then
2769
- return
2770
- fi
2771
- # run "$@" with winpty
2772
- export CI_UNAME="${CI_UNAME:-$(uname)}"
2773
- case "$CI_UNAME" in
2774
- MSYS*)
2775
- if [ ! "$CI_WINPTY" ] && [ "$1" != shHttpFileServer ]
2776
- then
2777
- export CI_WINPTY=1
2778
- winpty -Xallow-non-tty -Xplain sh "$0" "$@"
2779
- return
2780
- fi
2781
- ;;
2782
- esac
2783
- # run "$@"
2784
- export NODE_OPTIONS="--unhandled-rejections=strict"
2785
- if [ -f ./.ci.sh ]
2786
- then
2787
- . ./.ci.sh "$@"
2788
- fi
2789
- "$@"
2790
- )}
2791
-
2792
- # init ubuntu .bashrc
2793
- shBashrcDebianInit || return "$?"
2794
-
2795
- shCiMain "$@"