sqlmath 0.0.1 → 0.0.2

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.
Files changed (100) hide show
  1. package/.gitconfig +2 -2
  2. package/.github/workflows/ci.yml +73 -15
  3. package/.github/workflows/publish.yml +66 -0
  4. package/.gitignore +1 -5
  5. package/CHANGELOG.md +53 -2
  6. package/LICENSE +16 -22
  7. package/README.md +18 -219
  8. package/asset_image_folder_open_solid.svg +1 -0
  9. package/jslint.mjs +10998 -0
  10. package/jslint_ci.sh +1542 -728
  11. package/package.json +23 -8
  12. package/{sqlite-autoconf-3360000/sqlite3.c → sqlite3.c} +13116 -85
  13. package/sqlite3_ext.c +8372 -0
  14. package/{sqlite-autoconf-3360000/shell.c → sqlite3_shell.c} +330 -275
  15. package/sqlmath.mjs +1713 -0
  16. package/sqlmath_base.c +1832 -0
  17. package/sqlmath_custom.c +78 -0
  18. package/sqlmath_custom.cpp +0 -0
  19. package/sqlmath_custom.mjs +4 -0
  20. package/sqlmath_old.js +31038 -0
  21. package/extension-functions.c +0 -2047
  22. package/node_sqlite3.cc +0 -11877
  23. package/sqlite-autoconf-3360000/INSTALL +0 -370
  24. package/sqlite-autoconf-3360000/Makefile.am +0 -20
  25. package/sqlite-autoconf-3360000/Makefile.fallback +0 -19
  26. package/sqlite-autoconf-3360000/Makefile.in +0 -1028
  27. package/sqlite-autoconf-3360000/Makefile.msc +0 -1037
  28. package/sqlite-autoconf-3360000/README.txt +0 -113
  29. package/sqlite-autoconf-3360000/Replace.cs +0 -223
  30. package/sqlite-autoconf-3360000/aclocal.m4 +0 -10199
  31. package/sqlite-autoconf-3360000/compile +0 -347
  32. package/sqlite-autoconf-3360000/config.guess +0 -1480
  33. package/sqlite-autoconf-3360000/config.sub +0 -1801
  34. package/sqlite-autoconf-3360000/configure +0 -16135
  35. package/sqlite-autoconf-3360000/configure.ac +0 -285
  36. package/sqlite-autoconf-3360000/depcomp +0 -791
  37. package/sqlite-autoconf-3360000/install-sh +0 -508
  38. package/sqlite-autoconf-3360000/ltmain.sh +0 -11156
  39. package/sqlite-autoconf-3360000/missing +0 -215
  40. package/sqlite-autoconf-3360000/sqlite3.1 +0 -286
  41. package/sqlite-autoconf-3360000/sqlite3.h +0 -12353
  42. package/sqlite-autoconf-3360000/sqlite3.pc.in +0 -13
  43. package/sqlite-autoconf-3360000/sqlite3.rc +0 -83
  44. package/sqlite-autoconf-3360000/sqlite3ext.h +0 -663
  45. package/sqlite-autoconf-3360000/sqlite3rc.h +0 -3
  46. package/sqlite-autoconf-3360000/tea/Makefile.in +0 -440
  47. package/sqlite-autoconf-3360000/tea/README +0 -36
  48. package/sqlite-autoconf-3360000/tea/aclocal.m4 +0 -9
  49. package/sqlite-autoconf-3360000/tea/configure +0 -9989
  50. package/sqlite-autoconf-3360000/tea/configure.ac +0 -201
  51. package/sqlite-autoconf-3360000/tea/doc/sqlite3.n +0 -15
  52. package/sqlite-autoconf-3360000/tea/generic/tclsqlite3.c +0 -4016
  53. package/sqlite-autoconf-3360000/tea/license.terms +0 -6
  54. package/sqlite-autoconf-3360000/tea/pkgIndex.tcl.in +0 -7
  55. package/sqlite-autoconf-3360000/tea/tclconfig/install-sh +0 -528
  56. package/sqlite-autoconf-3360000/tea/tclconfig/tcl.m4 +0 -4168
  57. package/sqlite-autoconf-3360000/tea/win/makefile.vc +0 -419
  58. package/sqlite-autoconf-3360000/tea/win/nmakehlp.c +0 -815
  59. package/sqlite-autoconf-3360000/tea/win/rules.vc +0 -711
  60. package/sqlmath.js +0 -238
  61. package/test/backup.test.js +0 -279
  62. package/test/blob.test.js +0 -54
  63. package/test/cache.test.js +0 -42
  64. package/test/constants.test.js +0 -44
  65. package/test/database_fail.test.js +0 -153
  66. package/test/each.test.js +0 -39
  67. package/test/exec.test.js +0 -39
  68. package/test/extension.test.js +0 -26
  69. package/test/extension_functions.test.js +0 -29
  70. package/test/fts-content.test.js +0 -13
  71. package/test/interrupt.test.js +0 -80
  72. package/test/issue-108.test.js +0 -28
  73. package/test/json.test.js +0 -22
  74. package/test/map.test.js +0 -63
  75. package/test/named_columns.test.js +0 -38
  76. package/test/named_params.test.js +0 -69
  77. package/test/null_error.test.js +0 -41
  78. package/test/nw/.gitignore +0 -3
  79. package/test/nw/Makefile +0 -39
  80. package/test/nw/index.html +0 -14
  81. package/test/nw/package.json +0 -9
  82. package/test/open_close.test.js +0 -187
  83. package/test/other_objects.test.js +0 -98
  84. package/test/parallel_insert.test.js +0 -44
  85. package/test/prepare.test.js +0 -427
  86. package/test/profile.test.js +0 -57
  87. package/test/rerun.test.js +0 -50
  88. package/test/scheduling.test.js +0 -44
  89. package/test/serialization.test.js +0 -104
  90. package/test/support/createdb-electron.js +0 -10
  91. package/test/support/createdb.js +0 -47
  92. package/test/support/elmo.png +0 -0
  93. package/test/support/helper.js +0 -37
  94. package/test/support/script.sql +0 -70
  95. package/test/trace.test.js +0 -67
  96. package/test/unicode.test.js +0 -114
  97. package/test/upsert.test.js +0 -27
  98. package/test/verbose.test.js +0 -60
  99. package/test.js +0 -141
  100. package/test.slr.mjs +0 -212
package/jslint_ci.sh CHANGED
@@ -5,7 +5,7 @@
5
5
  # http://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
6
6
 
7
7
  # sh one-liner
8
- #
8
+ # git add .; npm run test2; git checkout .
9
9
  # git branch -d -r origin/aa
10
10
  # git config --global diff.algorithm histogram
11
11
  # git fetch origin alpha beta master && git fetch upstream alpha beta master
@@ -18,13 +18,131 @@
18
18
  # ln -f jslint.mjs ~/jslint.mjs
19
19
  # openssl rand -base64 32 # random key
20
20
  # sh jslint_ci.sh shCiBranchPromote origin alpha beta
21
- # sh jslint_ci.sh shRunWithScreenshotTxt .build/screenshot-changelog.svg head -n50 CHANGELOG.md
21
+ # sh jslint_ci.sh shRunWithScreenshotTxt .artifact/screenshot_changelog.svg head -n50 CHANGELOG.md
22
22
  # vim rgx-lowercase \L\1\e
23
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
+
24
142
  shBrowserScreenshot() {(set -e
25
143
  # this function will run headless-chrome to screenshot url $1 with
26
144
  # window-size $2
27
- node --input-type=module -e '
145
+ node --input-type=module --eval '
28
146
  import moduleChildProcess from "child_process";
29
147
  import modulePath from "path";
30
148
  import moduleUrl from "url";
@@ -41,7 +159,9 @@ import moduleUrl from "url";
41
159
  return argList[0];
42
160
  };
43
161
  }());
44
- (function () {
162
+ (async function () {
163
+ let child;
164
+ let exitCode;
45
165
  let file;
46
166
  let timeStart;
47
167
  let url;
@@ -60,10 +180,10 @@ import moduleUrl from "url";
60
180
  if (String(file + "/").startsWith(process.cwd() + "/")) {
61
181
  file = file.replace(process.cwd(), "");
62
182
  }
63
- file = ".build/screenshot-browser-" + encodeURIComponent(file).replace((
183
+ file = ".artifact/screenshot_browser_" + encodeURIComponent(file).replace((
64
184
  /%/g
65
185
  ), "_").toLowerCase() + ".png";
66
- moduleChildProcess.spawn(
186
+ child = moduleChildProcess.spawn(
67
187
  (
68
188
  process.platform === "darwin"
69
189
  ? "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
@@ -96,71 +216,64 @@ import moduleUrl from "url";
96
216
  "ignore", 1, 2
97
217
  ]
98
218
  }
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
- );
219
+ );
220
+ exitCode = await new Promise(function (resolve) {
221
+ child.on("exit", resolve);
107
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
+ );
108
230
  }());
109
- ' "$@" # "'
231
+ ' "$@" # '
110
232
  )}
111
233
 
112
234
  shCiArtifactUpload() {(set -e
113
235
  # this function will upload build-artifacts to branch-gh-pages
114
236
  local BRANCH
115
- local SIZE
116
- node --input-type=module -e '
237
+ local FILE
238
+ node --input-type=module --eval '
117
239
  process.exit(Number(
118
- `${process.version.split(".")[0]}.${process.arch}.${process.platform}` !==
119
- process.env.CI_NODE_VERSION_ARCH_PLATFORM
240
+ `${process.version.split(".")[0]}.${process.arch}.${process.platform}`
241
+ !== process.env.CI_NODE_VERSION_ARCH_PLATFORM
120
242
  ));
121
243
  ' || return 0
122
- # init $BRANCH
123
- BRANCH="$(git rev-parse --abbrev-ref HEAD)"
124
- git pull --unshallow origin "$BRANCH"
125
244
  # init .git/config
126
245
  git config --local user.email "github-actions@users.noreply.github.com"
127
246
  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";
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 '
135
256
  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));
257
+ (function () {
147
258
  [
148
- // parallel-task - screenshot files
149
- [
150
- "shRunWithScreenshotTxt",
151
- ".build/screenshot-files.svg",
152
- "shGitLsTree"
153
- ],
154
259
  // parallel-task - screenshot changelog
155
260
  [
261
+ "jslint_ci.sh",
156
262
  "shRunWithScreenshotTxt",
157
- ".build/screenshot-changelog.svg",
263
+ ".artifact/screenshot_changelog.svg",
158
264
  "head",
159
265
  "-n50",
160
266
  "CHANGELOG.md"
267
+ ],
268
+ // parallel-task - screenshot files
269
+ [
270
+ "jslint_ci.sh",
271
+ "shRunWithScreenshotTxt",
272
+ ".artifact/screenshot_package_listing.svg",
273
+ "shGitLsTree"
161
274
  ]
162
275
  ].forEach(function (argList) {
163
- moduleChildProcess.spawn("./jslint_ci.sh", argList, {
276
+ moduleChildProcess.spawn("sh", argList, {
164
277
  stdio: [
165
278
  "ignore", 1, 2
166
279
  ]
@@ -170,111 +283,26 @@ echo "\
170
283
  }
171
284
  });
172
285
  });
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
286
  }());
267
- ' # '
268
- # add dir .build
269
- git add -f .build jslint.cjs jslint.js
270
- git commit -am "add dir .build"
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"
271
300
  # checkout branch-gh-pages
272
- git checkout -b gh-pages
273
301
  git fetch origin gh-pages
274
- git reset --hard origin/gh-pages
302
+ git checkout -b gh-pages origin/gh-pages
275
303
  # update dir branch-$BRANCH
276
304
  rm -rf "branch-$BRANCH"
277
- mkdir "branch-$BRANCH"
305
+ mkdir -p "branch-$BRANCH"
278
306
  (set -e
279
307
  cd "branch-$BRANCH"
280
308
  git init -b branch1
@@ -285,22 +313,31 @@ import moduleFs from "fs";
285
313
  # update root-dir with branch-beta
286
314
  if [ "$BRANCH" = beta ]
287
315
  then
288
- git rm -rf .build
316
+ rm -rf .artifact
289
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
290
327
  fi
291
328
  # update README.md with branch-$BRANCH and $GITHUB_REPOSITORY
292
329
  sed -i \
293
330
  -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|$(
331
+ -e "s|\b$UPSTREAM_OWNER/$UPSTREAM_REPO\b|$GITHUB_REPOSITORY|g" \
332
+ -e "s|\b$UPSTREAM_OWNER\.github\.io/$UPSTREAM_REPO\b|$(
296
333
  printf "$GITHUB_REPOSITORY" | sed -e "s|/|.github.io/|"
297
334
  )|g" \
298
335
  "branch-$BRANCH/README.md"
299
336
  git status
300
337
  git commit -am "update dir branch-$BRANCH" || true
301
- # if branch-gh-pages has more than 100 commits,
338
+ # if branch-gh-pages has more than 50 commits,
302
339
  # then backup and squash commits
303
- if [ "$(git rev-list --count gh-pages)" -gt 100 ]
340
+ if [ "$(git rev-list --count gh-pages)" -gt 50 ]
304
341
  then
305
342
  # backup
306
343
  shGitCmdWithGithubToken push origin -f gh-pages:gh-pages-backup
@@ -325,8 +362,65 @@ import moduleFs from "fs";
325
362
  )
326
363
  )}
327
364
 
365
+ shCiArtifactUploadCustom() {(set -e
366
+ # this function will run custom-code to upload build-artifacts
367
+ return
368
+ )}
369
+
328
370
  shCiBase() {(set -e
329
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
330
424
  )}
331
425
 
332
426
  shCiBranchPromote() {(set -e
@@ -344,9 +438,15 @@ shCiBranchPromote() {(set -e
344
438
  git push "$REMOTE" "$REMOTE/$BRANCH1:$BRANCH2" "$@"
345
439
  )}
346
440
 
441
+ shCiNpmPublishCustom() {(set -e
442
+ # this function will run custom-code to npm-publish package
443
+ npm install
444
+ npm publish --access public
445
+ )}
446
+
347
447
  shDirHttplinkValidate() {(set -e
348
448
  # this function will validate http-links embedded in .html and .md files
349
- node --input-type=module -e '
449
+ node --input-type=module --eval '
350
450
  import moduleFs from "fs";
351
451
  import moduleHttps from "https";
352
452
  import moduleUrl from "url";
@@ -356,7 +456,7 @@ import moduleUrl from "url";
356
456
  await moduleFs.promises.readdir(".")
357
457
  ).forEach(async function (file) {
358
458
  let data;
359
- if (!(
459
+ if (file === "CHANGELOG.md" || !(
360
460
  /.\.html$|.\.md$/m
361
461
  ).test(file)) {
362
462
  return;
@@ -437,7 +537,12 @@ import moduleUrl from "url";
437
537
  });
438
538
  });
439
539
  }());
440
- ' # "'
540
+ ' "$@" # '
541
+ )}
542
+
543
+ shDuList() {(set -e
544
+ # this function will du $1 and sort its subdir by size
545
+ du -md1 "$1" | sort -nr
441
546
  )}
442
547
 
443
548
  shGitCmdWithGithubToken() {(set -e
@@ -462,12 +567,44 @@ shGitCmdWithGithubToken() {(set -e
462
567
  return "$EXIT_CODE"
463
568
  )}
464
569
 
570
+ shGitGc() {(set -e
571
+ # this function will gc unreachable .git objects
572
+ # http://stackoverflow.com/questions/3797907/how-to-remove-unused-objects-from-a-git-repository
573
+ git \
574
+ -c gc.reflogExpire=0 \
575
+ -c gc.reflogExpireUnreachable=0 \
576
+ -c gc.rerereresolved=0 \
577
+ -c gc.rerereunresolved=0 \
578
+ -c gc.pruneExpire=now \
579
+ gc
580
+ )}
581
+
582
+ shGitInitBase() {(set -e
583
+ # this function will git init && create basic git-template from jslint-org/base
584
+ local BRANCH
585
+ git init
586
+ git config core.autocrlf input
587
+ git remote remove base 2>/dev/null || true
588
+ git remote add base https://github.com/jslint-org/base
589
+ git fetch base base
590
+ for BRANCH in base alpha
591
+ do
592
+ git branch -D "$BRANCH" 2>/dev/null || true
593
+ git checkout -b "$BRANCH" base/base
594
+ done
595
+ sed -i.bak "s|owner/repo|${1:-owner/repo}|" .gitconfig
596
+ rm .gitconfig.bak
597
+ cp .gitconfig .git/config
598
+ git commit -am "update owner/repo to $1" || true
599
+ )}
600
+
601
+
465
602
  shGitLsTree() {(set -e
466
603
  # this function will "git ls-tree" all files committed in HEAD
467
604
  # example use:
468
605
  # shGitLsTree | sort -rk3 # sort by date
469
606
  # shGitLsTree | sort -rk4 # sort by size
470
- node --input-type=module -e '
607
+ node --input-type=module --eval '
471
608
  import moduleChildProcess from "child_process";
472
609
  (async function () {
473
610
  let result;
@@ -488,7 +625,7 @@ import moduleChildProcess from "child_process";
488
625
  }).setEncoding("utf8");
489
626
  });
490
627
  result = Array.from(result.matchAll(
491
- /^(\S+?)\u0020+?\S+?\u0020+?\S+?\u0020+?(\S+?)\t(\S+?)$/gm
628
+ /^(\S+?) +?\S+? +?\S+? +?(\S+?)\t(\S+?)$/gm
492
629
  )).map(function ([
493
630
  ignore, mode, size, file
494
631
  ]) {
@@ -541,7 +678,82 @@ import moduleChildProcess from "child_process";
541
678
  }).join(""));
542
679
  });
543
680
  }());
544
- ' # "'
681
+ ' "$@" # '
682
+ )}
683
+
684
+ shGitSquashPop() {(set -e
685
+ # this function will squash HEAD to given $COMMIT
686
+ # http://stackoverflow.com/questions/5189560
687
+ # /how-can-i-squash-my-last-x-commits-together-using-git
688
+ COMMIT="$1"
689
+ MESSAGE="$2"
690
+ # reset git to previous $COMMIT
691
+ git reset "$COMMIT"
692
+ git add .
693
+ # commit HEAD immediately after previous $COMMIT
694
+ git commit -am "$MESSAGE" || true
695
+ )}
696
+
697
+ shGrep() {(set -e
698
+ # this function will recursively grep . for $REGEXP
699
+ REGEXP="$1"
700
+ shift
701
+ FILE_FILTER="\
702
+ /\\.|~$|/(obj|release)/|(\\b|_)(\\.\\d|\
703
+ archive|artifact|\
704
+ bower_component|build|\
705
+ coverage|\
706
+ doc|\
707
+ external|\
708
+ fixture|\
709
+ git_module|\
710
+ jquery|\
711
+ log|\
712
+ min|misc|mock|\
713
+ node_module|\
714
+ old|\
715
+ raw|\rollup|\
716
+ swp|\
717
+ tmp|\
718
+ vendor)s{0,1}(\\b|_)\
719
+ "
720
+ find . -type f |
721
+ grep -v -E "$FILE_FILTER" |
722
+ tr "\n" "\000" |
723
+ xargs -0 grep -HIin -E "$REGEXP" "$@" |
724
+ tee /tmp/shGrep.txt || true
725
+ )}
726
+
727
+ shGrepReplace() {(set -e
728
+ # this function will inline grep-and-replace /tmp/shGrep.txt
729
+ node --input-type=module --eval '
730
+ import moduleFs from "fs";
731
+ import moduleOs from "os";
732
+ import modulePath from "path";
733
+ (async function () {
734
+ "use strict";
735
+ let data;
736
+ let dict = {};
737
+ data = await moduleFs.promises.readFile((
738
+ moduleOs.tmpdir() + "/shGrep.txt"
739
+ ), "utf8");
740
+ data = data.replace((
741
+ /^(.+?):(\d+?):(.*?)$/gm
742
+ ), function (ignore, file, lineno, str) {
743
+ dict[file] = dict[file] || moduleFs.readFileSync( //jslint-quiet
744
+ modulePath.resolve(file),
745
+ "utf8"
746
+ ).split("\n");
747
+ dict[file][lineno - 1] = str;
748
+ return "";
749
+ });
750
+ Object.entries(dict).forEach(function ([
751
+ file, data
752
+ ]) {
753
+ moduleFs.promises.writeFile(file, data.join("\n"));
754
+ });
755
+ }());
756
+ ' "$@" # '
545
757
  )}
546
758
 
547
759
  shHttpFileServer() {(set -e
@@ -569,7 +781,7 @@ shHttpFileServer() {(set -e
569
781
  done
570
782
  return
571
783
  fi
572
- node --input-type=module -e '
784
+ node --input-type=module --eval '
573
785
  import moduleChildProcess from "child_process";
574
786
  import moduleFs from "fs";
575
787
  import moduleHttp from "http";
@@ -590,9 +802,9 @@ import moduleUrl from "url";
590
802
  };
591
803
  }());
592
804
  (async function httpFileServer() {
593
- /*
594
- * this function will start http-file-server
595
- */
805
+
806
+ // this function will start http-file-server
807
+
596
808
  let contentTypeDict = {
597
809
  ".bmp": "image/bmp",
598
810
  ".cjs": "application/javascript; charset=utf-8",
@@ -636,10 +848,10 @@ import moduleUrl from "url";
636
848
  return;
637
849
  }
638
850
  console.error(
639
- "serverLog - " +
640
- new Date(timeStart).toISOString() + " - " +
641
- (Date.now() - timeStart) + "ms - " +
642
- (res.statusCode || 0) + " " + req.method + " " + pathname
851
+ "serverLog - "
852
+ + new Date(timeStart).toISOString() + " - "
853
+ + (Date.now() - timeStart) + "ms - "
854
+ + (res.statusCode || 0) + " " + req.method + " " + pathname
643
855
  );
644
856
  });
645
857
  // debug - echo request
@@ -678,9 +890,9 @@ import moduleUrl from "url";
678
890
  }).listen(process.env.PORT);
679
891
  }());
680
892
  (function jslintDir() {
681
- /*
682
- * this function will jslint current-directory
683
- */
893
+
894
+ // this function will jslint current-directory
895
+
684
896
  moduleFs.stat((
685
897
  process.env.HOME + "/jslint.mjs"
686
898
  ), function (ignore, exists) {
@@ -696,9 +908,9 @@ import moduleUrl from "url";
696
908
  });
697
909
  }());
698
910
  (function replStart() {
699
- /*
700
- * this function will start repl-debugger
701
- */
911
+
912
+ // this function will start repl-debugger
913
+
702
914
  let that;
703
915
  // start repl
704
916
  that = moduleRepl.start({
@@ -715,7 +927,7 @@ import moduleUrl from "url";
715
927
  // hook custom-eval-function
716
928
  that.eval = function (script, context, file, onError) {
717
929
  script.replace((
718
- /^(\S+)\u0020(.*?)\n/
930
+ /^(\S+) (.*?)\n/
719
931
  ), function (ignore, match1, match2) {
720
932
  switch (match1) {
721
933
  // syntax-sugar - run shell-cmd
@@ -735,7 +947,7 @@ import moduleUrl from "url";
735
947
  break;
736
948
  }
737
949
  match2 = match2.replace((
738
- /^git\u0020/
950
+ /^git /
739
951
  ), "git --no-pager ");
740
952
  // run shell-cmd
741
953
  console.error("$ " + match2);
@@ -756,8 +968,8 @@ import moduleUrl from "url";
756
968
  console.error(
757
969
  match2.split("").map(function (chr) {
758
970
  return (
759
- "\\u" +
760
- chr.charCodeAt(0).toString(16).padStart(4, 0)
971
+ "\\u"
972
+ + chr.charCodeAt(0).toString(16).padStart(4, 0)
761
973
  );
762
974
  }).join("")
763
975
  );
@@ -772,15 +984,15 @@ import moduleUrl from "url";
772
984
  // 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
985
  case "keys":
774
986
  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"
987
+ "console.error(Object.keys(" + match2
988
+ + ").map(function(key){return("
989
+ + "typeof " + match2 + "[key]===\u0027object\u0027&&"
990
+ + match2 + "[key]&&"
991
+ + match2 + "[key]===global[key]"
992
+ + "?\u0027global\u0027"
993
+ + ":typeof " + match2 + "[key]"
994
+ + ")+\u0027 \u0027+key;"
995
+ + "}).sort().join(\u0027\\n\u0027))\n"
784
996
  );
785
997
  break;
786
998
  // syntax-sugar - print String(val)
@@ -794,9 +1006,9 @@ import moduleUrl from "url";
794
1006
  };
795
1007
  }());
796
1008
  (function watchDir() {
797
- /*
798
- * this function will watch current-directory for changes
799
- */
1009
+
1010
+ // this function will watch current-directory for changes
1011
+
800
1012
  moduleFs.readdir(".", function (ignore, fileList) {
801
1013
  fileList.forEach(function (file) {
802
1014
  if (file[0] === ".") {
@@ -820,15 +1032,16 @@ import moduleUrl from "url";
820
1032
  ' "$@" # '
821
1033
  )}
822
1034
 
823
- shImageJslintCreate() {(set -e
824
- # this function will create .png logo of jslint
1035
+ shImageLogoCreate() {(set -e
1036
+ # this function will create .png logo
1037
+ local SIZE
825
1038
  echo '
826
1039
  <!DOCTYPE html>
827
1040
  <html lang="en">
828
1041
  <head>
829
1042
  <title>logo</title>
830
1043
  <style>
831
- /* sh jslint_ci.sh shBrowserScreenshot asset-image-jslint.html --window-size=512x512 */
1044
+ /* sh jslint_ci.sh shBrowserScreenshot asset_image_logo.html --window-size=512x512 */
832
1045
  /* csslint box-model:false */
833
1046
  /* csslint ignore:start */
834
1047
  *,
@@ -839,7 +1052,7 @@ shImageJslintCreate() {(set -e
839
1052
  @font-face {
840
1053
  font-family: Daley;
841
1054
  font-weight: bold;
842
- src: url("asset-font-daley-bold.woff2") format("woff2");
1055
+ src: url("asset_font_daley_bold.woff2") format("woff2");
843
1056
  }
844
1057
  /* csslint ignore:end */
845
1058
  body,
@@ -884,26 +1097,26 @@ div {
884
1097
  </div>
885
1098
  </body>
886
1099
  </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 \
1100
+ ' > .artifact/asset_image_logo_512.html
1101
+ cp asset_font_daley_bold.woff2 .artifact || true
1102
+ # screenshot asset_image_logo_512.png
1103
+ shBrowserScreenshot .artifact/asset_image_logo_512.html \
891
1104
  --window-size=512x512 \
892
- -screenshot=.build/asset-image-jslint-512.png
1105
+ -screenshot=.artifact/asset_image_logo_512.png
893
1106
  # create various smaller thumbnails
894
1107
  for SIZE in 32 64 128 256
895
1108
  do
896
- convert -resize "${SIZE}x${SIZE}" .build/asset-image-jslint-512.png \
897
- ".build/asset-image-jslint-$SIZE.png"
1109
+ convert -resize "${SIZE}x${SIZE}" .artifact/asset_image_logo_512.png \
1110
+ ".artifact/asset_image_logo_$SIZE.png"
898
1111
  printf \
899
- "shImageJslintCreate - wrote - .build/asset-image-jslint-$SIZE.png\n" 1>&2
1112
+ "shImageLogoCreate - wrote - .artifact/asset_image_logo_$SIZE.png\n" 1>&2
900
1113
  done
901
1114
  # convert to svg @ https://convertio.co/png-svg/
902
1115
  )}
903
1116
 
904
1117
  shImageToDataUri() {(set -e
905
1118
  # this function will convert image $1 to data-uri string
906
- node --input-type=module -e '
1119
+ node --input-type=module --eval '
907
1120
  import moduleFs from "fs";
908
1121
  import moduleHttps from "https";
909
1122
  (async function () {
@@ -944,45 +1157,45 @@ shJsonNormalize() {(set -e
944
1157
  # 1. read json-data from file $1
945
1158
  # 2. normalize json-data
946
1159
  # 3. write normalized json-data back to file $1
947
- node --input-type=module -e '
1160
+ node --input-type=module --eval '
948
1161
  import moduleFs from "fs";
949
- (async function () {
950
- function identity(val) {
1162
+ function noop(val) {
951
1163
 
952
- // This function will return <val>.
1164
+ // This function will do nothing except return <val>.
953
1165
 
954
- return val;
955
- }
956
- function objectDeepCopyWithKeysSorted(obj) {
1166
+ return val;
1167
+ }
1168
+ function objectDeepCopyWithKeysSorted(obj) {
957
1169
 
958
- // this function will recursively deep-copy <obj> with keys sorted
1170
+ // This function will recursively deep-copy <obj> with keys sorted.
959
1171
 
960
- let sorted;
961
- if (typeof obj !== "object" || !obj) {
962
- return obj;
963
- }
1172
+ let sorted;
1173
+ if (typeof obj !== "object" || !obj) {
1174
+ return obj;
1175
+ }
964
1176
 
965
- // recursively deep-copy list with child-keys sorted
1177
+ // Recursively deep-copy list with child-keys sorted.
966
1178
 
967
- if (Array.isArray(obj)) {
968
- return obj.map(objectDeepCopyWithKeysSorted);
969
- }
1179
+ if (Array.isArray(obj)) {
1180
+ return obj.map(objectDeepCopyWithKeysSorted);
1181
+ }
970
1182
 
971
- // recursively deep-copy obj with keys sorted
1183
+ // Recursively deep-copy obj with keys sorted.
972
1184
 
973
- sorted = {};
974
- Object.keys(obj).sort().forEach(function (key) {
975
- sorted[key] = objectDeepCopyWithKeysSorted(obj[key]);
976
- });
977
- return sorted;
978
- }
1185
+ sorted = {};
1186
+ Object.keys(obj).sort().forEach(function (key) {
1187
+ sorted[key] = objectDeepCopyWithKeysSorted(obj[key]);
1188
+ });
1189
+ return sorted;
1190
+ }
1191
+ (async function () {
979
1192
  console.error("shJsonNormalize - " + process.argv[1]);
980
- moduleFs.promises.writeFile(
1193
+ await moduleFs.promises.writeFile(
981
1194
  process.argv[1],
982
1195
  JSON.stringify(
983
1196
  objectDeepCopyWithKeysSorted(
984
1197
  JSON.parse(
985
- identity(
1198
+ noop(
986
1199
  await moduleFs.promises.readFile(
987
1200
  process.argv[1],
988
1201
  "utf8"
@@ -993,16 +1206,26 @@ import moduleFs from "fs";
993
1206
  )
994
1207
  ),
995
1208
  undefined,
996
- 4
1209
+ Number(process.argv[2]) || 4
997
1210
  ) + "\n"
998
1211
  );
999
1212
  }());
1000
1213
  ' "$@" # '
1001
1214
  )}
1002
1215
 
1216
+ shNpmPublishV0() {(set -e
1217
+ # this function will npm-publish name $1 with bare package.json
1218
+ local DIR
1219
+ DIR=/tmp/shNpmPublishV0
1220
+ rm -rf "$DIR" && mkdir -p "$DIR" && cd "$DIR"
1221
+ printf "{\"name\":\"$1\",\"version\":\"0.0.1\"}\n" > package.json
1222
+ shift
1223
+ npm publish "$@"
1224
+ )}
1225
+
1003
1226
  shRawLibFetch() {(set -e
1004
1227
  # this function will fetch raw-lib from $1
1005
- node --input-type=module -e '
1228
+ node --input-type=module --eval '
1006
1229
  import moduleChildProcess from "child_process";
1007
1230
  import moduleFs from "fs";
1008
1231
  import moduleHttps from "https";
@@ -1129,12 +1352,12 @@ import modulePath from "path";
1129
1352
  }
1130
1353
  if (elem.dateCommitted) {
1131
1354
  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
- "*/"
1355
+ "\n\n\n/*\n"
1356
+ + "repo " + elem.prefix.replace("/blob/", "/tree/") + "\n"
1357
+ + "committed " + (
1358
+ /\b\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ\b|$/
1359
+ ).exec(elem.dateCommitted.toString())[0] + "\n"
1360
+ + "*/"
1138
1361
  );
1139
1362
  }
1140
1363
  // comment /*...*/
@@ -1145,15 +1368,17 @@ import modulePath from "path";
1145
1368
  /\*\//g
1146
1369
  ), "*\\/") + "\n*/";
1147
1370
  }
1148
- // mangle module.exports
1371
+ // init header and footer
1149
1372
  result += (
1150
- "\n\n\n/*\nfile " + elem.url + "\n*/\n" +
1151
- elem.data.toString().trim()
1373
+ "\n\n\n/*\nfile " + elem.url + "\n*/\n"
1374
+ + (elem.header || "")
1375
+ + elem.data.toString().trim()
1376
+ + (elem.footer || "")
1152
1377
  );
1153
1378
  });
1154
1379
  result = (
1155
- "\n" + result.trim() +
1156
- "\n\n\n/*\nfile none\n*/\n/*jslint-enable*/\n"
1380
+ "\n" + result.trim()
1381
+ + "\n\n\n/*\nfile none\n*/\n/*jslint-enable*/\n"
1157
1382
  );
1158
1383
  // comment #!
1159
1384
  result = result.replace((
@@ -1165,11 +1390,11 @@ import modulePath from "path";
1165
1390
  ), "\n");
1166
1391
  // remove trailing-whitespace
1167
1392
  result = result.replace((
1168
- /[\t\u0020]+$/gm
1393
+ /[\t ]+$/gm
1169
1394
  ), "");
1170
1395
  // remove leading-newline before ket
1171
1396
  result = result.replace((
1172
- /\n+?(\n\u0020*?\})/g
1397
+ /\n+?(\n *?\})/g
1173
1398
  ), "$1");
1174
1399
  // eslint - no-multiple-empty-lines
1175
1400
  // https://github.com/eslint/eslint/blob/v7.2.0/docs/rules/no-multiple-empty-lines.md //jslint-quiet
@@ -1186,17 +1411,17 @@ import modulePath from "path";
1186
1411
  result = result.replace(new RegExp(aa, flags), bb);
1187
1412
  if (result0 === result) {
1188
1413
  throw new Error(
1189
- "shRawLibFetch - cannot find-and-replace snippet " +
1190
- JSON.stringify(aa)
1414
+ "shRawLibFetch - cannot find-and-replace snippet "
1415
+ + JSON.stringify(aa)
1191
1416
  );
1192
1417
  }
1193
1418
  });
1194
1419
  // init header
1195
1420
  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) {
1421
+ matchObj.input.slice(0, matchObj.index)
1422
+ + "/*jslint-disable*/\n/*\nshRawLibFetch\n"
1423
+ + JSON.stringify(JSON.parse(matchObj[1]), undefined, 4) + "\n"
1424
+ + matchObj[2].split("\n\n").filter(function (elem) {
1200
1425
  return elem.trim();
1201
1426
  }).map(function (elem) {
1202
1427
  return elem.trim().replace((
@@ -1231,8 +1456,8 @@ import modulePath from "path";
1231
1456
  });
1232
1457
  if (result0 === result) {
1233
1458
  throw new Error(
1234
- "shRawLibFetch - cannot find-and-replace snippet " +
1235
- JSON.stringify(aa)
1459
+ "shRawLibFetch - cannot find-and-replace snippet "
1460
+ + JSON.stringify(aa)
1236
1461
  );
1237
1462
  }
1238
1463
  return "";
@@ -1247,8 +1472,8 @@ import modulePath from "path";
1247
1472
  return;
1248
1473
  }
1249
1474
  data = (
1250
- "data:" + dataUriType + ";base64," +
1251
- data.toString("base64")
1475
+ "data:" + dataUriType + ";base64,"
1476
+ + data.toString("base64")
1252
1477
  );
1253
1478
  result0 = result;
1254
1479
  result = result.replace(
@@ -1260,15 +1485,15 @@ import modulePath from "path";
1260
1485
  );
1261
1486
  if (result0 === result) {
1262
1487
  throw new Error(
1263
- "shRawLibFetch - cannot find-and-replace snippet " +
1264
- JSON.stringify(exports)
1488
+ "shRawLibFetch - cannot find-and-replace snippet "
1489
+ + JSON.stringify(exports)
1265
1490
  );
1266
1491
  }
1267
1492
  });
1268
1493
  // init footer
1269
1494
  result = header + result;
1270
1495
  matchObj.input.replace((
1271
- /\n\/\*\nfile\u0020none\n\*\/\n\/\*jslint-enable\*\/\n([\S\s]+)/
1496
+ /\n\/\*\nfile none\n\*\/\n\/\*jslint-enable\*\/\n([\S\s]+)/
1272
1497
  ), function (ignore, match1) {
1273
1498
  result += "\n\n" + match1.trim() + "\n";
1274
1499
  });
@@ -1277,579 +1502,1160 @@ import modulePath from "path";
1277
1502
  });
1278
1503
  }());
1279
1504
  ' "$@" # '
1280
- git diff 2>/dev/null || true
1505
+ git diff
1506
+ )}
1507
+
1508
+ shRmDsStore() {(set -e
1509
+ # this function will recursively rm .DS_Store from current-dir
1510
+ # http://stackoverflow.com/questions/2016844/bash-recursively-remove-files
1511
+ local NAME
1512
+ for NAME in "._*" ".DS_Store" "desktop.ini" "npm-debug.log" "*~"
1513
+ do
1514
+ find . -iname "$NAME" -print0 | xargs -0 rm -f || true
1515
+ done
1281
1516
  )}
1282
1517
 
1283
1518
  shRunWithCoverage() {(set -e
1284
1519
  # 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) {
1520
+ # and create coverage-report .artifact/coverage/index.html
1521
+ node --input-type=module --eval '
1522
+ /*jslint indent2*/
1523
+ let moduleChildProcess;
1524
+ let moduleFs;
1525
+ let moduleFsInitResolveList;
1526
+ let modulePath;
1527
+ let moduleUrl;
1528
+ function assertOrThrow(condition, message) {
1529
+ if (!condition) {
1530
+ throw (
1531
+ (!message || typeof message === "string")
1532
+ ? new Error(String(message).slice(0, 2048))
1533
+ : message
1534
+ );
1535
+ }
1536
+ }
1537
+ async function fsWriteFileWithParents(pathname, data) {
1538
+ await moduleFsInit();
1539
+ try {
1540
+ await moduleFs.promises.writeFile(pathname, data);
1541
+ } catch (ignore) {
1542
+ await moduleFs.promises.mkdir(modulePath.dirname(pathname), {
1543
+ recursive: true
1544
+ });
1545
+ await moduleFs.promises.writeFile(pathname, data);
1546
+ }
1547
+ console.error("wrote file " + pathname);
1548
+ }
1549
+ function htmlEscape(str) {
1550
+ return String(str).replace((
1551
+ /&/g
1552
+ ), "&amp;").replace((
1553
+ /</g
1554
+ ), "&lt;").replace((
1555
+ />/g
1556
+ ), "&gt;");
1557
+ }
1558
+ async function moduleFsInit() {
1303
1559
 
1304
- // this function will both print <argList> to stderr and return <argList>[0]
1560
+ if (moduleFs !== undefined) {
1561
+ return;
1562
+ }
1563
+ if (moduleFsInitResolveList !== undefined) {
1564
+ return new Promise(function (resolve) {
1565
+ moduleFsInitResolveList.push(resolve);
1566
+ });
1567
+ }
1568
+ moduleFsInitResolveList = [];
1569
+ [
1570
+ moduleChildProcess,
1571
+ moduleFs,
1572
+ modulePath,
1573
+ moduleUrl
1574
+ ] = await Promise.all([
1575
+ import("child_process"),
1576
+ import("fs"),
1577
+ import("path"),
1578
+ import("url")
1579
+ ]);
1580
+ while (moduleFsInitResolveList.length > 0) {
1581
+ moduleFsInitResolveList.shift()();
1582
+ }
1583
+ }
1584
+ function v8CoverageListMerge(processCovs) {
1585
+ let resultMerged = []; // List of merged scripts from processCovs.
1586
+ let urlToScriptDict = new Map(); // Map scriptCov.url to scriptCovs.
1305
1587
 
1306
- consoleError("\n\ndebugInline");
1307
- consoleError(...argList);
1308
- consoleError("\n");
1309
- return argList[0];
1588
+ function compareRangeList(aa, bb) {
1589
+ if (aa.startOffset !== bb.startOffset) {
1590
+ return aa.startOffset - bb.startOffset;
1591
+ }
1592
+ return bb.endOffset - aa.endOffset;
1593
+ }
1594
+
1595
+ function dictKeyValueAppend(dict, key, val) {
1596
+ let list = dict.get(key);
1597
+ if (list === undefined) {
1598
+ list = [];
1599
+ dict.set(key, list);
1600
+ }
1601
+ list.push(val);
1602
+ }
1603
+
1604
+ function mergeTreeList(parentTrees) {
1605
+ if (parentTrees.length <= 1) {
1606
+ return parentTrees[0];
1607
+ }
1608
+ return {
1609
+ children: mergeTreeListToChildren(parentTrees),
1610
+ delta: parentTrees.reduce(function (aa, bb) {
1611
+ return aa + bb.delta;
1612
+ }, 0),
1613
+ end: parentTrees[0].end,
1614
+ start: parentTrees[0].start
1310
1615
  };
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
1616
+ }
1617
+
1618
+ function mergeTreeListToChildren(parentTrees) {
1619
+ let openRange;
1620
+ let parentToChildDict = new Map(); // Map parent to child.
1621
+ let queueList;
1622
+ let queueListIi = 0;
1623
+ let queueOffset;
1624
+ let queueTrees;
1625
+ let resultChildren = [];
1626
+ let startToTreeDict = new Map(); // Map tree.start to tree.
1627
+ function nextXxx() {
1628
+ let [
1629
+ nextOffset, nextTrees
1630
+ ] = queueList[queueListIi] || [];
1631
+ let openRangeEnd;
1632
+ if (queueTrees === undefined) {
1633
+ queueListIi += 1;
1634
+ } else if (nextOffset === undefined || nextOffset > queueOffset) {
1635
+ nextOffset = queueOffset;
1636
+ nextTrees = queueTrees;
1637
+ queueTrees = undefined;
1638
+ } else {
1639
+ if (nextOffset === queueOffset) {
1640
+ queueTrees.forEach(function (tree) {
1641
+ nextTrees.push(tree);
1642
+ });
1643
+ queueTrees = undefined;
1644
+ }
1645
+ queueListIi += 1;
1646
+ }
1647
+ if (nextOffset === undefined) {
1648
+ if (openRange !== undefined) {
1649
+ resultAppendNextChild();
1650
+ }
1651
+ return true;
1652
+ }
1653
+ if (openRange !== undefined && openRange.end <= nextOffset) {
1654
+ resultAppendNextChild();
1655
+ openRange = undefined;
1656
+ }
1657
+ if (openRange === undefined) {
1658
+ openRangeEnd = nextOffset + 1;
1659
+ nextTrees.forEach(function ({
1660
+ parentIi,
1661
+ tree
1662
+ }) {
1663
+ openRangeEnd = Math.max(openRangeEnd, tree.end);
1664
+ dictKeyValueAppend(parentToChildDict, parentIi, tree);
1665
+ });
1666
+ queueOffset = openRangeEnd;
1667
+ openRange = {
1668
+ end: openRangeEnd,
1669
+ start: nextOffset
1670
+ };
1671
+ } else {
1672
+ nextTrees.forEach(function ({
1673
+ parentIi,
1674
+ tree
1675
+ }) {
1676
+ let right;
1677
+ if (tree.end > openRange.end) {
1678
+ right = treeSplit(tree, openRange.end);
1679
+ if (queueTrees === undefined) {
1680
+ queueTrees = [];
1681
+ }
1682
+ queueTrees.push({
1683
+ parentIi,
1684
+ tree: right
1685
+ });
1686
+ }
1687
+ dictKeyValueAppend(parentToChildDict, parentIi, tree);
1688
+ });
1689
+ }
1690
+ }
1691
+ function resultAppendNextChild() {
1692
+ let treesMatching = [];
1693
+ parentToChildDict.forEach(function (nested) {
1694
+ if (
1695
+ nested.length === 1
1696
+ && nested[0].start === openRange.start
1697
+ && nested[0].end === openRange.end
1698
+ ) {
1699
+ treesMatching.push(nested[0]);
1700
+ } else {
1701
+ treesMatching.push({
1702
+ children: nested,
1703
+ delta: 0,
1704
+ end: openRange.end,
1705
+ start: openRange.start
1706
+ });
1707
+ }
1708
+ });
1709
+ parentToChildDict.clear();
1710
+ resultChildren.push(mergeTreeList(treesMatching));
1711
+ }
1712
+ function treeSplit(tree, offset) {
1713
+ let child;
1714
+ let ii = 0;
1715
+ let leftChildLen = tree.children.length;
1716
+ let mid;
1717
+ let resultTree;
1718
+ let rightChildren;
1719
+ while (ii < tree.children.length) {
1720
+ child = tree.children[ii];
1721
+ if (child.start < offset && offset < child.end) {
1722
+ mid = treeSplit(child, offset);
1723
+ leftChildLen = ii + 1;
1724
+ break;
1725
+ }
1726
+ if (child.start >= offset) {
1727
+ leftChildLen = ii;
1728
+ break;
1729
+ }
1730
+ ii += 1;
1731
+ }
1732
+ rightChildren = tree.children.splice(
1733
+ leftChildLen,
1734
+ tree.children.length - leftChildLen
1735
+ );
1736
+ if (mid !== undefined) {
1737
+ rightChildren.unshift(mid);
1738
+ }
1739
+ resultTree = {
1740
+ children: rightChildren,
1741
+ delta: tree.delta,
1742
+ end: tree.end,
1743
+ start: offset
1744
+ };
1745
+ tree.end = offset;
1746
+ return resultTree;
1747
+ }
1748
+ parentTrees.forEach(function (parentTree, parentIi) {
1749
+ parentTree.children.forEach(function (child) {
1750
+ dictKeyValueAppend(startToTreeDict, child.start, {
1751
+ parentIi,
1752
+ tree: child
1753
+ });
1754
+ });
1755
+ });
1756
+ queueList = Array.from(startToTreeDict).map(function ([
1757
+ startOffset, trees
1758
+ ]) {
1759
+ return [
1760
+ startOffset, trees
1761
+ ];
1762
+ }).sort(function (aa, bb) {
1763
+ return aa[0] - bb[0];
1764
+ });
1765
+ while (true) {
1766
+ if (nextXxx()) {
1767
+ break;
1768
+ }
1769
+ }
1770
+ return resultChildren;
1771
+ }
1772
+
1773
+ function sortFunc(funcCov) {
1774
+ funcCov.ranges = treeToRanges(treeFromSortedRanges(
1775
+ funcCov.ranges.sort(compareRangeList)
1776
+ ));
1777
+ return funcCov;
1778
+ }
1779
+
1780
+ function sortScript(scriptCov) {
1781
+
1782
+ scriptCov.functions.forEach(function (funcCov) {
1783
+ sortFunc(funcCov);
1784
+ });
1785
+ scriptCov.functions.sort(function (aa, bb) {
1786
+ return compareRangeList(aa.ranges[0], bb.ranges[0]);
1787
+ });
1788
+ return scriptCov;
1789
+ }
1790
+
1791
+ function treeFromSortedRanges(ranges) {
1792
+ let root;
1793
+ let stack = []; // Stack of parent trees and parent counts.
1794
+ ranges.forEach(function (range) {
1795
+ let node = {
1796
+ children: [],
1797
+ delta: range.count,
1798
+ end: range.endOffset,
1799
+ start: range.startOffset
1800
+ };
1801
+ let parent;
1802
+ let parentCount;
1803
+ if (root === undefined) {
1804
+ root = node;
1805
+ stack.push([
1806
+ node, range.count
1807
+ ]);
1808
+ return;
1809
+ }
1810
+ while (true) {
1811
+ [
1812
+ parent, parentCount
1813
+ ] = stack[stack.length - 1];
1814
+ if (range.startOffset < parent.end) {
1815
+ break;
1816
+ }
1817
+ stack.pop();
1818
+ }
1819
+ node.delta -= parentCount;
1820
+ parent.children.push(node);
1821
+ stack.push([
1822
+ node, range.count
1823
+ ]);
1824
+ });
1825
+ return root;
1826
+ }
1827
+
1828
+ function treeToRanges(tree) {
1829
+ let count;
1830
+ let cur;
1831
+ let ii;
1832
+ let parentCount;
1833
+ let ranges = [];
1834
+ let stack = [ // Stack of parent trees and counts.
1835
+ [
1836
+ tree, 0
1837
+ ]
1838
+ ];
1839
+ function normalizeRange(tree) {
1840
+ let children = [];
1841
+ let curEnd;
1842
+ let head;
1843
+ let tail = [];
1844
+ function endChain() {
1845
+ if (tail.length !== 0) {
1846
+ head.end = tail[tail.length - 1].end;
1847
+ tail.forEach(function (tailTree) {
1848
+ tailTree.children.forEach(function (subChild) {
1849
+ subChild.delta += tailTree.delta - head.delta;
1850
+ head.children.push(subChild);
1851
+ });
1852
+ });
1853
+ tail.length = 0;
1854
+ }
1855
+ normalizeRange(head);
1856
+ children.push(head);
1857
+ }
1858
+ tree.children.forEach(function (child) {
1859
+ if (head === undefined) {
1860
+ head = child;
1861
+ } else if (
1862
+ child.delta === head.delta && child.start === curEnd
1863
+ ) {
1864
+ tail.push(child);
1865
+ } else {
1866
+ endChain();
1867
+ head = child;
1868
+ }
1869
+ curEnd = child.end;
1870
+ });
1871
+ if (head !== undefined) {
1872
+ endChain();
1873
+ }
1874
+ if (children.length === 1) {
1875
+ if (
1876
+ children[0].start === tree.start
1877
+ && children[0].end === tree.end
1878
+ ) {
1879
+ tree.delta += children[0].delta;
1880
+ tree.children = children[0].children;
1881
+ return;
1882
+ }
1883
+ }
1884
+ tree.children = children;
1885
+ }
1886
+ normalizeRange(tree);
1887
+ while (stack.length > 0) {
1888
+ [
1889
+ cur, parentCount
1890
+ ] = stack.pop();
1891
+ count = parentCount + cur.delta;
1892
+ ranges.push({
1893
+ count,
1894
+ endOffset: cur.end,
1895
+ startOffset: cur.start
1896
+ });
1897
+ ii = cur.children.length - 1;
1898
+ while (ii >= 0) {
1899
+ stack.push([
1900
+ cur.children[ii], count
1901
+ ]);
1902
+ ii -= 1;
1903
+ }
1904
+ }
1905
+ return ranges;
1906
+ }
1907
+
1908
+ if (processCovs.length === 0) {
1909
+ return {
1910
+ result: []
1911
+ };
1912
+ }
1913
+ processCovs.forEach(function ({
1914
+ result
1915
+ }) {
1916
+ result.forEach(function (scriptCov) {
1917
+ dictKeyValueAppend(urlToScriptDict, scriptCov.url, scriptCov);
1918
+ });
1919
+ });
1920
+ urlToScriptDict.forEach(function (scriptCovs) {
1921
+
1922
+ let functions = [];
1923
+ let rangeToFuncDict = new Map();
1924
+ if (scriptCovs.length === 1) {
1925
+ resultMerged.push(sortScript(scriptCovs[0]));
1926
+ return;
1927
+ }
1928
+ scriptCovs.forEach(function ({
1929
+ functions
1321
1930
  }) {
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
- ), "&amp;").replace((
1335
- /"/gu
1336
- ), "&quot;").replace((
1337
- /\u0027/gu
1338
- ), "&apos;").replace((
1339
- /</gu
1340
- ), "&lt;").replace((
1341
- />/gu
1342
- ), "&gt;").replace((
1343
- /&amp;(amp;|apos;|gt;|lt;|quot;)/igu
1344
- ), "&$1");
1931
+ functions.forEach(function (funcCov) {
1932
+ dictKeyValueAppend(
1933
+ rangeToFuncDict,
1934
+ (
1935
+ funcCov.ranges[0].startOffset
1936
+ + ";" + funcCov.ranges[0].endOffset
1937
+ ),
1938
+ funcCov
1939
+ );
1940
+ });
1941
+ });
1942
+ rangeToFuncDict.forEach(function (funcCovs) {
1943
+
1944
+ let count = 0;
1945
+ let isBlockCoverage;
1946
+ let merged;
1947
+ let ranges;
1948
+ let trees = [];
1949
+ if (funcCovs.length === 1) {
1950
+ functions.push(sortFunc(funcCovs[0]));
1951
+ return;
1952
+ }
1953
+ funcCovs.forEach(function (funcCov) {
1954
+ count += (
1955
+ funcCov.count !== undefined
1956
+ ? funcCov.count
1957
+ : funcCov.ranges[0].count
1958
+ );
1959
+ if (funcCov.isBlockCoverage) {
1960
+ trees.push(treeFromSortedRanges(funcCov.ranges));
1345
1961
  }
1346
- html = "";
1347
- html += `<!DOCTYPE html>
1962
+ });
1963
+ if (trees.length > 0) {
1964
+ isBlockCoverage = true;
1965
+ ranges = treeToRanges(mergeTreeList(trees));
1966
+ } else {
1967
+ isBlockCoverage = false;
1968
+ ranges = [
1969
+ {
1970
+ count,
1971
+ endOffset: funcCovs[0].ranges[0].endOffset,
1972
+ startOffset: funcCovs[0].ranges[0].startOffset
1973
+ }
1974
+ ];
1975
+ }
1976
+ merged = {
1977
+ functionName: funcCovs[0].functionName,
1978
+ isBlockCoverage,
1979
+ ranges
1980
+ };
1981
+ if (count !== ranges[0].count) {
1982
+ merged.count = count;
1983
+ }
1984
+ functions.push(merged);
1985
+ });
1986
+ resultMerged.push(sortScript({
1987
+ functions,
1988
+ scriptId: scriptCovs[0].scriptId,
1989
+ url: scriptCovs[0].url
1990
+ }));
1991
+ });
1992
+ Object.entries(resultMerged.sort(function (aa, bb) {
1993
+ return (
1994
+ aa.url > bb.url
1995
+ ? 1
1996
+ : -1
1997
+ );
1998
+ })).forEach(function ([
1999
+ scriptId, scriptCov
2000
+ ]) {
2001
+ scriptCov.scriptId = scriptId.toString(10);
2002
+ });
2003
+ return {
2004
+ result: resultMerged
2005
+ };
2006
+ }
2007
+ async function v8CoverageReportCreate({
2008
+ consoleError,
2009
+ coverageDir,
2010
+ processArgv = []
2011
+ }) {
2012
+ let cwd;
2013
+ let exitCode = 0;
2014
+ let fileDict;
2015
+ let fileExcludeList = [];
2016
+ let fileIncludeList = [];
2017
+ let fileIncludeNodeModules;
2018
+ let processArgElem;
2019
+ let promiseList = [];
2020
+ let v8CoverageObj;
2021
+
2022
+ function htmlRender({
2023
+ fileList,
2024
+ lineList,
2025
+ modeIndex,
2026
+ pathname
2027
+ }) {
2028
+ let html;
2029
+ let padLines;
2030
+ let padPathname;
2031
+ let txt;
2032
+ let txtBorder;
2033
+ html = "";
2034
+ html += String(`
2035
+ <!DOCTYPE html>
1348
2036
  <html lang="en">
1349
2037
  <head>
1350
- <title>coverage-report</title>
2038
+ <title>V8 Coverage Report</title>
1351
2039
  <style>
1352
- /* csslint ignore:start */
2040
+ /* jslint utility2:true */
2041
+ /*csslint ignore:start*/
1353
2042
  * {
1354
2043
  box-sizing: border-box;
1355
- font-family: consolas, menlo, monospace;
2044
+ font-family: consolas, menlo, monospace;
1356
2045
  }
1357
- /* csslint ignore:end */
2046
+ /*csslint ignore:end*/
2047
+
2048
+ /* css - coverage_report - general */
1358
2049
  body {
1359
- margin: 0;
2050
+ margin: 0;
1360
2051
  }
1361
2052
  .coverage pre {
1362
- margin: 5px 0;
2053
+ margin: 5px 0;
1363
2054
  }
1364
2055
  .coverage table {
1365
- border-collapse: collapse;
2056
+ border-collapse: collapse;
1366
2057
  }
1367
2058
  .coverage td,
1368
2059
  .coverage th {
1369
- border: 1px solid #777;
1370
- margin: 0;
1371
- padding: 5px;
2060
+ border: 1px solid #777;
2061
+ line-height: 20px;
2062
+ margin: 0;
2063
+ padding: 5px 10px;
1372
2064
  }
1373
2065
  .coverage td span {
1374
- display: inline-block;
1375
- width: 100%;
2066
+ display: inline-block;
2067
+ width: 100%;
1376
2068
  }
1377
2069
  .coverage .content {
1378
- padding: 0 5px;
2070
+ padding: 0 5px;
1379
2071
  }
1380
2072
  .coverage .content a {
1381
- text-decoration: none;
2073
+ text-decoration: none;
1382
2074
  }
1383
2075
  .coverage .count {
1384
- margin: 0 5px;
1385
- padding: 0 5px;
2076
+ margin: 0 5px;
2077
+ padding: 0 5px;
1386
2078
  }
1387
2079
  .coverage .footer,
1388
2080
  .coverage .header {
1389
- padding: 20px;
2081
+ padding: 20px;
2082
+ }
2083
+ .coverage .footer {
2084
+ text-align: center;
1390
2085
  }
1391
2086
  .coverage .percentbar {
1392
- height: 12px;
1393
- margin: 2px 0;
1394
- min-width: 200px;
1395
- position: relative;
1396
- width: 100%;
2087
+ height: 12px;
2088
+ margin: 2px 0;
2089
+ min-width: 200px;
2090
+ position: relative;
2091
+ width: 100%;
1397
2092
  }
1398
2093
  .coverage .percentbar div {
1399
- height: 100%;
1400
- position: absolute;
2094
+ height: 100%;
2095
+ position: absolute;
1401
2096
  }
1402
2097
  .coverage .title {
1403
- font-size: large;
1404
- font-weight: bold;
1405
- margin-bottom: 10px;
2098
+ font-size: large;
2099
+ font-weight: bold;
2100
+ margin-bottom: 10px;
1406
2101
  }
1407
2102
 
2103
+ /* css - coverage_report - color */
1408
2104
  .coverage td,
1409
2105
  .coverage th {
1410
- background: #fff;
2106
+ background: #fff;
1411
2107
  }
1412
- .coverage .count {
1413
- background: #9d9;
1414
- color: #777;
2108
+ .coverage .count,
2109
+ .coverage .coverageHigh {
2110
+ background: #9d9;
1415
2111
  }
1416
- .coverage .coverageHigh{
1417
- background: #9d9;
2112
+ .coverage .count {
2113
+ color: #666;
1418
2114
  }
1419
- .coverage .coverageLow{
1420
- background: #ebb;
2115
+ .coverage .coverageIgnore {
2116
+ background: #ccc;
1421
2117
  }
1422
- .coverage .coverageMedium{
1423
- background: #fd7;
2118
+ .coverage .coverageLow,
2119
+ .coverage .uncovered {
2120
+ background: #ebb;
1424
2121
  }
1425
- .coverage .header {
1426
- background: #ddd;
2122
+ .coverage .coverageMedium {
2123
+ background: #fd7;
1427
2124
  }
2125
+ .coverage .footer,
2126
+ .coverage .header,
1428
2127
  .coverage .lineno {
1429
- background: #ddd;
2128
+ background: #ddd;
1430
2129
  }
1431
2130
  .coverage .percentbar {
1432
- background: #999;
2131
+ background: #999;
1433
2132
  }
1434
2133
  .coverage .percentbar div {
1435
- background: #666;
1436
- }
1437
- .coverage .uncovered {
1438
- background: #dbb;
2134
+ background: #666;
1439
2135
  }
1440
2136
 
2137
+ /* css - coverage_report - important */
1441
2138
  .coverage pre:hover span,
1442
2139
  .coverage tr:hover td {
1443
- background: #7d7;
2140
+ background: #7d7;
1444
2141
  }
1445
2142
  .coverage pre:hover span.uncovered,
1446
2143
  .coverage tr:hover td.coverageLow {
1447
- background: #d99;
2144
+ background: #f99;
1448
2145
  }
1449
2146
  </style>
1450
2147
  </head>
1451
2148
  <body class="coverage">
2149
+ <!-- header start -->
1452
2150
  <div class="header">
1453
- <div class="title">coverage-report</div>
2151
+ <div class="title">V8 Coverage Report</div>
1454
2152
  <table>
1455
2153
  <thead>
1456
- <tr>
1457
- <th>files covered</th>
1458
- <th>lines</th>
1459
- </tr>
2154
+ <tr>
2155
+ <th>Files covered</th>
2156
+ <th>Lines</th>
2157
+ <th>Remaining</th>
2158
+ </tr>
1460
2159
  </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
- });
2160
+ <tbody>
2161
+ `).trim() + "\n";
2162
+ if (modeIndex) {
2163
+ padLines = String("(ignore) 100.00 %").length;
2164
+ padPathname = 32;
2165
+ fileList.unshift({
2166
+ linesCovered: 0,
2167
+ linesTotal: 0,
2168
+ modeCoverageIgnoreFile: "",
2169
+ pathname: "./"
2170
+ });
2171
+ fileList.slice(1).forEach(function ({
2172
+ linesCovered,
2173
+ linesTotal,
2174
+ modeCoverageIgnoreFile,
2175
+ pathname
2176
+ }) {
2177
+ if (!modeCoverageIgnoreFile) {
2178
+ fileList[0].linesCovered += linesCovered;
2179
+ fileList[0].linesTotal += linesTotal;
1483
2180
  }
1484
- txtBorder = (
1485
- "+" + "-".repeat(padPathname + 2) + "+"
1486
- + "-".repeat(padLines + 2) + "+\n"
2181
+ padPathname = Math.max(padPathname, pathname.length + 2);
2182
+ padLines = Math.max(
2183
+ padLines,
2184
+ String(linesCovered + " / " + linesTotal).length
1487
2185
  );
1488
- txt = "";
1489
- txt += "coverage-report\n";
1490
- txt += txtBorder;
1491
- txt += (
1492
- "| " + String("files covered").padEnd(padPathname, " ") + " | "
1493
- + String("lines").padStart(padLines, " ") + " |\n"
2186
+ });
2187
+ }
2188
+ txtBorder = (
2189
+ "+" + "-".repeat(padPathname + 2) + "+"
2190
+ + "-".repeat(padLines + 2) + "+\n"
2191
+ );
2192
+ txt = "";
2193
+ txt += "V8 Coverage Report\n";
2194
+ txt += txtBorder;
2195
+ txt += (
2196
+ "| " + String("Files covered").padEnd(padPathname, " ") + " | "
2197
+ + String("Lines").padStart(padLines, " ") + " |\n"
2198
+ );
2199
+ txt += txtBorder;
2200
+ fileList.forEach(function ({
2201
+ linesCovered,
2202
+ linesTotal,
2203
+ modeCoverageIgnoreFile,
2204
+ pathname
2205
+ }, ii) {
2206
+ let coverageLevel;
2207
+ let coveragePct;
2208
+ let fill;
2209
+ let str1;
2210
+ let str2;
2211
+ let xx1;
2212
+ let xx2;
2213
+ coveragePct = Math.floor(10000 * linesCovered / linesTotal || 0);
2214
+ coverageLevel = (
2215
+ modeCoverageIgnoreFile
2216
+ ? "coverageIgnore"
2217
+ : coveragePct >= 8000
2218
+ ? "coverageHigh"
2219
+ : coveragePct >= 5000
2220
+ ? "coverageMedium"
2221
+ : "coverageLow"
2222
+ );
2223
+ coveragePct = String(coveragePct).replace((
2224
+ /..$/m
2225
+ ), ".$&");
2226
+ if (modeIndex && ii === 0) {
2227
+ fill = (
2228
+ "#" + Math.round(
2229
+ (100 - Number(coveragePct)) * 2.21
2230
+ ).toString(16).padStart(2, "0")
2231
+ + Math.round(
2232
+ Number(coveragePct) * 2.21
2233
+ ).toString(16).padStart(2, "0")
2234
+ + "00"
1494
2235
  );
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(`
2236
+ str1 = "coverage";
2237
+ str2 = coveragePct + " %";
2238
+ xx1 = 6 * str1.length + 20;
2239
+ xx2 = 6 * str2.length + 20;
2240
+ promiseList.push(fsWriteFileWithParents((
2241
+ coverageDir + "coverage_badge.svg"
2242
+ ), String(`
1540
2243
  <svg height="20" width="${xx1 + xx2}" xmlns="http://www.w3.org/2000/svg">
1541
2244
  <rect fill="#555" height="20" width="${xx1 + xx2}"/>
1542
2245
  <rect fill="${fill}" height="20" width="${xx2}" x="${xx1}"/>
1543
2246
  <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"
2247
+ fill="#fff"
2248
+ font-family="verdana, geneva, dejavu sans, sans-serif"
2249
+ font-size="11"
2250
+ font-weight="bold"
2251
+ text-anchor="middle"
1549
2252
  >
1550
2253
  <text x="${0.5 * xx1}" y="14">${str1}</text>
1551
2254
  <text x="${xx1 + 0.5 * xx2}" y="14">${str2}</text>
1552
2255
  </g>
1553
2256
  </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>
2257
+ `).trim() + "\n"));
2258
+ pathname = "";
2259
+ }
2260
+ txt += (
2261
+ "| "
2262
+ + String("./" + pathname).padEnd(padPathname, " ") + " | "
2263
+ + String(
2264
+ modeCoverageIgnoreFile + " " + coveragePct + " %"
2265
+ ).padStart(padLines, " ") + " |\n"
2266
+ );
2267
+ txt += (
2268
+ "| " + "*".repeat(
2269
+ Math.round(0.01 * coveragePct * padPathname)
2270
+ ).padEnd(padPathname, "_") + " | "
2271
+ + String(
2272
+ linesCovered + " / " + linesTotal
2273
+ ).padStart(padLines, " ") + " |\n"
2274
+ );
2275
+ txt += txtBorder;
2276
+ pathname = htmlEscape(pathname);
2277
+ html += String(`
2278
+ <tr>
2279
+ <td class="${coverageLevel}">
2280
+ ${(
2281
+ modeIndex
2282
+ ? (
2283
+ "<a href=\"" + (pathname || "index") + ".html\">. / "
2284
+ + pathname + "</a><br>"
2285
+ )
2286
+ : (
2287
+ "<a href=\""
2288
+ + "../".repeat(pathname.split("/").length - 1)
2289
+ + "index.html\">. / </a>"
2290
+ + pathname + "<br>"
2291
+ )
2292
+ )}
2293
+ <div class="percentbar">
2294
+ <div style="width: ${coveragePct}%;"></div>
2295
+ </div>
2296
+ </td>
2297
+ <td style="text-align: right;">
2298
+ ${modeCoverageIgnoreFile} ${coveragePct} %<br>
1591
2299
  ${linesCovered} / ${linesTotal}
1592
- </td>
1593
- </tr>`;
1594
- });
1595
- if (lineList) {
1596
- html += `</tbody>
2300
+ </td>
2301
+ <td style="text-align: right;">
2302
+ <br>
2303
+ ${linesTotal - linesCovered} / ${linesTotal}
2304
+ </td>
2305
+ </tr>
2306
+ `).trim() + "\n";
2307
+ });
2308
+ html += String(`
2309
+ </tbody>
1597
2310
  </table>
1598
2311
  </div>
2312
+ <!-- header end -->
2313
+ `).trim() + "\n";
2314
+ if (!modeIndex) {
2315
+ html += String(`
2316
+ <!-- content start -->
1599
2317
  <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(`
2318
+ `).trim() + "\n";
2319
+ lineList.forEach(function ({
2320
+ count,
2321
+ holeList,
2322
+ line,
2323
+ startOffset
2324
+ }, ii) {
2325
+ let chunk;
2326
+ let inHole;
2327
+ let lineHtml;
2328
+ let lineId;
2329
+ lineHtml = "";
2330
+ lineId = "line_" + (ii + 1);
2331
+ switch (count) {
2332
+ case -1:
2333
+ case 0:
2334
+ if (holeList.length === 0) {
2335
+ lineHtml += "</span>";
2336
+ lineHtml += "<span class=\"uncovered\">";
2337
+ lineHtml += htmlEscape(line);
2338
+ break;
2339
+ }
2340
+ line = line.split("").map(function (char) {
2341
+ return {
2342
+ char,
2343
+ isHole: undefined
2344
+ };
2345
+ });
2346
+ holeList.forEach(function ([
2347
+ aa, bb
2348
+ ]) {
2349
+ aa = Math.max(aa - startOffset, 0);
2350
+ bb = Math.min(bb - startOffset, line.length);
2351
+ while (aa < bb) {
2352
+ line[aa].isHole = true;
2353
+ aa += 1;
2354
+ }
2355
+ });
2356
+ chunk = "";
2357
+ line.forEach(function ({
2358
+ char,
2359
+ isHole
2360
+ }) {
2361
+ if (inHole !== isHole) {
2362
+ lineHtml += htmlEscape(chunk);
2363
+ lineHtml += "</span><span";
2364
+ if (isHole) {
2365
+ lineHtml += " class=\"uncovered\"";
2366
+ }
2367
+ lineHtml += ">";
2368
+ chunk = "";
2369
+ inHole = isHole;
2370
+ }
2371
+ chunk += char;
2372
+ });
2373
+ lineHtml += htmlEscape(chunk);
2374
+ break;
2375
+ default:
2376
+ lineHtml += htmlEscape(line);
2377
+ }
2378
+ html += String(`
1661
2379
  <pre>
1662
2380
  <span class="lineno">
1663
2381
  <a href="#${lineId}" id="${lineId}">${String(ii + 1).padStart(5, " ")}.</a>
1664
2382
  </span>
1665
2383
  <span class="count
1666
- ${(
1667
- count <= 0
1668
- ? "uncovered"
1669
- : ""
1670
- )}"
2384
+ ${(
2385
+ count <= 0
2386
+ ? "uncovered"
2387
+ : ""
2388
+ )}"
1671
2389
  >
1672
- ${String(count).padStart(7, " ")}
2390
+ ${String(count || "-0").padStart(7, " ")}
1673
2391
  </span>
1674
2392
  <span>${lineHtml}</span>
1675
2393
  </pre>
1676
- `).replace((
1677
- /\n/g
1678
- ), "").trim() + "\n";
1679
- });
1680
- }
1681
- html += `
2394
+ `).replace((
2395
+ /\n/g
2396
+ ), "").trim() + "\n";
2397
+ });
2398
+ html += String(`
1682
2399
  </div>
1683
- <div class="coverageFooter">
2400
+ <!-- content end -->
2401
+ `).trim() + "\n";
2402
+ }
2403
+ html += String(`
2404
+ <div class="footer">
2405
+ [
2406
+ This document was created with
2407
+ <a href="https://github.com/jslint-org/jslint">JSLint</a>
2408
+ ]
1684
2409
  </div>
1685
2410
  </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);
2411
+ </html>
2412
+ `).trim() + "\n";
2413
+ promiseList.push(fsWriteFileWithParents(pathname + ".html", html));
2414
+ if (!modeIndex) {
2415
+ return;
1701
2416
  }
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
- }
2417
+ consoleError("\n" + txt);
2418
+ promiseList.push(fsWriteFileWithParents((
2419
+ coverageDir + "coverage_report.txt"
2420
+ ), txt));
2421
+ }
2422
+
2423
+ function pathnameRelativeCwd(pathname) {
2424
+ pathname = modulePath.resolve(pathname).replace((
2425
+ /\\/g
2426
+ ), "/");
2427
+ if (!pathname.startsWith(cwd)) {
2428
+ return;
2429
+ }
2430
+ pathname = pathname.slice(cwd.length);
2431
+ return pathname;
2432
+ }
2433
+
2434
+ /*
2435
+ function sentinel() {}
2436
+ */
2437
+
2438
+ await moduleFsInit();
2439
+ consoleError = consoleError || console.error;
2440
+ cwd = process.cwd().replace((
2441
+ /\\/g
2442
+ ), "/") + "/";
2443
+ assertOrThrow(coverageDir, "invalid coverageDir " + coverageDir);
2444
+ coverageDir = modulePath.resolve(coverageDir).replace((
2445
+ /\\/g
2446
+ ), "/") + "/";
2447
+
2448
+ processArgv = processArgv.slice();
2449
+ while (processArgv[0] && processArgv[0][0] === "-") {
2450
+ processArgElem = processArgv.shift().split("=");
2451
+ processArgElem[1] = processArgElem.slice(1).join("=");
2452
+ switch (processArgElem[0]) {
2453
+ case "--exclude":
2454
+ fileExcludeList = fileExcludeList.concat(
2455
+ processArgElem[1].split(",")
2456
+ );
2457
+ break;
2458
+ case "--exclude-node-modules":
2459
+ fileIncludeNodeModules = (
2460
+ /0|false|null|undefined/
2461
+ ).test(processArgElem[1]);
2462
+ break;
2463
+ case "--include":
2464
+ fileIncludeList = fileIncludeList.concat(
2465
+ processArgElem[1].split(",")
2466
+ );
2467
+ break;
2468
+ }
2469
+ }
2470
+ if (processArgv.length > 0) {
2471
+ await fsWriteFileWithParents(coverageDir + "/touch.txt", "");
2472
+ await Promise.all(Array.from(
2473
+ await moduleFs.promises.readdir(coverageDir)
2474
+ ).map(async function (file) {
2475
+ if ((
2476
+ /^coverage-\d+?-\d+?-\d+?\.json$/
2477
+ ).test(file)) {
2478
+ console.error("rm file " + coverageDir + file);
2479
+ await moduleFs.promises.unlink(coverageDir + file);
2480
+ }
1716
2481
  }));
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
2482
+ exitCode = await new Promise(function (resolve) {
2483
+ moduleChildProcess.spawn((
2484
+ processArgv[0] === "npm"
2485
+ ? process.platform.replace("win32", "npm.cmd").replace(
2486
+ process.platform,
2487
+ "npm"
2488
+ )
2489
+ : processArgv[0]
2490
+ ), processArgv.slice(1), {
2491
+ env: Object.assign({}, process.env, {
2492
+ NODE_V8_COVERAGE: coverageDir
2493
+ }),
2494
+ stdio: [
2495
+ "ignore", 1, 2
2496
+ ]
2497
+ }).on("exit", resolve);
2498
+ });
2499
+ }
2500
+ v8CoverageObj = await moduleFs.promises.readdir(coverageDir);
2501
+ v8CoverageObj = v8CoverageObj.filter(function (file) {
2502
+ return (
2503
+ /^coverage-\d+?-\d+?-\d+?\.json$/
2504
+ ).test(file);
2505
+ });
2506
+ v8CoverageObj = await Promise.all(v8CoverageObj.map(async function (file) {
2507
+ let data = await moduleFs.promises.readFile(coverageDir + file, "utf8");
2508
+ data = JSON.parse(data);
2509
+ data.result = data.result.filter(function (scriptCov) {
2510
+ let pathname = scriptCov.url;
2511
+ if (!pathname.startsWith("file:///")) {
2512
+ return;
2513
+ }
2514
+ pathname = pathnameRelativeCwd(moduleUrl.fileURLToPath(pathname));
2515
+ if (
2516
+ !pathname
2517
+ || pathname.startsWith("[")
2518
+ || (
2519
+ !fileIncludeNodeModules
2520
+ && (
2521
+ /(?:^|\/)node_modules\//m
2522
+ ).test(pathname)
2523
+ )
2524
+ || fileExcludeList.indexOf(pathname) >= 0
2525
+ || (
2526
+ fileIncludeList.length > 0
2527
+ && fileIncludeList.indexOf(pathname) === -1
2528
+ )
2529
+ ) {
2530
+ return;
2531
+ }
2532
+ scriptCov.url = pathname;
2533
+ return true;
2534
+ });
2535
+ return data;
2536
+ }));
2537
+ v8CoverageObj = v8CoverageListMerge(v8CoverageObj);
2538
+ await fsWriteFileWithParents(
2539
+ coverageDir + "v8_coverage_merged.json",
2540
+ JSON.stringify(v8CoverageObj, undefined, 1)
2541
+ );
2542
+ fileDict = {};
2543
+ await Promise.all(v8CoverageObj.result.map(async function ({
2544
+ functions,
2545
+ url: pathname
2546
+ }) {
2547
+ let lineList;
2548
+ let linesCovered;
2549
+ let linesTotal;
2550
+ let source;
2551
+ source = await moduleFs.promises.readFile(pathname, "utf8");
2552
+ lineList = [{}];
2553
+ source.replace((
2554
+ /^.*$/gm
2555
+ ), function (line, startOffset) {
2556
+ lineList[lineList.length - 1].endOffset = startOffset - 1;
2557
+ lineList.push({
2558
+ count: -1,
2559
+ endOffset: 0,
2560
+ holeList: [],
2561
+ line,
2562
+ startOffset
2563
+ });
2564
+ return "";
2565
+ });
2566
+ lineList.shift();
2567
+ lineList[lineList.length - 1].endOffset = source.length;
2568
+ functions.reverse().forEach(function ({
2569
+ ranges
1724
2570
  }) {
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
2571
+ ranges.reverse().forEach(function ({
2572
+ count,
2573
+ endOffset,
2574
+ startOffset
2575
+ }, ii, list) {
2576
+ lineList.forEach(function (elem) {
2577
+ if (!(
2578
+ (
2579
+ elem.startOffset <= startOffset
2580
+ && startOffset <= elem.endOffset
2581
+ ) || (
2582
+ elem.startOffset <= endOffset
2583
+ && endOffset <= elem.endOffset
2584
+ ) || (
2585
+ startOffset <= elem.startOffset
2586
+ && elem.endOffset <= endOffset
1746
2587
  )
1747
- ) {
2588
+ )) {
1748
2589
  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
2590
+ }
2591
+ if (ii + 1 === list.length) {
2592
+ if (elem.count === -1) {
2593
+ elem.count = count;
2594
+ }
2595
+ return;
2596
+ }
2597
+ if (elem.count !== 0) {
2598
+ elem.count = Math.max(count, elem.count);
2599
+ }
2600
+ if (count === 0) {
2601
+ elem.count = 0;
2602
+ elem.holeList.push([
2603
+ startOffset, endOffset
2604
+ ]);
2605
+ }
1832
2606
  });
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"
2607
+ });
1846
2608
  });
1847
- }());
1848
- ' # "'
1849
- find "$DIR_COVERAGE"
1850
- fi
1851
- printf "shRunWithCoverage - EXIT_CODE=$EXIT_CODE\n" 1>&2
1852
- return "$EXIT_CODE"
2609
+ linesTotal = lineList.length;
2610
+ linesCovered = lineList.filter(function ({
2611
+ count
2612
+ }) {
2613
+ return count > 0;
2614
+ }).length;
2615
+ await moduleFs.promises.mkdir((
2616
+ modulePath.dirname(coverageDir + pathname)
2617
+ ), {
2618
+ recursive: true
2619
+ });
2620
+ fileDict[pathname] = {
2621
+ lineList,
2622
+ linesCovered,
2623
+ linesTotal,
2624
+ modeCoverageIgnoreFile: (
2625
+ (
2626
+ /^\/\*coverage-ignore-file\*\/$/m
2627
+ ).test(source.slice(0, 65536))
2628
+ ? "(ignore)"
2629
+ : ""
2630
+ ),
2631
+ pathname
2632
+ };
2633
+ htmlRender({
2634
+ fileList: [
2635
+ fileDict[pathname]
2636
+ ],
2637
+ lineList,
2638
+ pathname: coverageDir + pathname
2639
+ });
2640
+ }));
2641
+ htmlRender({
2642
+ fileList: Object.keys(fileDict).sort().map(function (pathname) {
2643
+ return fileDict[pathname];
2644
+ }),
2645
+ modeIndex: true,
2646
+ pathname: coverageDir + "index"
2647
+ });
2648
+ await Promise.all(promiseList);
2649
+ assertOrThrow(
2650
+ exitCode === 0,
2651
+ "v8CoverageReportCreate - nonzero exitCode " + exitCode
2652
+ );
2653
+ }
2654
+ v8CoverageReportCreate({
2655
+ coverageDir: ".artifact/coverage",
2656
+ processArgv: process.argv.slice(2)
2657
+ });
2658
+ ' 0 "$@" # '
1853
2659
  )}
1854
2660
 
1855
2661
  shRunWithScreenshotTxt() {(set -e
@@ -1866,9 +2672,10 @@ shRunWithScreenshotTxt() {(set -e
1866
2672
  "$@" 2>&1 || printf "$?\n" > "$SCREENSHOT_SVG.exit_code"
1867
2673
  ) | tee "$SCREENSHOT_SVG.txt"
1868
2674
  EXIT_CODE="$(cat "$SCREENSHOT_SVG.exit_code")"
1869
- printf "shRunWithScreenshotTxt - EXIT_CODE=$EXIT_CODE\n" 1>&2
2675
+ printf "shRunWithScreenshotTxt - EXIT_CODE=$EXIT_CODE - $SCREENSHOT_SVG\n" \
2676
+ 1>&2
1870
2677
  # format text-output
1871
- node --input-type=module -e '
2678
+ node --input-type=module --eval '
1872
2679
  import moduleFs from "fs";
1873
2680
  (async function () {
1874
2681
  let result = await moduleFs.promises.readFile(
@@ -1935,7 +2742,7 @@ ${result}
1935
2742
  `).trim() + "\n";
1936
2743
  moduleFs.promises.writeFile(process.argv[1], result);
1937
2744
  }());
1938
- ' "$SCREENSHOT_SVG" # "'
2745
+ ' "$SCREENSHOT_SVG" # '
1939
2746
  printf "shRunWithScreenshotTxt - wrote - $SCREENSHOT_SVG\n"
1940
2747
  # cleanup
1941
2748
  rm "$SCREENSHOT_SVG.exit_code" "$SCREENSHOT_SVG.txt"
@@ -1943,7 +2750,11 @@ ${result}
1943
2750
  )}
1944
2751
 
1945
2752
  shCiMain() {(set -e
1946
- # run $@
2753
+ # this function will run $@
2754
+ if [ "$1" = "" ]
2755
+ then
2756
+ return
2757
+ fi
1947
2758
  # run "$@" with winpty
1948
2759
  export CI_UNAME="${CI_UNAME:-$(uname)}"
1949
2760
  case "$CI_UNAME" in
@@ -1951,7 +2762,7 @@ shCiMain() {(set -e
1951
2762
  if [ ! "$CI_WINPTY" ] && [ "$1" != shHttpFileServer ]
1952
2763
  then
1953
2764
  export CI_WINPTY=1
1954
- winpty -Xallow-non-tty -Xplain sh jslint_ci.sh "$@"
2765
+ winpty -Xallow-non-tty -Xplain sh "$0" "$@"
1955
2766
  return
1956
2767
  fi
1957
2768
  ;;
@@ -1965,4 +2776,7 @@ shCiMain() {(set -e
1965
2776
  "$@"
1966
2777
  )}
1967
2778
 
2779
+ # init ubuntu .bashrc
2780
+ shBashrcDebianInit || return "$?"
2781
+
1968
2782
  shCiMain "$@"