wsemi 1.9.13 → 1.9.15

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 (516) hide show
  1. package/README.md +1 -1
  2. package/dist/wsemi.umd.js +7 -7
  3. package/dist/wsemi.umd.js.map +1 -1
  4. package/docs/-_class.mjs.html +1 -1
  5. package/docs/-_const.mjs.html +1 -1
  6. package/docs/-_detector.mjs.html +1 -1
  7. package/docs/-_optNum.mjs.html +1 -1
  8. package/docs/ab2blob.mjs.html +1 -1
  9. package/docs/ab2u8arr.mjs.html +1 -1
  10. package/docs/addExcelWorksheetFromData.mjs.html +1 -1
  11. package/docs/addMonth.mjs.html +1 -1
  12. package/docs/aes2str.mjs.html +1 -1
  13. package/docs/alive.mjs.html +106 -5
  14. package/docs/arr2dt.mjs.html +1 -1
  15. package/docs/arrAccum.mjs.html +1 -1
  16. package/docs/arrAdd.mjs.html +1 -1
  17. package/docs/arrAt.mjs.html +1 -1
  18. package/docs/arrDiff.mjs.html +1 -1
  19. package/docs/arrFilterByKeywords.mjs.html +1 -1
  20. package/docs/arrFilterByNum.mjs.html +1 -1
  21. package/docs/arrFilterByPnum.mjs.html +1 -1
  22. package/docs/arrFilterByPnumAndToLog.mjs.html +1 -1
  23. package/docs/arrFind.mjs.html +1 -1
  24. package/docs/arrGroupByMaxmin.mjs.html +1 -1
  25. package/docs/arrHas.mjs.html +1 -1
  26. package/docs/arrInsert.mjs.html +1 -1
  27. package/docs/arrLookupByMaxmin.mjs.html +1 -1
  28. package/docs/arrMax.mjs.html +1 -1
  29. package/docs/arrMin.mjs.html +1 -1
  30. package/docs/arrMulti.mjs.html +1 -1
  31. package/docs/arrNorm.mjs.html +1 -1
  32. package/docs/arrProduct.mjs.html +1 -1
  33. package/docs/arrPull.mjs.html +1 -1
  34. package/docs/arrPullAt.mjs.html +1 -1
  35. package/docs/arrReduce.mjs.html +1 -1
  36. package/docs/arrReverse.mjs.html +1 -1
  37. package/docs/arrSep.mjs.html +1 -1
  38. package/docs/arrSort.mjs.html +1 -1
  39. package/docs/asind.mjs.html +1 -1
  40. package/docs/atan2d.mjs.html +1 -1
  41. package/docs/atand.mjs.html +1 -1
  42. package/docs/attstr.mjs.html +1 -1
  43. package/docs/b642obj.mjs.html +1 -1
  44. package/docs/b642str.mjs.html +1 -1
  45. package/docs/b642u16arr.mjs.html +1 -1
  46. package/docs/b642u8arr.mjs.html +1 -1
  47. package/docs/binstr.mjs.html +1 -1
  48. package/docs/blob2ab.mjs.html +1 -1
  49. package/docs/blob2b64.mjs.html +1 -1
  50. package/docs/blob2str.mjs.html +1 -1
  51. package/docs/blob2u8arr.mjs.html +1 -1
  52. package/docs/blobs2b64s.mjs.html +1 -1
  53. package/docs/blobs2u8arrs.mjs.html +1 -1
  54. package/docs/bodyLog.mjs.html +1 -1
  55. package/docs/browserView.mjs.html +1 -1
  56. package/docs/browserViewFromBlob.mjs.html +1 -1
  57. package/docs/browserViewFromText.mjs.html +1 -1
  58. package/docs/browserViewFromU8arr.mjs.html +1 -1
  59. package/docs/bs2u8arr.mjs.html +1 -1
  60. package/docs/bufRead.mjs.html +1 -1
  61. package/docs/bufReadDbl.mjs.html +1 -1
  62. package/docs/bufWrite.mjs.html +1 -1
  63. package/docs/bufWriteDbl.mjs.html +1 -1
  64. package/docs/cache.mjs.html +3 -3
  65. package/docs/cacheBd.mjs.html +1 -1
  66. package/docs/cacheSt.mjs.html +2 -2
  67. package/docs/cbol.mjs.html +1 -1
  68. package/docs/cdbl.mjs.html +1 -1
  69. package/docs/ceil.mjs.html +1 -1
  70. package/docs/cfilesize.mjs.html +1 -1
  71. package/docs/cfinancial.mjs.html +1 -1
  72. package/docs/cint.mjs.html +1 -1
  73. package/docs/clearXSS.mjs.html +1 -1
  74. package/docs/clearXSSDyn.mjs.html +1 -1
  75. package/docs/color.mjs.html +1 -1
  76. package/docs/composeToTree.mjs.html +1 -1
  77. package/docs/convertToTree.mjs.html +1 -1
  78. package/docs/copyStrToClipboard.mjs.html +1 -1
  79. package/docs/cosd.mjs.html +1 -1
  80. package/docs/cotd.mjs.html +1 -1
  81. package/docs/createExcelWorkbook.mjs.html +1 -1
  82. package/docs/cscd.mjs.html +1 -1
  83. package/docs/cstr.mjs.html +1 -1
  84. package/docs/day2cht.mjs.html +1 -1
  85. package/docs/debounce.mjs.html +1 -1
  86. package/docs/delay.mjs.html +1 -1
  87. package/docs/detectXSS.mjs.html +1 -1
  88. package/docs/detectXSSDyn.mjs.html +1 -1
  89. package/docs/dig.mjs.html +1 -1
  90. package/docs/digExp.mjs.html +1 -1
  91. package/docs/domAlert.mjs.html +1 -1
  92. package/docs/domAppend.mjs.html +1 -1
  93. package/docs/domCancelEvent.mjs.html +1 -1
  94. package/docs/domCompareText.mjs.html +1 -1
  95. package/docs/domConvertToPic.mjs.html +1 -1
  96. package/docs/domConvertToPicDyn.mjs.html +1 -1
  97. package/docs/domDetect.mjs.html +1 -1
  98. package/docs/domDrag.mjs.html +1 -1
  99. package/docs/domDragBarAndScroll.mjs.html +1 -1
  100. package/docs/domDragPointer.mjs.html +1 -1
  101. package/docs/domDragPreview.mjs.html +1 -1
  102. package/docs/domDropFiles.mjs.html +1 -1
  103. package/docs/domElementsFromPoint.mjs.html +1 -1
  104. package/docs/domFadeIn.mjs.html +1 -1
  105. package/docs/domFadeOut.mjs.html +1 -1
  106. package/docs/domFind.mjs.html +1 -1
  107. package/docs/domFinds.mjs.html +1 -1
  108. package/docs/domGetAttr.mjs.html +1 -1
  109. package/docs/domGetBoudRect.mjs.html +1 -1
  110. package/docs/domGetBoudRectRefSelf.mjs.html +1 -1
  111. package/docs/domGetFileAccept.mjs.html +1 -1
  112. package/docs/domGetFiles.mjs.html +1 -1
  113. package/docs/domGetParents.mjs.html +1 -1
  114. package/docs/domGetPointFromEvent.mjs.html +1 -1
  115. package/docs/domGetScrollableParent.mjs.html +1 -1
  116. package/docs/domGetWindowSize.mjs.html +1 -1
  117. package/docs/domIsClientXYIn.mjs.html +1 -1
  118. package/docs/domIsFocused.mjs.html +1 -1
  119. package/docs/domIsRendered.mjs.html +1 -1
  120. package/docs/domIsStable.mjs.html +1 -1
  121. package/docs/domIsVisible.mjs.html +1 -1
  122. package/docs/domPrepend.mjs.html +1 -1
  123. package/docs/domRemove.mjs.html +1 -1
  124. package/docs/domRenderMarkdownMind.mjs.html +1 -1
  125. package/docs/domRenderMarkdownMindDyn.mjs.html +1 -1
  126. package/docs/domRipple.mjs.html +1 -1
  127. package/docs/domScrollIntoView.mjs.html +1 -1
  128. package/docs/domScrollTo.mjs.html +1 -1
  129. package/docs/domSetAttr.mjs.html +1 -1
  130. package/docs/domShowImages.mjs.html +1 -1
  131. package/docs/domShowImagesDyn.mjs.html +1 -1
  132. package/docs/domShowInputAndGetFiles.mjs.html +1 -1
  133. package/docs/domShowInputAndGetFilesU8Arrs.mjs.html +1 -1
  134. package/docs/domShowInputDatatime.mjs.html +1 -1
  135. package/docs/domTooltip.mjs.html +1 -1
  136. package/docs/domTriggerEvent.mjs.html +1 -1
  137. package/docs/domVirtualCreate.mjs.html +1 -1
  138. package/docs/domVirtualCreateQueue.mjs.html +1 -1
  139. package/docs/downloadExcelFileFromData.mjs.html +1 -1
  140. package/docs/downloadExcelFileFromDataDyn.mjs.html +1 -1
  141. package/docs/downloadFileFromB64.mjs.html +1 -1
  142. package/docs/downloadFileFromBlob.mjs.html +1 -1
  143. package/docs/downloadFileFromText.mjs.html +1 -1
  144. package/docs/downloadFileFromU8Arr.mjs.html +1 -1
  145. package/docs/dtmapping.mjs.html +1 -1
  146. package/docs/dtpick.mjs.html +1 -1
  147. package/docs/estimateTicks.mjs.html +1 -1
  148. package/docs/evEmit.mjs.html +2 -2
  149. package/docs/evEmitDelay.mjs.html +1 -1
  150. package/docs/evem.mjs.html +1 -1
  151. package/docs/examples/ex-blob2b64.html +1 -1
  152. package/docs/examples/ex-clearXSS.html +1 -1
  153. package/docs/examples/ex-clearXSSDyn.html +1 -1
  154. package/docs/examples/ex-colorConverter.html +1 -1
  155. package/docs/examples/ex-detectXSS.html +1 -1
  156. package/docs/examples/ex-detectXSSDyn.html +1 -1
  157. package/docs/examples/ex-domCompareText.html +1 -1
  158. package/docs/examples/ex-domConvertToPic.html +1 -1
  159. package/docs/examples/ex-domDrag.html +1 -1
  160. package/docs/examples/ex-domDropFiles.html +1 -1
  161. package/docs/examples/ex-domIsVisible.html +1 -1
  162. package/docs/examples/ex-domRenderMarkdownMind.html +1 -1
  163. package/docs/examples/ex-domRenderMarkdownMindDyn.html +1 -1
  164. package/docs/examples/ex-domRipple.html +1 -1
  165. package/docs/examples/ex-domScrollIntoView.html +1 -1
  166. package/docs/examples/ex-domScrollTo.html +1 -1
  167. package/docs/examples/ex-domShowImages.html +1 -1
  168. package/docs/examples/ex-domShowImagesDyn.html +1 -1
  169. package/docs/examples/ex-domShowInputAndGetFiles.html +1 -1
  170. package/docs/examples/ex-domTooltip.html +1 -1
  171. package/docs/examples/ex-getFileHash.html +1 -1
  172. package/docs/examples/ex-getUserAgent.html +1 -1
  173. package/docs/examples/ex-getUserAgentDyn.html +1 -1
  174. package/docs/examples/ex-html2str.html +1 -1
  175. package/docs/examples/ex-obj2u8arr-u8arr2obj.html +1 -1
  176. package/docs/examples/ex-openLink.html +1 -1
  177. package/docs/examples/ex-str2aes-aes2str.html +1 -1
  178. package/docs/examples/ex-str2b64-b642str.html +1 -1
  179. package/docs/examples/ex-strFindFuzz.html +1 -1
  180. package/docs/examples/ex-timeTZ2expire-timeTZ2past.html +1 -1
  181. package/docs/examples/ex-xlsx.html +1 -1
  182. package/docs/execCli.mjs.html +67 -33
  183. package/docs/execCliCore.mjs.html +4 -1
  184. package/docs/execCliJsonRpc.mjs.html +3 -3
  185. package/docs/execCliSession.mjs.html +24 -12
  186. package/docs/execJsCode.mjs.html +1 -1
  187. package/docs/execProcess.mjs.html +58 -35
  188. package/docs/execProcessKillPid.mjs.html +5 -3
  189. package/docs/filepathToTree.mjs.html +1 -1
  190. package/docs/files2data.mjs.html +1 -1
  191. package/docs/flattenToConn.mjs.html +1 -1
  192. package/docs/flattenTree.mjs.html +1 -1
  193. package/docs/floor.mjs.html +1 -1
  194. package/docs/fsBuildReadStreamText.mjs.html +1 -1
  195. package/docs/fsBuildWriteStreamText.mjs.html +1 -1
  196. package/docs/fsCleanFolder.mjs.html +1 -1
  197. package/docs/fsCleanFolderCore.mjs.html +1 -1
  198. package/docs/fsCopyFile.mjs.html +1 -1
  199. package/docs/fsCopyFileCore.mjs.html +1 -1
  200. package/docs/fsCopyFolder.mjs.html +1 -1
  201. package/docs/fsCopyFolderCore.mjs.html +1 -1
  202. package/docs/fsCreateFile.mjs.html +1 -1
  203. package/docs/fsCreateFileCore.mjs.html +1 -1
  204. package/docs/fsCreateFolder.mjs.html +1 -1
  205. package/docs/fsCreateFolderCore.mjs.html +1 -1
  206. package/docs/fsDeleteFile.mjs.html +1 -1
  207. package/docs/fsDeleteFileCore.mjs.html +1 -1
  208. package/docs/fsDeleteFileSafe.mjs.html +1 -1
  209. package/docs/fsDeleteFileSafeCore.mjs.html +1 -1
  210. package/docs/fsDeleteFolder.mjs.html +1 -1
  211. package/docs/fsDeleteFolderCore.mjs.html +1 -1
  212. package/docs/fsDeleteFolderSafe.mjs.html +1 -1
  213. package/docs/fsDeleteFolderSafeCore.mjs.html +1 -1
  214. package/docs/fsDownloadFile.mjs.html +1 -1
  215. package/docs/fsDownloadFileCore.mjs.html +1 -1
  216. package/docs/fsEvem.mjs.html +1 -1
  217. package/docs/fsExists.mjs.html +1 -1
  218. package/docs/fsExistsCore.mjs.html +1 -1
  219. package/docs/fsGetFileBasicHash.mjs.html +1 -1
  220. package/docs/fsGetFileBasicHashCore.mjs.html +1 -1
  221. package/docs/fsGetFileHash.mjs.html +1 -1
  222. package/docs/fsGetFileHashCore.mjs.html +1 -1
  223. package/docs/fsGetFileXxHash.mjs.html +1 -1
  224. package/docs/fsGetFileXxHashCore.mjs.html +1 -1
  225. package/docs/fsGetFilesInFolder.mjs.html +1 -1
  226. package/docs/fsGetFilesInFolderCore.mjs.html +1 -1
  227. package/docs/fsGetFilesWithHashInFolder.mjs.html +1 -1
  228. package/docs/fsGetFilesWithHashInFolderCore.mjs.html +1 -1
  229. package/docs/fsGetFolderBasicHash.mjs.html +1 -1
  230. package/docs/fsGetFolderBasicHashCore.mjs.html +1 -1
  231. package/docs/fsGetFoldersInFolder.mjs.html +1 -1
  232. package/docs/fsGetFoldersInFolderCore.mjs.html +1 -1
  233. package/docs/fsIsFile.mjs.html +1 -1
  234. package/docs/fsIsFileCore.mjs.html +1 -1
  235. package/docs/fsIsFolder.mjs.html +1 -1
  236. package/docs/fsIsFolderCore.mjs.html +1 -1
  237. package/docs/fsMergeFiles.mjs.html +1 -1
  238. package/docs/fsMergeFilesCore.mjs.html +1 -1
  239. package/docs/fsReadJson.mjs.html +1 -1
  240. package/docs/fsReadText.mjs.html +1 -1
  241. package/docs/fsReadTextCore.mjs.html +1 -1
  242. package/docs/fsRenameFile.mjs.html +1 -1
  243. package/docs/fsRenameFileCore.mjs.html +1 -1
  244. package/docs/fsRenameFolder.mjs.html +1 -1
  245. package/docs/fsRenameFolderCore.mjs.html +1 -1
  246. package/docs/fsSrlog.mjs.html +1 -1
  247. package/docs/fsSyncFolder.mjs.html +1 -1
  248. package/docs/fsSyncFolderCore.mjs.html +1 -1
  249. package/docs/fsTask.mjs.html +1 -1
  250. package/docs/fsTaskCp.mjs.html +1 -1
  251. package/docs/fsTreeFolder.mjs.html +1 -1
  252. package/docs/fsTreeFolderCore.mjs.html +1 -1
  253. package/docs/fsTreeFolderWithHash.mjs.html +1 -1
  254. package/docs/fsTreeFolderWithHashCore.mjs.html +1 -1
  255. package/docs/fsWatchFile.mjs.html +1 -1
  256. package/docs/fsWatchFolder.mjs.html +1 -1
  257. package/docs/fsWriteJson.mjs.html +1 -1
  258. package/docs/fsWriteText.mjs.html +1 -1
  259. package/docs/fsWriteTextCore.mjs.html +1 -1
  260. package/docs/genGradientColor.mjs.html +1 -1
  261. package/docs/genID.mjs.html +1 -1
  262. package/docs/genIDSeq.mjs.html +1 -1
  263. package/docs/genPm.mjs.html +1 -1
  264. package/docs/getBufferSize.mjs.html +1 -1
  265. package/docs/getClearPathName.mjs.html +1 -1
  266. package/docs/getCsvStrFromData.mjs.html +1 -1
  267. package/docs/getDataFromExcelFileU8Arr.mjs.html +1 -1
  268. package/docs/getDataFromExcelFileU8ArrDyn.mjs.html +1 -1
  269. package/docs/getEnv.mjs.html +1 -1
  270. package/docs/getErrorMessage.mjs.html +1 -1
  271. package/docs/getExcelU8ArrFromData.mjs.html +1 -1
  272. package/docs/getExcelU8ArrFromWorkbook.mjs.html +1 -1
  273. package/docs/getExcelWorkbookFromData.mjs.html +1 -1
  274. package/docs/getExcelWorkbookFromWorksheet.mjs.html +1 -1
  275. package/docs/getExcelWorksheetFromData.mjs.html +1 -1
  276. package/docs/getFileAccept.mjs.html +1 -1
  277. package/docs/getFileBasicHash.mjs.html +1 -1
  278. package/docs/getFileHash.mjs.html +1 -1
  279. package/docs/getFileName.mjs.html +1 -1
  280. package/docs/getFileNameExt.mjs.html +1 -1
  281. package/docs/getFileTrueName.mjs.html +1 -1
  282. package/docs/getFileType.mjs.html +1 -1
  283. package/docs/getFileXxHash.mjs.html +1 -1
  284. package/docs/getGlobal.mjs.html +1 -1
  285. package/docs/getObjSize.mjs.html +1 -1
  286. package/docs/getPathParent.mjs.html +1 -1
  287. package/docs/getTimeBetween.mjs.html +1 -1
  288. package/docs/getTimeFromUnit.mjs.html +1 -1
  289. package/docs/getTimeHp.mjs.html +1 -1
  290. package/docs/getTimeObject.mjs.html +1 -1
  291. package/docs/getTimeRange.mjs.html +1 -1
  292. package/docs/getUserAgent.mjs.html +1 -1
  293. package/docs/getUserAgentDyn.mjs.html +1 -1
  294. package/docs/getltdtkeys.mjs.html +1 -1
  295. package/docs/global.html +7 -7
  296. package/docs/haskey.mjs.html +1 -1
  297. package/docs/html2str.mjs.html +1 -1
  298. package/docs/htmlDecode.mjs.html +1 -1
  299. package/docs/htmlEncode.mjs.html +1 -1
  300. package/docs/importResources.mjs.html +1 -1
  301. package/docs/index.html +1 -1
  302. package/docs/interp1.mjs.html +1 -1
  303. package/docs/isDate.mjs.html +1 -1
  304. package/docs/isDev.mjs.html +1 -1
  305. package/docs/isEle.mjs.html +1 -1
  306. package/docs/isEleExistByID.mjs.html +1 -1
  307. package/docs/isEmail.mjs.html +1 -1
  308. package/docs/isErr.mjs.html +1 -1
  309. package/docs/isIE.mjs.html +1 -1
  310. package/docs/isNarrow.mjs.html +1 -1
  311. package/docs/isStrHasCapital.mjs.html +1 -1
  312. package/docs/isStrHasLetter.mjs.html +1 -1
  313. package/docs/isStrHasLowerCase.mjs.html +1 -1
  314. package/docs/isStrHasNumber.mjs.html +1 -1
  315. package/docs/isStrHasSpace.mjs.html +1 -1
  316. package/docs/isStrHasSymbol.mjs.html +1 -1
  317. package/docs/isUserIdentify.mjs.html +1 -1
  318. package/docs/isUserName.mjs.html +1 -1
  319. package/docs/isUserPw.mjs.html +1 -1
  320. package/docs/isWindow.mjs.html +1 -1
  321. package/docs/isab.mjs.html +1 -1
  322. package/docs/isarr.mjs.html +1 -1
  323. package/docs/isarr0.mjs.html +1 -1
  324. package/docs/isarr1.mjs.html +1 -1
  325. package/docs/isbigint.mjs.html +1 -1
  326. package/docs/isblob.mjs.html +1 -1
  327. package/docs/isbol.mjs.html +1 -1
  328. package/docs/isday.mjs.html +1 -1
  329. package/docs/isearr.mjs.html +1 -1
  330. package/docs/iseobj.mjs.html +1 -1
  331. package/docs/iser.mjs.html +1 -1
  332. package/docs/isernot.mjs.html +1 -1
  333. package/docs/isestr.mjs.html +1 -1
  334. package/docs/isfile.mjs.html +1 -1
  335. package/docs/isfun.mjs.html +1 -1
  336. package/docs/isint.mjs.html +1 -1
  337. package/docs/ismonth.mjs.html +1 -1
  338. package/docs/isn0int.mjs.html +1 -1
  339. package/docs/isn0num.mjs.html +1 -1
  340. package/docs/isnan.mjs.html +1 -1
  341. package/docs/isnbr.mjs.html +1 -1
  342. package/docs/isnint.mjs.html +1 -1
  343. package/docs/isnnum.mjs.html +1 -1
  344. package/docs/isnull.mjs.html +1 -1
  345. package/docs/isnum.mjs.html +1 -1
  346. package/docs/isobj.mjs.html +1 -1
  347. package/docs/isobj0.mjs.html +1 -1
  348. package/docs/isp0int.mjs.html +1 -1
  349. package/docs/isp0num.mjs.html +1 -1
  350. package/docs/ispint.mjs.html +1 -1
  351. package/docs/ispm.mjs.html +1 -1
  352. package/docs/ispnum.mjs.html +1 -1
  353. package/docs/isstr.mjs.html +1 -1
  354. package/docs/isstr0.mjs.html +1 -1
  355. package/docs/istime.mjs.html +1 -1
  356. package/docs/istimeTZ.mjs.html +1 -1
  357. package/docs/istimems.mjs.html +1 -1
  358. package/docs/istimemsTZ.mjs.html +1 -1
  359. package/docs/isu16arr.mjs.html +1 -1
  360. package/docs/isu8arr.mjs.html +1 -1
  361. package/docs/isundefined.mjs.html +1 -1
  362. package/docs/j2o.mjs.html +1 -1
  363. package/docs/judge.mjs.html +1 -1
  364. package/docs/keysmat2ltdt.mjs.html +1 -1
  365. package/docs/ltdt2vrtsable.mjs.html +1 -1
  366. package/docs/ltdtDiff.mjs.html +1 -1
  367. package/docs/ltdtDiffByKey.mjs.html +1 -1
  368. package/docs/ltdtkeys2mat.mjs.html +1 -1
  369. package/docs/ltdtkeysheads2mat.mjs.html +1 -1
  370. package/docs/ltdtmapping.mjs.html +1 -1
  371. package/docs/ltdtmerge.mjs.html +1 -1
  372. package/docs/ltdtpick.mjs.html +1 -1
  373. package/docs/ltdtpull.mjs.html +1 -1
  374. package/docs/mat2ltdt.mjs.html +1 -1
  375. package/docs/matConcat.mjs.html +1 -1
  376. package/docs/matDiff.mjs.html +1 -1
  377. package/docs/matat.mjs.html +1 -1
  378. package/docs/now2str.mjs.html +1 -1
  379. package/docs/now2strp.mjs.html +1 -1
  380. package/docs/nowDay2str.mjs.html +1 -1
  381. package/docs/nowms2str.mjs.html +1 -1
  382. package/docs/nowms2strp.mjs.html +1 -1
  383. package/docs/o2j.mjs.html +1 -1
  384. package/docs/obj2b64.mjs.html +1 -1
  385. package/docs/obj2pb64.mjs.html +1 -1
  386. package/docs/obj2str.mjs.html +1 -1
  387. package/docs/obj2stru8arr.mjs.html +1 -1
  388. package/docs/obj2u8arr.mjs.html +1 -1
  389. package/docs/objSortBy.mjs.html +1 -1
  390. package/docs/objSortByKeys.mjs.html +1 -1
  391. package/docs/oo.mjs.html +1 -1
  392. package/docs/openLink.mjs.html +1 -1
  393. package/docs/pb642obj.mjs.html +1 -1
  394. package/docs/pmChain.mjs.html +1 -1
  395. package/docs/pmConvertResolve.mjs.html +1 -1
  396. package/docs/pmDebounce.mjs.html +1 -1
  397. package/docs/pmHook.mjs.html +1 -1
  398. package/docs/pmHookReject.mjs.html +1 -1
  399. package/docs/pmIni.mjs.html +1 -1
  400. package/docs/pmInvResolve.mjs.html +1 -1
  401. package/docs/pmKeyMutex.mjs.html +1 -1
  402. package/docs/pmMap.mjs.html +1 -1
  403. package/docs/pmQueue.mjs.html +1 -1
  404. package/docs/pmSeries.mjs.html +1 -1
  405. package/docs/pmThrottle.mjs.html +1 -1
  406. package/docs/pmTimeout.mjs.html +1 -1
  407. package/docs/preciseNum.mjs.html +1 -1
  408. package/docs/pseudoRandom.mjs.html +1 -1
  409. package/docs/pseudoRandomIntRange.mjs.html +1 -1
  410. package/docs/pseudoRandomIntsNdpRange.mjs.html +1 -1
  411. package/docs/pseudoRandomIntsRange.mjs.html +1 -1
  412. package/docs/pseudoRandomRange.mjs.html +1 -1
  413. package/docs/pseudoRandomsRange.mjs.html +1 -1
  414. package/docs/queue.mjs.html +1 -1
  415. package/docs/random.mjs.html +1 -1
  416. package/docs/randomIntRange.mjs.html +1 -1
  417. package/docs/randomIntsNdpRange.mjs.html +1 -1
  418. package/docs/randomIntsRange.mjs.html +1 -1
  419. package/docs/randomRange.mjs.html +1 -1
  420. package/docs/randomsRange.mjs.html +1 -1
  421. package/docs/rang.mjs.html +1 -1
  422. package/docs/rep.mjs.html +1 -1
  423. package/docs/repObj.mjs.html +1 -1
  424. package/docs/replace.mjs.html +1 -1
  425. package/docs/replaceObj.mjs.html +1 -1
  426. package/docs/replacePlus.mjs.html +1 -1
  427. package/docs/round.mjs.html +1 -1
  428. package/docs/secd.mjs.html +1 -1
  429. package/docs/sep.mjs.html +1 -1
  430. package/docs/sepInt.mjs.html +1 -1
  431. package/docs/setIntervalHp.mjs.html +1 -1
  432. package/docs/setTimeoutHp.mjs.html +1 -1
  433. package/docs/sind.mjs.html +1 -1
  434. package/docs/split.mjs.html +1 -1
  435. package/docs/str2aes.mjs.html +1 -1
  436. package/docs/str2b64.mjs.html +1 -1
  437. package/docs/str2hint.mjs.html +1 -1
  438. package/docs/str2md5.mjs.html +1 -1
  439. package/docs/str2obj.mjs.html +1 -1
  440. package/docs/str2sha.mjs.html +1 -1
  441. package/docs/str2sha512.mjs.html +1 -1
  442. package/docs/str2u8arr.mjs.html +1 -1
  443. package/docs/strCompare.mjs.html +1 -1
  444. package/docs/strCompareForVersion.mjs.html +1 -1
  445. package/docs/strDiff.mjs.html +1 -1
  446. package/docs/strDiffToHtml.mjs.html +1 -1
  447. package/docs/strFindFuzz.mjs.html +1 -1
  448. package/docs/strFindSimilar.mjs.html +1 -1
  449. package/docs/strTruncate.mjs.html +1 -1
  450. package/docs/strdelleft.mjs.html +1 -1
  451. package/docs/strdelright.mjs.html +1 -1
  452. package/docs/strleft.mjs.html +1 -1
  453. package/docs/strmid.mjs.html +1 -1
  454. package/docs/strright.mjs.html +1 -1
  455. package/docs/stru8arr2obj.mjs.html +1 -1
  456. package/docs/tand.mjs.html +1 -1
  457. package/docs/time2day.mjs.html +1 -1
  458. package/docs/time2hour.mjs.html +1 -1
  459. package/docs/time2min.mjs.html +1 -1
  460. package/docs/timeTZ2day.mjs.html +1 -1
  461. package/docs/timeTZ2expire.mjs.html +1 -1
  462. package/docs/timeTZ2hour.mjs.html +1 -1
  463. package/docs/timeTZ2min.mjs.html +1 -1
  464. package/docs/timeTZ2past.mjs.html +1 -1
  465. package/docs/timems2day.mjs.html +1 -1
  466. package/docs/timems2hour.mjs.html +1 -1
  467. package/docs/timems2min.mjs.html +1 -1
  468. package/docs/timems2time.mjs.html +1 -1
  469. package/docs/timemsTZ2day.mjs.html +1 -1
  470. package/docs/timemsTZ2expire.mjs.html +1 -1
  471. package/docs/timemsTZ2hour.mjs.html +1 -1
  472. package/docs/timemsTZ2min.mjs.html +1 -1
  473. package/docs/timemsTZ2past.mjs.html +1 -1
  474. package/docs/timemsTZ2time.mjs.html +1 -1
  475. package/docs/treeObj.mjs.html +1 -1
  476. package/docs/treeToFilepath.mjs.html +1 -1
  477. package/docs/trim.mjs.html +1 -1
  478. package/docs/u16arr2b64.mjs.html +1 -1
  479. package/docs/u16arr2u8arr.mjs.html +1 -1
  480. package/docs/u8arr2ab.mjs.html +1 -1
  481. package/docs/u8arr2b64.mjs.html +1 -1
  482. package/docs/u8arr2blob.mjs.html +1 -1
  483. package/docs/u8arr2bs.mjs.html +1 -1
  484. package/docs/u8arr2obj.mjs.html +1 -1
  485. package/docs/u8arr2str.mjs.html +1 -1
  486. package/docs/u8arr2u16arr.mjs.html +1 -1
  487. package/docs/urlParse.mjs.html +1 -1
  488. package/docs/verifyValue.mjs.html +1 -1
  489. package/docs/waitFun.mjs.html +1 -1
  490. package/docs/wsemi.html +24 -23
  491. package/package.json +2 -2
  492. package/script.txt +1 -1
  493. package/src/_execSpawnError.mjs +41 -0
  494. package/src/alive.mjs +105 -4
  495. package/src/cache.mjs +2 -2
  496. package/src/cacheSt.mjs +1 -1
  497. package/src/evEmit.mjs +1 -1
  498. package/src/execCli.mjs +66 -32
  499. package/src/execCliCore.mjs +3 -0
  500. package/src/execCliJsonRpc.mjs +2 -2
  501. package/src/execCliSession.mjs +23 -11
  502. package/src/execProcess.mjs +57 -34
  503. package/src/execProcessKillPid.mjs +4 -2
  504. package/test/_execSpawnError.test.mjs +81 -0
  505. package/test/alive.test.mjs +201 -0
  506. package/test/cache.test.mjs +26 -0
  507. package/test/cacheSt.test.mjs +40 -0
  508. package/test/execCli.test.mjs +95 -0
  509. package/test/execCliJsonRpc.test.mjs +27 -0
  510. package/test/execCliSession.test.mjs +82 -0
  511. package/test/execProcess.test.mjs +135 -3
  512. package/test/execProcessKillPid.test.mjs +34 -0
  513. package/test/tools/spawnEmfileRunner.mjs +55 -0
  514. package/toolfp/dist/wsemip.umd.js +1 -1
  515. package/toolparfor/dist/wpf.umd.js +1 -1
  516. package/toolparfor/dist/wpf_pmSeries.umd.js +1 -1
@@ -3,15 +3,17 @@ import codec from './_execProcessCodec.mjs'
3
3
  import cp from 'child_process'
4
4
  import get from 'lodash-es/get.js'
5
5
  import genPm from './genPm.mjs'
6
- import isearr from './isearr.mjs'
6
+ import isarr from './isarr.mjs'
7
7
  import isbol from './isbol.mjs'
8
8
  import isfun from './isfun.mjs'
9
+ import isstr from './isstr.mjs'
9
10
  import isestr from './isestr.mjs'
10
11
  import isnum from './isnum.mjs'
11
12
  import strleft from './strleft.mjs'
12
13
  import strright from './strright.mjs'
13
14
  import arrHas from './arrHas.mjs'
14
15
  import execProcessKillPid from './execProcessKillPid.mjs'
16
+ import execSpawnError from './_execSpawnError.mjs'
15
17
 
16
18
 
17
19
  /**
@@ -20,15 +22,15 @@ import execProcessKillPid from './execProcessKillPid.mjs'
20
22
  * Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/execProcess.test.mjs Github}
21
23
  * @memberOf wsemi
22
24
  * @param {String} prog 輸入執行檔或程式語言位置字串,若為註冊系統的全域指令,例如可直接給'Python',腳本需自行接收呼叫引數,並將回傳資料轉json字串後print/log到dos視窗,即可由nodejs接收
23
- * @param {String|Array} args 輸入腳本檔案位置字串或參數
25
+ * @param {String|Array} args 輸入參數陣列或字串,例如腳本檔案位置字串,空陣列或空字串代表無參數;非陣列亦非字串時reject錯誤訊息(不拋錯)
24
26
  * @param {Object} [opt={}] 輸入設定物件
25
- * @param {String} [opt.mode='spawn'] 輸入執行模式字串,可選'spawn'、'exec'、'execFile',預設'spawn'。'spawn'不經shell直接執行,輸出以串流處理,適合大量輸出或長時間執行,prog與args不需也不可加引號;'exec'經shell執行,prog與args以空白串接成指令字串,適合須用到shell語法之情形,陣列型args之元素含空白且未含雙引號者會自動以雙引號包住,prog含空白亦同,已含雙引號者視為呼叫端自行處理而原樣串接,字串型args視為呼叫端已自組之指令列,原樣串接不加引號;'execFile'不經shell直接執行可執行檔,args須為陣列,給字串會被當成單一參數。三種模式之stdout與stderr皆以Buffer接收後走同一條解碼路徑
26
- * @param {Function} [opt.cbStdout=null] 輸入回調stdout函數,預設null。收到的是經串流解碼之字串,多位元組字元跨chunk時會等到完整才給,故不會收到空字串;codeCmd為'auto'時回調為盡力判定,該串流首次遇到非utf-8位元組後才改用系統字碼頁,之前已回調之字串不追溯,最終結果以resolve或reject之字串為準
27
+ * @param {String} [opt.mode='spawn'] 輸入執行模式字串,可選'spawn'、'exec'、'execFile',預設'spawn'。'spawn'不經shell直接執行,輸出以串流處理,適合大量輸出或長時間執行,prog與args不需也不可加引號;'exec'經shell執行,prog與args以空白串接成指令字串,適合須用到shell語法之情形,陣列型args之元素含空白且未含雙引號者會自動以雙引號包住,prog含空白亦同,已含雙引號者視為呼叫端自行處理而原樣串接,字串型args視為呼叫端已自組之指令列,原樣串接不加引號;'execFile'不經shell直接執行可執行檔,args須為陣列,給字串會被當成單一參數。三種模式之stdout與stderr皆以Buffer接收後走同一條解碼路徑;惟'exec'與'execFile'之stdout或stderr超過1MB(node之maxBuffer預設值)時子程序會被node終止,reject為`code[null]:\n訊息`,大量輸出請用'spawn'
28
+ * @param {Function} [opt.cbStdout=null] 輸入回調stdout函數,預設null。收到的是經串流解碼之字串,多位元組字元跨chunk時會等到完整才給,故不會收到空字串;codeCmd為'auto'時回調為盡力判定,該串流首次遇到非utf-8位元組後才改用系統字碼頁,之前已回調之字串不追溯,最終結果以resolve或reject之字串為準。回調內拋出之錯誤不會被攔截,將成為未捕捉例外,請於回調內自行處理
27
29
  * @param {Function} [opt.cbStderr=null] 輸入回調stderr函數,預設null,行為同cbStdout
28
30
  * @param {String} [opt.codeCmd='utf8'] 輸入解碼stdout與stderr之編碼字串,預設'utf8'。可給TextDecoder支援之標籤,例如'utf8'、'big5'、'gbk'、'gb18030'、'shift_jis'、'euc-kr'、'euc-jp'、'latin1'、'utf-16le',亦可給Windows字碼頁編號寫法如'cp950'、'950'、'cp936'、'cp932'、'cp949'、'cp437'、'cp1252';給'system'表示用當前作業系統字碼頁,win32以chcp查詢一次後快取,其他平台為utf-8;給'auto'表示先以utf-8嚴格解碼,遇非utf-8位元組之串流改用系統字碼頁,適合不確定子程序輸出編碼之情形,例如Windows原生指令與以ANSI字碼頁輸出之打包程式。非有效字串視為未設定而用預設值,有效字串但不支援之編碼則於執行前reject並帶該標籤。輸出開頭之utf-8 BOM會被移除
29
31
  * @param {Boolean} [opt.useChcp=false] 輸入是否於指令前置chcp 65001,僅'exec'模式生效,預設false。可使主控台工具改以utf-8輸出,副作用是其訊息語言可能變為英文;使用時codeCmd請維持預設'utf8'或給'auto',不要搭配'system'
30
32
  * @param {Number} [opt.timeout=null] 輸入逾時毫秒數,預設null表示不限制;逾時觸發時會調用execProcessKillPid強制關閉子進程及其子孫程序,並reject回傳逾時訊息
31
- * @returns {Promise} 回傳Promise,resolve回傳stdout與stderr依到達順序合併之字串,不另加換行,子程序自己的換行原樣保留;reject回傳錯誤訊息,離開碼非0時為`code[N]:\n訊息`,逾時為`timeout[Nms]:\n訊息`
33
+ * @returns {Promise} 回傳Promise,resolve回傳stdout與stderr依到達順序合併之字串,不另加換行,子程序自己的換行原樣保留;reject回傳錯誤訊息字串:離開碼非0時為`code[N]:\n訊息`,訊息為子程序之輸出,子程序因訊號結束時N為null;逾時為`timeout[Nms]:\n訊息`;無法啟動子程序時(找不到執行檔、權限不足、非有效執行檔、參數過長、參數含空字元、系統資源用盡等)為`spawn[錯誤碼]:\n訊息`,訊息為node之錯誤說明(可含執行檔路徑),不含args之內容;args型別不符、codeCmd不支援或spawn模式prog含引號時為說明字串
32
34
  * @example
33
35
  * //need test in nodejs
34
36
  *
@@ -45,6 +47,7 @@ import execProcessKillPid from './execProcessKillPid.mjs'
45
47
  *
46
48
  * if (true) {
47
49
  * //execFile與spawn之args須為陣列, 每個元素為一個參數; 給字串會被當成單一參數而失敗
50
+ * //密碼置於命令列參數時同機其他使用者可由程序列表看到; 失敗訊息不含args, 但子程序自身之輸出可能回顯
48
51
  * let prog = `C:\\Program Files\\7-Zip\\7z.exe`
49
52
  * let pw = 'AbcD1234'
50
53
  * let args = ['a', 'abc.7z', 'abc.txt', `-p${pw}`]
@@ -60,15 +63,6 @@ import execProcessKillPid from './execProcessKillPid.mjs'
60
63
  */
61
64
  function execProcess(prog, args, opt = {}) {
62
65
 
63
- //check
64
- if (!isearr(args) && !isestr(args)) {
65
- throw new Error(`args is not an effective array or string`)
66
- }
67
- let bArgsStr = isestr(args) //字串型args於exec模式視為呼叫端已自組之指令列
68
- if (isestr(args)) {
69
- args = [args]
70
- }
71
-
72
66
  //mode
73
67
  // spawn: 非同步執行命令,適合處理大量資料或長時間執行的程式,輸出以串流方式處理。spawnSync 為 spawn 的同步版本。
74
68
  // exec: 在 shell 中非同步執行命令,輸出被緩衝,適合輸出量較小的情況。execSync 為 exec 的同步版本。
@@ -107,6 +101,19 @@ function execProcess(prog, args, opt = {}) {
107
101
  //pm
108
102
  let pm = genPm()
109
103
 
104
+ //check args, 須為陣列(可為空陣列)或字串(可為空字串), 空陣列與空字串代表無參數; 其餘型別以reject回報, 不同步拋錯, 訊息不帶args之值
105
+ if (!isarr(args) && !isstr(args)) {
106
+ pm.reject(`args is not an array or string`)
107
+ return pm
108
+ }
109
+ let bArgsStr = isestr(args) //非空字串型args於exec模式視為呼叫端已自組之指令列
110
+ if (isestr(args)) {
111
+ args = [args]
112
+ }
113
+ else if (isstr(args)) {
114
+ args = [] //空字串代表無參數
115
+ }
116
+
110
117
  //check
111
118
  if (!arrHas(mode, ['spawn', 'exec', 'execFile'])) {
112
119
  pm.reject(`invalid mode[${mode}]`)
@@ -121,16 +128,21 @@ function execProcess(prog, args, opt = {}) {
121
128
  //start, 建立子進程並接線, labelSystem為系統字碼頁標籤, 僅codeCmd為'auto'或'system'時需要
122
129
  let start = (labelSystem) => {
123
130
 
131
+ //spawn不經shell, prog含引號會被當成檔名之一部分, 於啟動前reject
132
+ if (mode === 'spawn') {
133
+ let cr = strleft(prog, 1)
134
+ let cl = strright(prog, 1)
135
+ if (cr === `"` || cl === `"` || cr === `'` || cl === `'`) {
136
+ pm.reject(`prog[${prog}] of spawn does not need to add quotes`)
137
+ return
138
+ }
139
+ }
140
+
124
141
  //r
125
142
  let r = null
126
143
  try {
127
144
  if (mode === 'spawn') {
128
145
  // console.log('mode',mode)
129
- let cr = strleft(prog, 1)
130
- let cl = strright(prog, 1)
131
- if (cr === `"` || cl === `"` || cr === `'` || cl === `'`) {
132
- throw new Error('prog of spawn doens not need to add quotes')
133
- }
134
146
  r = cp.spawn(prog, args, {
135
147
  windowsHide: true, //執行的主程序若沒有主控台調用執行程序就不會有視窗, 但若通過pm2執行會有, 須設定windowsHide=true
136
148
  shell: false,
@@ -167,10 +179,26 @@ function execProcess(prog, args, opt = {}) {
167
179
  }
168
180
  }
169
181
  catch (err) {
170
- pm.reject(err)
182
+ //同步拋錯(EPERM、UNKNOWN、ENAMETOOLONG、參數檢查錯誤等), 轉為不含參數值之字串
183
+ let e = execSpawnError(err)
184
+ pm.reject(`spawn[${e.code}]:\n${e.message}`)
171
185
  return
172
186
  }
173
187
 
188
+ //timer, bTimeout, 逾時計時器於下方設定, 先宣告供error與close使用
189
+ let timer = null
190
+ let bTimeout = false
191
+
192
+ //error, 須於存取stdout與stderr前監聽: node對EMFILE、ENFILE不建立stdio即於nextTick發出'error', 先存取會拋TypeError且'error'無人監聽而拉倒程序
193
+ // 可能為'找不到可執行檔','權限不足','系統資源用盡'等, node所附之spawnargs含完整參數(exec模式為整條指令列), 故轉為不含參數值之字串
194
+ r.on('error', (err) => {
195
+ if (timer !== null) {
196
+ clearTimeout(timer)
197
+ }
198
+ let e = execSpawnError(err)
199
+ pm.reject(`spawn[${e.code}]:\n${e.message}`)
200
+ })
201
+
174
202
  //decOut, decErr, stdout與stderr各持一個串流解碼器, 多位元組字元跨chunk時由解碼器暫存, 不會被切成U+FFFD
175
203
  let label = cc.label
176
204
  if (cc.mode === 'system') {
@@ -201,11 +229,15 @@ function execProcess(prog, args, opt = {}) {
201
229
  }
202
230
  }
203
231
 
204
- //stdout data
205
- r.stdout.on('data', onData('out', decOut, cbStdout))
232
+ //stdout data, EMFILE、ENFILE時node未建立stdio(undefined), 由上方error回報
233
+ if (r.stdout) {
234
+ r.stdout.on('data', onData('out', decOut, cbStdout))
235
+ }
206
236
 
207
237
  //stderr data, 太多程式把warning或log輸出到stderr, 已無法視為有err發生
208
- r.stderr.on('data', onData('err', decErr, cbStderr))
238
+ if (r.stderr) {
239
+ r.stderr.on('data', onData('err', decErr, cbStderr))
240
+ }
209
241
 
210
242
  //buildMsg, 於close時收尾: 各解碼器flush, 'auto'且已改判之串流以全新解碼器重播原始chunk, 最後依到達順序合併, 不另加換行(chunk切點由作業系統決定, 附加換行會落在子程序輸出的任意位置)
211
243
  let buildMsg = () => {
@@ -257,8 +289,6 @@ function execProcess(prog, args, opt = {}) {
257
289
  // })
258
290
 
259
291
  //timer, 若有設定timeout, 逾時觸發時調用execProcessKillPid殺整棵程序樹
260
- let timer = null
261
- let bTimeout = false
262
292
  if (timeout !== null) {
263
293
  timer = setTimeout(() => {
264
294
  bTimeout = true
@@ -288,14 +318,6 @@ function execProcess(prog, args, opt = {}) {
288
318
  }
289
319
  })
290
320
 
291
- //error, 監聽(例如執行spawn本身)錯誤訊息, 可能為'找不到可執行檔','權限不足','系統資源用盡'等
292
- r.on('error', (err) => {
293
- if (timer !== null) {
294
- clearTimeout(timer)
295
- }
296
- pm.reject(err)
297
- })
298
-
299
321
  }
300
322
 
301
323
  //系統字碼頁僅'auto'與'system'需要, 首次會等chcp查詢完才啟動子進程, 之後為快取; 固定標籤同步啟動, 與既有時序相同
@@ -306,7 +328,8 @@ function execProcess(prog, args, opt = {}) {
306
328
  codec.getSystemCodePage()
307
329
  .then(start)
308
330
  .catch((err) => {
309
- pm.reject(err)
331
+ let e = execSpawnError(err)
332
+ pm.reject(`spawn[${e.code}]:\n${e.message}`)
310
333
  })
311
334
  }
312
335
 
@@ -1,5 +1,6 @@
1
1
  import treeKill from 'tree-kill'
2
2
  import genPm from './genPm.mjs'
3
+ import getErrorMessage from './getErrorMessage.mjs'
3
4
 
4
5
 
5
6
  /**
@@ -8,7 +9,7 @@ import genPm from './genPm.mjs'
8
9
  * Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/execProcessKillPid.test.mjs Github}
9
10
  * @memberOf wsemi
10
11
  * @param {Number|String} pid 輸入程序pid
11
- * @returns {Promise} 回傳Promise,resolve回傳成功訊息,reject回傳錯誤訊息
12
+ * @returns {Promise} 回傳Promise,resolve回傳成功訊息`pid[N] killed`,reject回傳錯誤訊息字串`pid[N] kill failed: 訊息`;Windows下訊息含taskkill之輸出,其為系統字碼頁而可能無法正確顯示
12
13
  * @example
13
14
  * //need test in nodejs
14
15
  *
@@ -40,9 +41,10 @@ function execProcessKillPid(pid) {
40
41
  let pm = genPm()
41
42
 
42
43
  //treeKill, Windows內部呼叫「taskkill /pid PID /T /F」, Linux/macOS則以ps/pgrep遞迴尋找子pid後逐一發signal
44
+ //失敗時tree-kill給Error物件(pid非數字、taskkill失敗等), 轉為錯誤訊息字串, 與resolve之訊息格式對稱
43
45
  treeKill(Number(pid), 'SIGKILL', (err) => {
44
46
  if (err) {
45
- pm.reject(err)
47
+ pm.reject(`pid[${pid}] kill failed: ${getErrorMessage(err)}`)
46
48
  }
47
49
  else {
48
50
  pm.resolve(`pid[${pid}] killed`)
@@ -0,0 +1,81 @@
1
+ import assert from 'assert'
2
+ import cp from 'child_process'
3
+ import execSpawnError from '../src/_execSpawnError.mjs'
4
+
5
+
6
+ describe(`_execSpawnError`, function() {
7
+
8
+ let SA = 'SECRET_ARG_7d1f' //機密標記
9
+
10
+ //mkErr, 依node之錯誤形狀造Error物件, 不實際spawn
11
+ let mkErr = (props) => {
12
+ return Object.assign(new Error(props.message), props)
13
+ }
14
+
15
+ it(`should keep the message and code of a system error that has errno`, function() {
16
+ //P01a: 有errno之系統錯誤, message為「syscall 錯誤碼」不含參數, 原樣使用; 不讀spawnargs
17
+ let err = mkErr({ message: 'spawn C:/x.exe ENOENT', code: 'ENOENT', errno: -4058, syscall: 'spawn C:/x.exe', path: 'C:/x.exe', spawnargs: ['a', SA] })
18
+ assert.strict.deepStrictEqual(execSpawnError(err), { code: 'ENOENT', message: 'spawn C:/x.exe ENOENT' })
19
+ })
20
+
21
+ it(`should strip the Received value of node argument validation errors and keep the argument name`, function() {
22
+ //P01b: 無errno之參數檢查錯誤, 去除「. Received 值」起之尾段
23
+ let e1 = mkErr({ message: `The argument 'args[2]' must be a string without null bytes. Received '${SA}\\x00x'`, code: 'ERR_INVALID_ARG_VALUE' })
24
+ let e2 = mkErr({ message: `The "file" argument must be of type string. Received undefined`, code: 'ERR_INVALID_ARG_TYPE' })
25
+ let e3 = mkErr({ message: `The property 'options.env['K']' must be a string without null bytes. Received '${SA}\\x00'\nline2`, code: 'ERR_INVALID_ARG_VALUE' })
26
+ let r = [e1, e2, e3].map(execSpawnError)
27
+ assert.strict.deepStrictEqual(r, [
28
+ { code: 'ERR_INVALID_ARG_VALUE', message: `The argument 'args[2]' must be a string without null bytes` },
29
+ { code: 'ERR_INVALID_ARG_TYPE', message: `The "file" argument must be of type string` },
30
+ { code: 'ERR_INVALID_ARG_VALUE', message: `The property 'options.env['K']' must be a string without null bytes` },
31
+ ])
32
+ })
33
+
34
+ it(`should not contain the argument value for the real error thrown by node spawn with a null byte`, function() {
35
+ //P01b: 以node實際拋出之錯誤驗證訊息格式, node若改變格式致值外露即失敗
36
+ let err = null
37
+ try {
38
+ cp.spawn(process.execPath, ['-e', '1', SA + '\u0000x'])
39
+ }
40
+ catch (e) {
41
+ err = e
42
+ }
43
+ assert.strict.deepStrictEqual(err !== null && String(err.message).includes(SA), true) //前提: node原訊息含值
44
+ let r = execSpawnError(err)
45
+ assert.strict.deepStrictEqual(r.code, 'ERR_INVALID_ARG_VALUE')
46
+ assert.strict.deepStrictEqual(r.message.includes(SA), false)
47
+ assert.strict.deepStrictEqual(r.message.includes('Received'), false)
48
+ assert.strict.deepStrictEqual(r.message.includes(`'args[2]'`), true)
49
+ })
50
+
51
+ it(`should fall back to UNKNOWN when code is missing and to code when message is empty`, function() {
52
+ //P01c、P01e
53
+ let r1 = execSpawnError(new Error('spawn x'))
54
+ let r2 = execSpawnError(mkErr({ message: '', code: 'EPERM', errno: -4048 }))
55
+ assert.strict.deepStrictEqual([r1, r2], [{ code: 'UNKNOWN', message: 'spawn x' }, { code: 'EPERM', message: 'EPERM' }])
56
+ })
57
+
58
+ it(`should not throw for non-object input or throwing getters`, function() {
59
+ //P01d: 任何輸入皆不拋錯
60
+ let px = new Proxy({}, {
61
+ get() {
62
+ throw new Error('boom')
63
+ },
64
+ })
65
+ let rs = []
66
+ assert.doesNotThrow(() => {
67
+ for (let v of [undefined, null, 'str', 123, {}, px]) {
68
+ rs.push(execSpawnError(v))
69
+ }
70
+ })
71
+ assert.strict.deepStrictEqual(rs.map((r) => [typeof r.code, typeof r.message, r.code]), [
72
+ ['string', 'string', 'UNKNOWN'],
73
+ ['string', 'string', 'UNKNOWN'],
74
+ ['string', 'string', 'UNKNOWN'],
75
+ ['string', 'string', 'UNKNOWN'],
76
+ ['string', 'string', 'UNKNOWN'],
77
+ ['string', 'string', 'UNKNOWN'],
78
+ ])
79
+ })
80
+
81
+ })
@@ -1,4 +1,5 @@
1
1
  import assert from 'assert'
2
+ import { spawnSync } from 'child_process'
2
3
  import alive from '../src/alive.mjs'
3
4
 
4
5
 
@@ -65,4 +66,204 @@ describe(`alive`, function() {
65
66
  assert.strict.deepStrictEqual(JSON.stringify(ms), r1)
66
67
  })
67
68
 
69
+ function test2() {
70
+ return new Promise((resolve, reject) => {
71
+ let ms = []
72
+
73
+ let oAL = alive({ timeAlive: 1500 })
74
+
75
+ oAL.on('message', function({ eventName, key }) {
76
+ ms.push(eventName + '|' + key)
77
+ })
78
+
79
+ oAL.trigger('a', { data: 123 })
80
+
81
+ setTimeout(() => {
82
+ oAL.trigger('b', { data: '34.56' })
83
+ let r = oAL.clear() //b剛trigger尚未發出enter, 故只回傳a, 且b之enter不再發出
84
+ ms.push('clear|' + r.map((v) => v.key).join(','))
85
+ }, 500)
86
+
87
+ setTimeout(() => {
88
+ resolve(ms)
89
+ }, 2500)
90
+
91
+ })
92
+ }
93
+ let r2 = '["enter|a","clear|a"]'
94
+ it(`should return '${r2}' when run test2'`, async function() {
95
+ let ms = await test2()
96
+ assert.strict.deepStrictEqual(JSON.stringify(ms), r2)
97
+ })
98
+
99
+ describe(`key`, function() {
100
+
101
+ let sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
102
+
103
+ //trigger之key為任意非空字串, 每個key皆須於首次trigger時enter、逾時leave、存活期間列於get
104
+ //__proto__與Object原型之屬性名(constructor、toString等)亦同, 不得被誤判為已存在或改掉佇列之原型
105
+ let keys = ['__proto__', 'data', 'time', 'constructor', 'toString', 'hasOwnProperty', 'valueOf', 'isPrototypeOf', '__defineGetter__']
106
+
107
+ it(`should treat __proto__ and names on Object.prototype as ordinary keys`, async function() {
108
+ let ms = []
109
+ let o = alive({ timeAlive: 100, timeDetect: 20 })
110
+ o.on('message', (m) => ms.push(m.eventName + '|' + m.key))
111
+ for (let k of keys) {
112
+ o.trigger(k, { k })
113
+ }
114
+ await sleep(30)
115
+ assert.strict.deepStrictEqual(o.get(), keys.map((k) => ({ key: k, data: { k } })))
116
+ await sleep(300)
117
+ assert.strict.deepStrictEqual(ms, [...keys.map((k) => 'enter|' + k), ...keys.map((k) => 'leave|' + k)])
118
+ assert.strict.deepStrictEqual(o.get(), [])
119
+ })
120
+
121
+ it(`should return __proto__ and names on Object.prototype from clear`, async function() {
122
+ let o = alive({ timeAlive: 300 })
123
+ o.trigger('__proto__', 1)
124
+ o.trigger('constructor', 2)
125
+ await sleep(30)
126
+ assert.strict.deepStrictEqual(o.clear(), [{ key: '__proto__', data: 1 }, { key: 'constructor', data: 2 }])
127
+ })
128
+
129
+ })
130
+
131
+ describe(`clear`, function() {
132
+
133
+ let sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
134
+
135
+ let create = (opt) => {
136
+ let ms = []
137
+ let errs = []
138
+ let o = alive(opt)
139
+ o.on('error', (e) => errs.push(e))
140
+ o.on('message', (m) => ms.push(m.eventName + '|' + m.key))
141
+ return { o, ms, errs }
142
+ }
143
+
144
+ it(`should return entered units, emit nothing afterwards and get [] (two units entered then clear)`, async function() {
145
+ let { o, ms } = create({ timeAlive: 300 })
146
+ o.trigger('a', { x: 1 })
147
+ o.trigger('b', { x: 2 })
148
+ await sleep(30)
149
+ let r = o.clear()
150
+ assert.strict.deepStrictEqual(r, [{ key: 'a', data: { x: 1 } }, { key: 'b', data: { x: 2 } }])
151
+ await sleep(500) //逾timeAlive仍不得發leave
152
+ assert.strict.deepStrictEqual(ms, ['enter|a', 'enter|b'])
153
+ assert.strict.deepStrictEqual(o.get(), [])
154
+ })
155
+
156
+ it(`should return [] and cancel the enter when cleared right after trigger`, async function() {
157
+ let { o, ms } = create({ timeAlive: 300 })
158
+ o.trigger('a', 1)
159
+ let r = o.clear()
160
+ await sleep(400)
161
+ assert.strict.deepStrictEqual(r, [])
162
+ assert.strict.deepStrictEqual(ms, [])
163
+ })
164
+
165
+ it(`should return only units whose enter was emitted`, async function() {
166
+ let { o, ms } = create({ timeAlive: 300 })
167
+ o.trigger('a', 1)
168
+ await sleep(30)
169
+ o.trigger('b', 2)
170
+ let r = o.clear()
171
+ await sleep(400)
172
+ assert.strict.deepStrictEqual(r, [{ key: 'a', data: 1 }])
173
+ assert.strict.deepStrictEqual(ms, ['enter|a'])
174
+ })
175
+
176
+ it(`should not return a unit that left and was triggered again but not yet re-entered`, async function() {
177
+ let { o, ms } = create({ timeAlive: 100, timeDetect: 20 })
178
+ o.trigger('a', 1)
179
+ await sleep(300) //a已enter且已leave
180
+ o.trigger('a', 2)
181
+ let r = o.clear()
182
+ await sleep(100)
183
+ assert.strict.deepStrictEqual(r, [])
184
+ assert.strict.deepStrictEqual(ms, ['enter|a', 'leave|a'])
185
+ })
186
+
187
+ it(`should not throw and return [] when called repeatedly or before any trigger`, function() {
188
+ let o = alive()
189
+ assert.strict.deepStrictEqual(o.clear(), [])
190
+ assert.strict.deepStrictEqual(o.clear(), [])
191
+ })
192
+
193
+ it(`should ignore trigger after clear`, async function() {
194
+ let { o, ms } = create({ timeAlive: 300 })
195
+ o.trigger('a', 1)
196
+ await sleep(30)
197
+ o.clear()
198
+ o.trigger('b', 2)
199
+ o.trigger('a', 3)
200
+ await sleep(400)
201
+ assert.strict.deepStrictEqual(ms, ['enter|a'])
202
+ assert.strict.deepStrictEqual(o.get(), [])
203
+ assert.strict.deepStrictEqual(o.clear(), [])
204
+ })
205
+
206
+ it(`should return the unit being dispatched and stop pending enters when cleared in an enter listener`, async function() {
207
+ let { o, ms, errs } = create({ timeAlive: 300 })
208
+ let rc = null
209
+ o.on('message', (m) => {
210
+ if (m.key === 'a' && rc === null) {
211
+ rc = o.clear()
212
+ }
213
+ })
214
+ o.trigger('a', 1)
215
+ o.trigger('b', 2)
216
+ await sleep(400)
217
+ assert.strict.deepStrictEqual(rc, [{ key: 'a', data: 1 }])
218
+ assert.strict.deepStrictEqual(ms, ['enter|a'])
219
+ assert.strict.deepStrictEqual(errs, [])
220
+ })
221
+
222
+ it(`should stop the eviction round without throwing when cleared in a leave listener`, async function() {
223
+ //三單元同一輪逾時, 第一則leave中clear: 其餘二單元不再發leave且由clear回傳; 未防護時同輪下一單元會讀到已清空之佇列而拋錯
224
+ let { o, ms, errs } = create({ timeAlive: 100, timeDetect: 20 })
225
+ let rc = null
226
+ o.on('message', (m) => {
227
+ if (m.eventName === 'leave' && rc === null) {
228
+ rc = o.clear()
229
+ }
230
+ })
231
+ o.trigger('a', 1)
232
+ o.trigger('b', 2)
233
+ o.trigger('c', 3)
234
+ await sleep(400)
235
+ assert.strict.deepStrictEqual(ms, ['enter|a', 'enter|b', 'enter|c', 'leave|a'])
236
+ assert.strict.deepStrictEqual(rc, [{ key: 'b', data: 2 }, { key: 'c', data: 3 }])
237
+ assert.strict.deepStrictEqual(errs, [])
238
+ })
239
+
240
+ it(`should leave no active timer so the process exits at once (child process)`, function() {
241
+ //於呼叫clear之計時器回呼結束後(setImmediate)才查資源, 回呼內該計時器自身仍會列出
242
+ let url = new URL('../src/alive.mjs', import.meta.url).href
243
+ let code = `
244
+ import alive from '${url}'
245
+ let t0 = Date.now()
246
+ let o = alive()
247
+ o.trigger('a', 1)
248
+ o.trigger('b', 2)
249
+ setTimeout(() => {
250
+ let r = o.clear()
251
+ setImmediate(() => {
252
+ let res = process.getActiveResourcesInfo().filter((x) => x !== 'TTYWrap' && x !== 'Immediate')
253
+ process.on('exit', () => {
254
+ console.log(JSON.stringify({ r, res, ms: Date.now() - t0 }))
255
+ })
256
+ })
257
+ }, 100)
258
+ `
259
+ let p = spawnSync(process.execPath, ['--input-type=module', '-e', code], { encoding: 'utf8', timeout: 20000 })
260
+ assert.strict.deepStrictEqual(p.status, 0, p.stderr)
261
+ let o = JSON.parse(p.stdout.trim())
262
+ assert.strict.deepStrictEqual(o.r, [{ key: 'a', data: 1 }, { key: 'b', data: 2 }])
263
+ assert.strict.deepStrictEqual(o.res, [])
264
+ assert.strict.deepStrictEqual(o.ms < 2000, true, `exit after ${o.ms}ms`) //未clear時須逾timeAlive(預設10000)才結束
265
+ })
266
+
267
+ })
268
+
68
269
  })
@@ -706,4 +706,30 @@ describe(`cache`, function() {
706
706
  assert.strict.deepStrictEqual(r, { defIsolated: true, getFalseSame: true, setFalseSame: true, overrideCloned: true, invalidUseSet: true, waitTrueIsolated: true, waitFalseSame: true, proxySame: true })
707
707
  })
708
708
 
709
+ //key為任意字串, __proto__與Object原型之屬性名(constructor、toString等)亦為一般key: 未set視為無效key、不得寫到原型上之物件, set後可取回
710
+ it(`should treat __proto__ and names on Object.prototype as ordinary keys`, async function() {
711
+ let had = Object.prototype.hasOwnProperty.call(Object, 'value')
712
+ try {
713
+ let oc = cache()
714
+ for (let k of ['__proto__', 'constructor', 'toString', 'hasOwnProperty', 'valueOf']) {
715
+ assert.strict.deepStrictEqual(await oc.get(k), null, `get ${k} before set`)
716
+ }
717
+ oc.update('constructor', 5) //未set之key不得寫入, 一般物件時會寫到Object本身
718
+ oc.clear('constructor')
719
+ assert.strict.deepStrictEqual(Object.prototype.hasOwnProperty.call(Object, 'value'), had)
720
+ oc.set('constructor', { fun: async () => 1 })
721
+ oc.set('__proto__', { fun: async () => 2 })
722
+ assert.strict.deepStrictEqual(await oc.get('constructor'), 1)
723
+ assert.strict.deepStrictEqual(await oc.get('__proto__'), 2)
724
+ assert.strict.deepStrictEqual(await oc.get('needExec'), null) //set __proto__不得使未set之key被視為存在
725
+ oc.remove('constructor')
726
+ assert.strict.deepStrictEqual(await oc.get('constructor'), null)
727
+ }
728
+ finally {
729
+ if (!had) {
730
+ delete Object.value //修正前之版本會寫入Object.value, 測試後還原以免影響同檔其他測試
731
+ }
732
+ }
733
+ })
734
+
709
735
  })
@@ -256,4 +256,44 @@ describe(`cacheSt`, function() {
256
256
  assert.strict.deepStrictEqual(ms, ms9)
257
257
  })
258
258
 
259
+ //key為任意字串, __proto__與Object原型之屬性名(constructor、toString等)亦為一般key: 未set不存在、set後可取回、不影響其他key
260
+ it(`should treat __proto__ and names on Object.prototype as ordinary keys`, async function() {
261
+ let cs = cacheSt({ timeDetect: 1000 })
262
+ try {
263
+ let names = ['__proto__', 'constructor', 'toString', 'hasOwnProperty', 'valueOf']
264
+ for (let k of names) {
265
+ assert.strict.deepStrictEqual(await cs.check(k), false, `check ${k} before set`)
266
+ assert.strict.deepStrictEqual(await cs.get(k), null, `get ${k} before set`)
267
+ }
268
+ assert.strict.deepStrictEqual(cs.checkWithSet('toString'), true)
269
+ assert.strict.deepStrictEqual(await cs.check('toString'), true)
270
+ await cs.set('__proto__', 'v')
271
+ assert.strict.deepStrictEqual(await cs.get('__proto__'), 'v')
272
+ assert.strict.deepStrictEqual(await cs.check('value'), false) //set __proto__不得使未set之key被視為存在
273
+ assert.strict.deepStrictEqual(await cs.check('time'), false)
274
+ await cs.set('constructor', 1)
275
+ assert.strict.deepStrictEqual(await cs.get('constructor'), 1)
276
+ await cs.del('constructor')
277
+ assert.strict.deepStrictEqual(await cs.check('constructor'), false)
278
+ await cs.del('__proto__')
279
+ assert.strict.deepStrictEqual(await cs.check('__proto__'), false)
280
+ }
281
+ finally {
282
+ cs.clear()
283
+ }
284
+ })
285
+
286
+ it(`should expire __proto__ like other keys`, async function() {
287
+ let cs = cacheSt({ timeExpire: 100, timeDetect: 50 })
288
+ try {
289
+ await cs.set('__proto__', 1)
290
+ assert.strict.deepStrictEqual(await cs.check('__proto__'), true)
291
+ await delay(300)
292
+ assert.strict.deepStrictEqual(await cs.check('__proto__'), false)
293
+ }
294
+ finally {
295
+ cs.clear()
296
+ }
297
+ })
298
+
259
299
  })