wsemi 1.9.21 → 1.9.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/wsemi.umd.js +6 -6
- package/dist/wsemi.umd.js.map +1 -1
- package/docs/-_class.mjs.html +1 -1
- package/docs/-_const.mjs.html +1 -1
- package/docs/-_detector.mjs.html +1 -1
- package/docs/-_errToStr.mjs.html +1 -1
- package/docs/-_execThrownMsg.mjs.html +1 -1
- package/docs/-_isRealError.mjs.html +1 -1
- package/docs/-_optNum.mjs.html +1 -1
- package/docs/-_pmMarkHandled.mjs.html +1 -1
- package/docs/-_pmReadItems.mjs.html +1 -1
- package/docs/-_pmSettleByState.mjs.html +1 -1
- package/docs/-_realErrorToStr.mjs.html +1 -1
- package/docs/-_toResultError.mjs.html +1 -1
- package/docs/ab2blob.mjs.html +1 -1
- package/docs/ab2u8arr.mjs.html +1 -1
- package/docs/addExcelWorksheetFromData.mjs.html +1 -1
- package/docs/addMonth.mjs.html +1 -1
- package/docs/aes2str.mjs.html +1 -1
- package/docs/alive.mjs.html +1 -1
- package/docs/arr2dt.mjs.html +1 -1
- package/docs/arrAccum.mjs.html +1 -1
- package/docs/arrAdd.mjs.html +1 -1
- package/docs/arrAt.mjs.html +1 -1
- package/docs/arrDiff.mjs.html +1 -1
- package/docs/arrFilterByKeywords.mjs.html +1 -1
- package/docs/arrFilterByNum.mjs.html +1 -1
- package/docs/arrFilterByPnum.mjs.html +1 -1
- package/docs/arrFilterByPnumAndToLog.mjs.html +1 -1
- package/docs/arrFind.mjs.html +1 -1
- package/docs/arrGroupByMaxmin.mjs.html +1 -1
- package/docs/arrHas.mjs.html +1 -1
- package/docs/arrInsert.mjs.html +1 -1
- package/docs/arrLookupByMaxmin.mjs.html +1 -1
- package/docs/arrMax.mjs.html +1 -1
- package/docs/arrMin.mjs.html +1 -1
- package/docs/arrMulti.mjs.html +1 -1
- package/docs/arrNorm.mjs.html +1 -1
- package/docs/arrProduct.mjs.html +1 -1
- package/docs/arrPull.mjs.html +1 -1
- package/docs/arrPullAt.mjs.html +1 -1
- package/docs/arrReduce.mjs.html +1 -1
- package/docs/arrReverse.mjs.html +1 -1
- package/docs/arrSep.mjs.html +1 -1
- package/docs/arrSort.mjs.html +1 -1
- package/docs/asind.mjs.html +1 -1
- package/docs/atan2d.mjs.html +1 -1
- package/docs/atand.mjs.html +1 -1
- package/docs/attstr.mjs.html +1 -1
- package/docs/b642obj.mjs.html +1 -1
- package/docs/b642str.mjs.html +1 -1
- package/docs/b642u16arr.mjs.html +1 -1
- package/docs/b642u8arr.mjs.html +1 -1
- package/docs/binstr.mjs.html +1 -1
- package/docs/blob2ab.mjs.html +1 -1
- package/docs/blob2b64.mjs.html +1 -1
- package/docs/blob2str.mjs.html +1 -1
- package/docs/blob2u8arr.mjs.html +1 -1
- package/docs/blobs2b64s.mjs.html +1 -1
- package/docs/blobs2u8arrs.mjs.html +1 -1
- package/docs/bodyLog.mjs.html +1 -1
- package/docs/browserView.mjs.html +1 -1
- package/docs/browserViewFromBlob.mjs.html +1 -1
- package/docs/browserViewFromText.mjs.html +1 -1
- package/docs/browserViewFromU8arr.mjs.html +1 -1
- package/docs/bs2u8arr.mjs.html +1 -1
- package/docs/bufRead.mjs.html +1 -1
- package/docs/bufReadDbl.mjs.html +1 -1
- package/docs/bufWrite.mjs.html +1 -1
- package/docs/bufWriteDbl.mjs.html +1 -1
- package/docs/cache.mjs.html +1 -1
- package/docs/cacheBd.mjs.html +1 -1
- package/docs/cacheSt.mjs.html +1 -1
- package/docs/cbol.mjs.html +1 -1
- package/docs/cdbl.mjs.html +1 -1
- package/docs/ceil.mjs.html +1 -1
- package/docs/cfilesize.mjs.html +1 -1
- package/docs/cfinancial.mjs.html +1 -1
- package/docs/cint.mjs.html +1 -1
- package/docs/clearXSS.mjs.html +263 -25
- package/docs/clearXSSDyn.mjs.html +1 -1
- package/docs/color.mjs.html +1 -1
- package/docs/composeToTree.mjs.html +1 -1
- package/docs/convertToTree.mjs.html +1 -1
- package/docs/copyStrToClipboard.mjs.html +1 -1
- package/docs/cosd.mjs.html +1 -1
- package/docs/cotd.mjs.html +1 -1
- package/docs/createExcelWorkbook.mjs.html +1 -1
- package/docs/cscd.mjs.html +1 -1
- package/docs/cstr.mjs.html +1 -1
- package/docs/cvOrmFind.mjs.html +1 -1
- package/docs/day2cht.mjs.html +1 -1
- package/docs/debounce.mjs.html +1 -1
- package/docs/delay.mjs.html +1 -1
- package/docs/detectXSS.mjs.html +1 -1
- package/docs/detectXSSDyn.mjs.html +1 -1
- package/docs/dig.mjs.html +1 -1
- package/docs/digExp.mjs.html +1 -1
- package/docs/domAlert.mjs.html +1 -1
- package/docs/domAppend.mjs.html +1 -1
- package/docs/domCancelEvent.mjs.html +1 -1
- package/docs/domCompareText.mjs.html +1 -1
- package/docs/domConvertToPic.mjs.html +1 -1
- package/docs/domConvertToPicDyn.mjs.html +1 -1
- package/docs/domDetect.mjs.html +1 -1
- package/docs/domDrag.mjs.html +1 -1
- package/docs/domDragBarAndScroll.mjs.html +1 -1
- package/docs/domDragPointer.mjs.html +1 -1
- package/docs/domDragPreview.mjs.html +1 -1
- package/docs/domDropFiles.mjs.html +1 -1
- package/docs/domElementsFromPoint.mjs.html +1 -1
- package/docs/domFadeIn.mjs.html +1 -1
- package/docs/domFadeOut.mjs.html +1 -1
- package/docs/domFind.mjs.html +1 -1
- package/docs/domFinds.mjs.html +1 -1
- package/docs/domGetAttr.mjs.html +1 -1
- package/docs/domGetBoudRect.mjs.html +1 -1
- package/docs/domGetBoudRectRefSelf.mjs.html +1 -1
- package/docs/domGetFileAccept.mjs.html +1 -1
- package/docs/domGetFiles.mjs.html +1 -1
- package/docs/domGetParents.mjs.html +1 -1
- package/docs/domGetPointFromEvent.mjs.html +1 -1
- package/docs/domGetScrollableParent.mjs.html +1 -1
- package/docs/domGetWindowSize.mjs.html +1 -1
- package/docs/domIsClientXYIn.mjs.html +1 -1
- package/docs/domIsFocused.mjs.html +1 -1
- package/docs/domIsRendered.mjs.html +1 -1
- package/docs/domIsStable.mjs.html +1 -1
- package/docs/domIsVisible.mjs.html +1 -1
- package/docs/domPrepend.mjs.html +1 -1
- package/docs/domRemove.mjs.html +1 -1
- package/docs/domRenderMarkdownMind.mjs.html +1 -1
- package/docs/domRenderMarkdownMindDyn.mjs.html +1 -1
- package/docs/domRipple.mjs.html +1 -1
- package/docs/domScrollIntoView.mjs.html +1 -1
- package/docs/domScrollTo.mjs.html +1 -1
- package/docs/domSetAttr.mjs.html +1 -1
- package/docs/domShowImages.mjs.html +1 -1
- package/docs/domShowImagesDyn.mjs.html +1 -1
- package/docs/domShowInputAndGetFiles.mjs.html +1 -1
- package/docs/domShowInputAndGetFilesU8Arrs.mjs.html +1 -1
- package/docs/domShowInputDatatime.mjs.html +1 -1
- package/docs/domTooltip.mjs.html +1 -1
- package/docs/domTriggerEvent.mjs.html +1 -1
- package/docs/domVirtualCreate.mjs.html +1 -1
- package/docs/domVirtualCreateQueue.mjs.html +1 -1
- package/docs/downloadExcelFileFromData.mjs.html +1 -1
- package/docs/downloadExcelFileFromDataDyn.mjs.html +1 -1
- package/docs/downloadFileFromB64.mjs.html +1 -1
- package/docs/downloadFileFromBlob.mjs.html +1 -1
- package/docs/downloadFileFromText.mjs.html +1 -1
- package/docs/downloadFileFromU8Arr.mjs.html +1 -1
- package/docs/dtmapping.mjs.html +1 -1
- package/docs/dtpick.mjs.html +1 -1
- package/docs/estimateTicks.mjs.html +1 -1
- package/docs/evEmit.mjs.html +1 -1
- package/docs/evEmitDelay.mjs.html +1 -1
- package/docs/evem.mjs.html +1 -1
- package/docs/examples/ex-blob2b64.html +1 -1
- package/docs/examples/ex-clearXSS.html +1 -1
- package/docs/examples/ex-clearXSSDyn.html +1 -1
- package/docs/examples/ex-colorConverter.html +1 -1
- package/docs/examples/ex-detectXSS.html +1 -1
- package/docs/examples/ex-detectXSSDyn.html +1 -1
- package/docs/examples/ex-domCompareText.html +1 -1
- package/docs/examples/ex-domConvertToPic.html +1 -1
- package/docs/examples/ex-domDrag.html +1 -1
- package/docs/examples/ex-domDropFiles.html +1 -1
- package/docs/examples/ex-domIsVisible.html +1 -1
- package/docs/examples/ex-domRenderMarkdownMind.html +1 -1
- package/docs/examples/ex-domRenderMarkdownMindDyn.html +1 -1
- package/docs/examples/ex-domRipple.html +1 -1
- package/docs/examples/ex-domScrollIntoView.html +1 -1
- package/docs/examples/ex-domScrollTo.html +1 -1
- package/docs/examples/ex-domShowImages.html +1 -1
- package/docs/examples/ex-domShowImagesDyn.html +1 -1
- package/docs/examples/ex-domShowInputAndGetFiles.html +1 -1
- package/docs/examples/ex-domTooltip.html +1 -1
- package/docs/examples/ex-getFileHash.html +1 -1
- package/docs/examples/ex-getUserAgent.html +1 -1
- package/docs/examples/ex-getUserAgentDyn.html +1 -1
- package/docs/examples/ex-html2str.html +1 -1
- package/docs/examples/ex-obj2u8arr-u8arr2obj.html +1 -1
- package/docs/examples/ex-openLink.html +1 -1
- package/docs/examples/ex-str2aes-aes2str.html +1 -1
- package/docs/examples/ex-str2b64-b642str.html +1 -1
- package/docs/examples/ex-strFindFuzz.html +1 -1
- package/docs/examples/ex-timeTZ2expire-timeTZ2past.html +1 -1
- package/docs/examples/ex-xlsx.html +1 -1
- package/docs/execCli.mjs.html +1 -1
- package/docs/execCliCore.mjs.html +1 -1
- package/docs/execCliJsonRpc.mjs.html +1 -1
- package/docs/execCliSession.mjs.html +1 -1
- package/docs/execJsCode.mjs.html +1 -1
- package/docs/execProcess.mjs.html +1 -1
- package/docs/execProcessKillPid.mjs.html +1 -1
- package/docs/filepathToTree.mjs.html +1 -1
- package/docs/files2data.mjs.html +1 -1
- package/docs/flattenToConn.mjs.html +12 -8
- package/docs/flattenTree.mjs.html +9 -9
- package/docs/floor.mjs.html +1 -1
- package/docs/fsBuildReadStreamText.mjs.html +1 -1
- package/docs/fsBuildWriteStreamText.mjs.html +1 -1
- package/docs/fsCleanFolder.mjs.html +1 -1
- package/docs/fsCleanFolderCore.mjs.html +1 -1
- package/docs/fsCopyFile.mjs.html +1 -1
- package/docs/fsCopyFileCore.mjs.html +1 -1
- package/docs/fsCopyFolder.mjs.html +1 -1
- package/docs/fsCopyFolderCore.mjs.html +1 -1
- package/docs/fsCreateFile.mjs.html +1 -1
- package/docs/fsCreateFileCore.mjs.html +1 -1
- package/docs/fsCreateFolder.mjs.html +1 -1
- package/docs/fsCreateFolderCore.mjs.html +1 -1
- package/docs/fsDeleteFile.mjs.html +1 -1
- package/docs/fsDeleteFileCore.mjs.html +1 -1
- package/docs/fsDeleteFileSafe.mjs.html +1 -1
- package/docs/fsDeleteFileSafeCore.mjs.html +1 -1
- package/docs/fsDeleteFolder.mjs.html +1 -1
- package/docs/fsDeleteFolderCore.mjs.html +1 -1
- package/docs/fsDeleteFolderSafe.mjs.html +1 -1
- package/docs/fsDeleteFolderSafeCore.mjs.html +1 -1
- package/docs/fsDownloadFile.mjs.html +1 -1
- package/docs/fsDownloadFileCore.mjs.html +1 -1
- package/docs/fsEvem.mjs.html +1 -1
- package/docs/fsExists.mjs.html +1 -1
- package/docs/fsExistsCore.mjs.html +1 -1
- package/docs/fsGetFileBasicHash.mjs.html +1 -1
- package/docs/fsGetFileBasicHashCore.mjs.html +1 -1
- package/docs/fsGetFileHash.mjs.html +1 -1
- package/docs/fsGetFileHashCore.mjs.html +1 -1
- package/docs/fsGetFileXxHash.mjs.html +1 -1
- package/docs/fsGetFileXxHashCore.mjs.html +1 -1
- package/docs/fsGetFilesInFolder.mjs.html +1 -1
- package/docs/fsGetFilesInFolderCore.mjs.html +1 -1
- package/docs/fsGetFilesWithHashInFolder.mjs.html +1 -1
- package/docs/fsGetFilesWithHashInFolderCore.mjs.html +1 -1
- package/docs/fsGetFolderBasicHash.mjs.html +1 -1
- package/docs/fsGetFolderBasicHashCore.mjs.html +1 -1
- package/docs/fsGetFoldersInFolder.mjs.html +1 -1
- package/docs/fsGetFoldersInFolderCore.mjs.html +1 -1
- package/docs/fsIsFile.mjs.html +1 -1
- package/docs/fsIsFileCore.mjs.html +1 -1
- package/docs/fsIsFolder.mjs.html +1 -1
- package/docs/fsIsFolderCore.mjs.html +1 -1
- package/docs/fsMergeFiles.mjs.html +1 -1
- package/docs/fsMergeFilesCore.mjs.html +1 -1
- package/docs/fsReadJson.mjs.html +1 -1
- package/docs/fsReadText.mjs.html +1 -1
- package/docs/fsReadTextCore.mjs.html +1 -1
- package/docs/fsRenameFile.mjs.html +1 -1
- package/docs/fsRenameFileCore.mjs.html +1 -1
- package/docs/fsRenameFolder.mjs.html +1 -1
- package/docs/fsRenameFolderCore.mjs.html +1 -1
- package/docs/fsSrlog.mjs.html +1 -1
- package/docs/fsSyncFolder.mjs.html +1 -1
- package/docs/fsSyncFolderCore.mjs.html +1 -1
- package/docs/fsTask.mjs.html +14 -13
- package/docs/fsTaskCp.mjs.html +1 -1
- package/docs/fsTreeFolder.mjs.html +1 -1
- package/docs/fsTreeFolderCore.mjs.html +1 -1
- package/docs/fsTreeFolderWithHash.mjs.html +1 -1
- package/docs/fsTreeFolderWithHashCore.mjs.html +1 -1
- package/docs/fsWatchFile.mjs.html +1 -1
- package/docs/fsWatchFolder.mjs.html +1 -1
- package/docs/fsWriteJson.mjs.html +1 -1
- package/docs/fsWriteText.mjs.html +1 -1
- package/docs/fsWriteTextCore.mjs.html +1 -1
- package/docs/genGradientColor.mjs.html +1 -1
- package/docs/genID.mjs.html +1 -1
- package/docs/genIDSeq.mjs.html +1 -1
- package/docs/genPm.mjs.html +1 -1
- package/docs/getBufferSize.mjs.html +1 -1
- package/docs/getClearPathName.mjs.html +1 -1
- package/docs/getCsvStrFromData.mjs.html +1 -1
- package/docs/getDataFromExcelFileU8Arr.mjs.html +1 -1
- package/docs/getDataFromExcelFileU8ArrDyn.mjs.html +1 -1
- package/docs/getEnv.mjs.html +1 -1
- package/docs/getErrorMessage.mjs.html +1 -1
- package/docs/getExcelU8ArrFromData.mjs.html +1 -1
- package/docs/getExcelU8ArrFromWorkbook.mjs.html +1 -1
- package/docs/getExcelWorkbookFromData.mjs.html +1 -1
- package/docs/getExcelWorkbookFromWorksheet.mjs.html +1 -1
- package/docs/getExcelWorksheetFromData.mjs.html +1 -1
- package/docs/getFileAccept.mjs.html +1 -1
- package/docs/getFileBasicHash.mjs.html +1 -1
- package/docs/getFileHash.mjs.html +1 -1
- package/docs/getFileName.mjs.html +1 -1
- package/docs/getFileNameExt.mjs.html +1 -1
- package/docs/getFileTrueName.mjs.html +1 -1
- package/docs/getFileType.mjs.html +1 -1
- package/docs/getFileXxHash.mjs.html +1 -1
- package/docs/getGlobal.mjs.html +1 -1
- package/docs/getObjSize.mjs.html +1 -1
- package/docs/getPathParent.mjs.html +1 -1
- package/docs/getTimeBetween.mjs.html +1 -1
- package/docs/getTimeFromUnit.mjs.html +1 -1
- package/docs/getTimeHp.mjs.html +1 -1
- package/docs/getTimeObject.mjs.html +1 -1
- package/docs/getTimeRange.mjs.html +1 -1
- package/docs/getUserAgent.mjs.html +1 -1
- package/docs/getUserAgentDyn.mjs.html +1 -1
- package/docs/getltdtkeys.mjs.html +7 -6
- package/docs/global.html +1 -1
- package/docs/haskey.mjs.html +1 -1
- package/docs/html2str.mjs.html +1 -1
- package/docs/htmlDecode.mjs.html +1 -1
- package/docs/htmlEncode.mjs.html +1 -1
- package/docs/importResources.mjs.html +1 -1
- package/docs/index.html +1 -1
- package/docs/interp1.mjs.html +1 -1
- package/docs/isDate.mjs.html +1 -1
- package/docs/isDev.mjs.html +1 -1
- package/docs/isEle.mjs.html +1 -1
- package/docs/isEleExistByID.mjs.html +1 -1
- package/docs/isEmail.mjs.html +1 -1
- package/docs/isErr.mjs.html +1 -1
- package/docs/isIE.mjs.html +1 -1
- package/docs/isNarrow.mjs.html +1 -1
- package/docs/isStrHasCapital.mjs.html +1 -1
- package/docs/isStrHasLetter.mjs.html +1 -1
- package/docs/isStrHasLowerCase.mjs.html +1 -1
- package/docs/isStrHasNumber.mjs.html +1 -1
- package/docs/isStrHasSpace.mjs.html +1 -1
- package/docs/isStrHasSymbol.mjs.html +1 -1
- package/docs/isUserIdentify.mjs.html +1 -1
- package/docs/isUserName.mjs.html +1 -1
- package/docs/isUserPw.mjs.html +1 -1
- package/docs/isWindow.mjs.html +1 -1
- package/docs/isab.mjs.html +1 -1
- package/docs/isarr.mjs.html +1 -1
- package/docs/isarr0.mjs.html +1 -1
- package/docs/isarr1.mjs.html +1 -1
- package/docs/isbigint.mjs.html +1 -1
- package/docs/isblob.mjs.html +1 -1
- package/docs/isbol.mjs.html +1 -1
- package/docs/isday.mjs.html +1 -1
- package/docs/isearr.mjs.html +1 -1
- package/docs/iseobj.mjs.html +1 -1
- package/docs/iser.mjs.html +1 -1
- package/docs/isernot.mjs.html +1 -1
- package/docs/isestr.mjs.html +1 -1
- package/docs/isfile.mjs.html +1 -1
- package/docs/isfun.mjs.html +1 -1
- package/docs/isint.mjs.html +1 -1
- package/docs/ismonth.mjs.html +1 -1
- package/docs/isn0int.mjs.html +1 -1
- package/docs/isn0num.mjs.html +1 -1
- package/docs/isnan.mjs.html +1 -1
- package/docs/isnbr.mjs.html +1 -1
- package/docs/isnint.mjs.html +1 -1
- package/docs/isnnum.mjs.html +1 -1
- package/docs/isnull.mjs.html +1 -1
- package/docs/isnum.mjs.html +1 -1
- package/docs/isobj.mjs.html +1 -1
- package/docs/isobj0.mjs.html +1 -1
- package/docs/isp0int.mjs.html +1 -1
- package/docs/isp0num.mjs.html +1 -1
- package/docs/ispint.mjs.html +1 -1
- package/docs/ispm.mjs.html +1 -1
- package/docs/ispnum.mjs.html +1 -1
- package/docs/isstr.mjs.html +1 -1
- package/docs/isstr0.mjs.html +1 -1
- package/docs/istime.mjs.html +1 -1
- package/docs/istimeTZ.mjs.html +1 -1
- package/docs/istimems.mjs.html +1 -1
- package/docs/istimemsTZ.mjs.html +1 -1
- package/docs/isu16arr.mjs.html +1 -1
- package/docs/isu8arr.mjs.html +1 -1
- package/docs/isundefined.mjs.html +1 -1
- package/docs/j2o.mjs.html +1 -1
- package/docs/judge.mjs.html +1 -1
- package/docs/keysmat2ltdt.mjs.html +1 -1
- package/docs/ltdt2vrtsable.mjs.html +1 -1
- package/docs/ltdtDiff.mjs.html +1 -1
- package/docs/ltdtDiffByKey.mjs.html +1 -1
- package/docs/ltdtkeys2mat.mjs.html +1 -1
- package/docs/ltdtkeysheads2mat.mjs.html +1 -1
- package/docs/ltdtmapping.mjs.html +1 -1
- package/docs/ltdtmerge.mjs.html +1 -1
- package/docs/ltdtpick.mjs.html +1 -1
- package/docs/ltdtpull.mjs.html +1 -1
- package/docs/mat2ltdt.mjs.html +1 -1
- package/docs/matConcat.mjs.html +1 -1
- package/docs/matDiff.mjs.html +1 -1
- package/docs/matat.mjs.html +1 -1
- package/docs/now2str.mjs.html +1 -1
- package/docs/now2strp.mjs.html +1 -1
- package/docs/nowDay2str.mjs.html +1 -1
- package/docs/nowms2str.mjs.html +1 -1
- package/docs/nowms2strp.mjs.html +1 -1
- package/docs/o2j.mjs.html +1 -1
- package/docs/obj2b64.mjs.html +1 -1
- package/docs/obj2pb64.mjs.html +1 -1
- package/docs/obj2str.mjs.html +1 -1
- package/docs/obj2stru8arr.mjs.html +1 -1
- package/docs/obj2u8arr.mjs.html +1 -1
- package/docs/objSortBy.mjs.html +1 -1
- package/docs/objSortByKeys.mjs.html +1 -1
- package/docs/oo.mjs.html +1 -1
- package/docs/openLink.mjs.html +1 -1
- package/docs/pb642obj.mjs.html +1 -1
- package/docs/pmChain.mjs.html +1 -1
- package/docs/pmConvertResolve.mjs.html +1 -1
- package/docs/pmDebounce.mjs.html +1 -1
- package/docs/pmHook.mjs.html +1 -1
- package/docs/pmHookReject.mjs.html +1 -1
- package/docs/pmIni.mjs.html +1 -1
- package/docs/pmInvResolve.mjs.html +1 -1
- package/docs/pmKeyMutex.mjs.html +1 -1
- package/docs/pmMap.mjs.html +1 -1
- package/docs/pmQueue.mjs.html +1 -1
- package/docs/pmSeries.mjs.html +1 -1
- package/docs/pmThrottle.mjs.html +1 -1
- package/docs/pmTimeout.mjs.html +1 -1
- package/docs/preciseNum.mjs.html +1 -1
- package/docs/pseudoRandom.mjs.html +1 -1
- package/docs/pseudoRandomIntRange.mjs.html +1 -1
- package/docs/pseudoRandomIntsNdpRange.mjs.html +1 -1
- package/docs/pseudoRandomIntsRange.mjs.html +1 -1
- package/docs/pseudoRandomRange.mjs.html +1 -1
- package/docs/pseudoRandomsRange.mjs.html +1 -1
- package/docs/queue.mjs.html +1 -1
- package/docs/random.mjs.html +1 -1
- package/docs/randomIntRange.mjs.html +1 -1
- package/docs/randomIntsNdpRange.mjs.html +1 -1
- package/docs/randomIntsRange.mjs.html +1 -1
- package/docs/randomRange.mjs.html +1 -1
- package/docs/randomsRange.mjs.html +1 -1
- package/docs/rang.mjs.html +1 -1
- package/docs/rep.mjs.html +1 -1
- package/docs/repObj.mjs.html +1 -1
- package/docs/replace.mjs.html +1 -1
- package/docs/replaceObj.mjs.html +1 -1
- package/docs/replacePlus.mjs.html +1 -1
- package/docs/round.mjs.html +1 -1
- package/docs/secd.mjs.html +1 -1
- package/docs/sep.mjs.html +1 -1
- package/docs/sepInt.mjs.html +1 -1
- package/docs/setIntervalHp.mjs.html +1 -1
- package/docs/setTimeoutHp.mjs.html +1 -1
- package/docs/sind.mjs.html +1 -1
- package/docs/split.mjs.html +1 -1
- package/docs/str2aes.mjs.html +1 -1
- package/docs/str2b64.mjs.html +1 -1
- package/docs/str2hint.mjs.html +1 -1
- package/docs/str2md5.mjs.html +1 -1
- package/docs/str2obj.mjs.html +1 -1
- package/docs/str2sha.mjs.html +1 -1
- package/docs/str2sha512.mjs.html +1 -1
- package/docs/str2u8arr.mjs.html +1 -1
- package/docs/strCompare.mjs.html +1 -1
- package/docs/strCompareForVersion.mjs.html +1 -1
- package/docs/strDiff.mjs.html +1 -1
- package/docs/strDiffToHtml.mjs.html +1 -1
- package/docs/strFindFuzz.mjs.html +1 -1
- package/docs/strFindSimilar.mjs.html +1 -1
- package/docs/strTruncate.mjs.html +1 -1
- package/docs/strdelleft.mjs.html +1 -1
- package/docs/strdelright.mjs.html +1 -1
- package/docs/strleft.mjs.html +1 -1
- package/docs/strmid.mjs.html +1 -1
- package/docs/strright.mjs.html +1 -1
- package/docs/stru8arr2obj.mjs.html +1 -1
- package/docs/tand.mjs.html +1 -1
- package/docs/time2day.mjs.html +1 -1
- package/docs/time2hour.mjs.html +1 -1
- package/docs/time2min.mjs.html +1 -1
- package/docs/timeTZ2day.mjs.html +1 -1
- package/docs/timeTZ2expire.mjs.html +1 -1
- package/docs/timeTZ2hour.mjs.html +1 -1
- package/docs/timeTZ2min.mjs.html +1 -1
- package/docs/timeTZ2past.mjs.html +1 -1
- package/docs/timems2day.mjs.html +1 -1
- package/docs/timems2hour.mjs.html +1 -1
- package/docs/timems2min.mjs.html +1 -1
- package/docs/timems2time.mjs.html +1 -1
- package/docs/timemsTZ2day.mjs.html +1 -1
- package/docs/timemsTZ2expire.mjs.html +1 -1
- package/docs/timemsTZ2hour.mjs.html +1 -1
- package/docs/timemsTZ2min.mjs.html +1 -1
- package/docs/timemsTZ2past.mjs.html +1 -1
- package/docs/timemsTZ2time.mjs.html +1 -1
- package/docs/treeObj.mjs.html +7 -7
- package/docs/treeToFilepath.mjs.html +1 -1
- package/docs/trim.mjs.html +1 -1
- package/docs/u16arr2b64.mjs.html +1 -1
- package/docs/u16arr2u8arr.mjs.html +1 -1
- package/docs/u8arr2ab.mjs.html +1 -1
- package/docs/u8arr2b64.mjs.html +1 -1
- package/docs/u8arr2blob.mjs.html +1 -1
- package/docs/u8arr2bs.mjs.html +1 -1
- package/docs/u8arr2obj.mjs.html +17 -3
- package/docs/u8arr2str.mjs.html +1 -1
- package/docs/u8arr2u16arr.mjs.html +1 -1
- package/docs/urlParse.mjs.html +1 -1
- package/docs/verifyValue.mjs.html +1 -1
- package/docs/waitFun.mjs.html +1 -1
- package/docs/wsemi.html +36 -13
- package/package.json +1 -1
- package/src/clearXSS.mjs +262 -24
- package/src/flattenToConn.mjs +11 -7
- package/src/flattenTree.mjs +8 -8
- package/src/fsTask.mjs +13 -12
- package/src/getltdtkeys.mjs +6 -5
- package/src/treeObj.mjs +6 -6
- package/src/u8arr2obj.mjs +16 -2
- package/test/clearXSS.test.mjs +1276 -1
- package/test/flattenToConn.test.mjs +83 -0
- package/test/flattenTree.test.mjs +49 -0
- package/test/fsTask.test.mjs +144 -0
- package/test/getltdtkeys.test.mjs +71 -0
- package/test/tools/clearXssWalkRunner.mjs +202 -0
- package/test/treeObj.test.mjs +119 -0
- package/test/u8arr2obj.test.mjs +107 -2
- package/toolfp/dist/wsemip.umd.js +1 -1
- package/toolparfor/dist/wpf.umd.js +1 -1
- package/toolparfor/dist/wpf_pmSeries.umd.js +1 -1
|
@@ -2,6 +2,89 @@ import assert from 'assert'
|
|
|
2
2
|
import flattenToConn from '../src/flattenToConn.mjs'
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
describe(`flattenToConn 偽稱Array之物件視為物件(R-OBJ-ITER-01 候選10)`, function() {
|
|
6
|
+
|
|
7
|
+
//以Symbol.toStringTag偽稱'Array'之物件(isarr為真而非真陣列), 可寫與不可寫兩種標籤
|
|
8
|
+
let mkFake = (len, writable) => {
|
|
9
|
+
let o = { a: 'kept', length: len }
|
|
10
|
+
if (writable) {
|
|
11
|
+
o[Symbol.toStringTag] = 'Array'
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
Object.defineProperty(o, Symbol.toStringTag, { value: 'Array' })
|
|
15
|
+
}
|
|
16
|
+
return o
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//flattenToConn以force走訪, 含Symbol鍵(treeObj取自有屬性名稱與自有Symbol), 偽標籤本身之Symbol鍵亦成一節點; 此處只比對字串鍵之節點
|
|
20
|
+
let strNodes = (r) => r.filter((v) => !/Symbol\(/.test(String(v.id)))
|
|
21
|
+
|
|
22
|
+
for (let writable of [true, false]) {
|
|
23
|
+
let tag = writable ? 'writable' : 'non-writable'
|
|
24
|
+
|
|
25
|
+
it(`should give the same nodes for a nested object faking Array (${tag} tag, length 2) as for the plain object with the same keys`, function() {
|
|
26
|
+
let r = strNodes(flattenToConn({ child: mkFake(2, writable) }))
|
|
27
|
+
let e = flattenToConn({ child: { a: 'kept', length: 2 } })
|
|
28
|
+
assert.strict.deepStrictEqual(r, e)
|
|
29
|
+
assert.strict.strictEqual(r[0].type, 'object')
|
|
30
|
+
assert.strict.strictEqual(r[0].numOfChilren, 2)
|
|
31
|
+
assert.strict.deepStrictEqual(r.map((v) => v.id), ['child', 'child-a', 'child-length'])
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it(`should give the same nodes for a nested object faking Array (${tag} tag, length 0) as for the plain object with the same keys`, function() {
|
|
35
|
+
let r = strNodes(flattenToConn({ child: mkFake(0, writable) }))
|
|
36
|
+
let e = flattenToConn({ child: { a: 'kept', length: 0 } })
|
|
37
|
+
assert.strict.deepStrictEqual(r, e)
|
|
38
|
+
assert.strict.strictEqual(r[0].type, 'object')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it(`should give the same nodes for an object faking Array (${tag} tag, length 2) at the root as for the plain object with the same keys`, function() {
|
|
42
|
+
let r = strNodes(flattenToConn(mkFake(2, writable)))
|
|
43
|
+
let e = flattenToConn({ a: 'kept', length: 2 })
|
|
44
|
+
assert.strict.deepStrictEqual(r, e)
|
|
45
|
+
assert.strict.deepStrictEqual(r.map((v) => v.id), ['a', 'length'])
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (let writable of [true, false]) {
|
|
50
|
+
for (let len of [0, 2, 1000]) {
|
|
51
|
+
it(`should count the string keys as the children of an object faking Array (${writable ? 'writable' : 'non-writable'} tag, length ${len}), not the length value`, function() {
|
|
52
|
+
//R-OBJ-ITER-01: length為一般鍵, numOfChilren為自有鍵數(a與length共2), 與length之值無關
|
|
53
|
+
let o = { a: 'kept', length: len }
|
|
54
|
+
if (writable) {
|
|
55
|
+
o[Symbol.toStringTag] = 'Array'
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
Object.defineProperty(o, Symbol.toStringTag, { value: 'Array' })
|
|
59
|
+
}
|
|
60
|
+
let r = flattenToConn({ child: o })
|
|
61
|
+
assert.strict.strictEqual(r[0].id, 'child')
|
|
62
|
+
assert.strict.strictEqual(r[0].type, 'object')
|
|
63
|
+
assert.strict.strictEqual(r[0].numOfChilren, 2)
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
for (let tag of ['Foo', 'Object', 'Arguments']) {
|
|
69
|
+
it(`should give array nodes for a real array with another Symbol.toStringTag (${tag}), like an ordinary array`, function() {
|
|
70
|
+
let a = Object.defineProperty([1, 2], Symbol.toStringTag, { value: tag })
|
|
71
|
+
let r = flattenToConn({ list: a })
|
|
72
|
+
let e = flattenToConn({ list: [1, 2] })
|
|
73
|
+
assert.strict.deepStrictEqual(r, e)
|
|
74
|
+
assert.strict.strictEqual(r[0].type, 'array')
|
|
75
|
+
assert.strict.deepStrictEqual(r.map((v) => v.id), ['list', 'list-0', 'list-1'])
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
it(`should still give array nodes for real arrays`, function() {
|
|
80
|
+
let r = flattenToConn({ list: [1, [2]] })
|
|
81
|
+
assert.strict.strictEqual(r[0].type, 'array')
|
|
82
|
+
assert.strict.strictEqual(r[0].numOfChilren, 2)
|
|
83
|
+
assert.strict.strictEqual(r.find((v) => v.id === 'list-1').type, 'array')
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
})
|
|
87
|
+
|
|
5
88
|
describe(`flattenToConn`, function() {
|
|
6
89
|
|
|
7
90
|
let obj = {
|
|
@@ -2,6 +2,55 @@ import assert from 'assert'
|
|
|
2
2
|
import flattenTree from '../src/flattenTree.mjs'
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
describe(`flattenTree 偽稱Array之根節點視為物件(R-OBJ-ITER-01 候選10)`, function() {
|
|
6
|
+
|
|
7
|
+
//以Symbol.toStringTag偽稱'Array'之根節點(isarr為真而非真陣列): 結果須同無標籤之相同鍵物件(標籤不可寫者不展開進節點)
|
|
8
|
+
let mkFake = (writable, len = 2) => {
|
|
9
|
+
let o = { id: 1, length: len, children: [{ id: 2, data: 'x' }] }
|
|
10
|
+
if (writable) {
|
|
11
|
+
o[Symbol.toStringTag] = 'Array'
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
Object.defineProperty(o, Symbol.toStringTag, { value: 'Array' })
|
|
15
|
+
}
|
|
16
|
+
return o
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
for (let writable of [true, false]) {
|
|
20
|
+
let tag = writable ? 'writable' : 'non-writable'
|
|
21
|
+
for (let len of [2, 0]) {
|
|
22
|
+
it(`should flatten a root object faking Array (${tag} tag, length ${len}) like the plain object with the same keys`, function() {
|
|
23
|
+
//根為物件時回傳根節點本身(含level與nk); length為0時不得被當成空陣列而回傳[]
|
|
24
|
+
let pick = (n) => ({ id: n.id, length: n.length, level: n.level, nk: n.nk, children: n.children })
|
|
25
|
+
let r = flattenTree(mkFake(writable, len))
|
|
26
|
+
let e = flattenTree({ id: 1, length: len, children: [{ id: 2, data: 'x' }] })
|
|
27
|
+
assert.strict.deepStrictEqual(pick(r), pick(e))
|
|
28
|
+
assert.strict.deepStrictEqual(pick(e), { id: 1, length: len, level: 0, nk: [0], children: [{ id: 2, data: 'x' }] })
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
for (let tag of ['Foo', 'Object']) {
|
|
34
|
+
it(`should flatten a real array root with another Symbol.toStringTag (${tag}) like an ordinary array`, function() {
|
|
35
|
+
let a = Object.defineProperty([{ id: 1, children: [{ id: 2 }] }], Symbol.toStringTag, { value: tag })
|
|
36
|
+
assert.strict.deepStrictEqual(flattenTree(a).map((v) => v.id), [1, 2])
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
it(`should return [] for an object faking Array without own string keys, like an empty object`, function() {
|
|
41
|
+
assert.strict.deepStrictEqual(flattenTree({ [Symbol.toStringTag]: 'Array' }), [])
|
|
42
|
+
assert.strict.deepStrictEqual(flattenTree(Object.defineProperty({}, Symbol.toStringTag, { value: 'Array' })), [])
|
|
43
|
+
assert.strict.deepStrictEqual(flattenTree({}), [])
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it(`should still flatten a real array root and return [] for empty array and empty object`, function() {
|
|
47
|
+
assert.strict.deepStrictEqual(flattenTree([{ id: 1, children: [{ id: 2 }] }]).map((v) => v.id), [1, 2])
|
|
48
|
+
assert.strict.deepStrictEqual(flattenTree([]), [])
|
|
49
|
+
assert.strict.deepStrictEqual(flattenTree({}), [])
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
})
|
|
53
|
+
|
|
5
54
|
describe(`flattenTree`, function() {
|
|
6
55
|
|
|
7
56
|
let obj = {
|
package/test/fsTask.test.mjs
CHANGED
|
@@ -3,8 +3,152 @@ import assert from 'assert'
|
|
|
3
3
|
import fsDeleteFile from '../src/fsDeleteFile.mjs'
|
|
4
4
|
import fsCreateFolder from '../src/fsCreateFolder.mjs'
|
|
5
5
|
import fsDeleteFolder from '../src/fsDeleteFolder.mjs'
|
|
6
|
+
import { fileURLToPath } from 'url'
|
|
7
|
+
import { dirname, join } from 'path'
|
|
6
8
|
import fsTask from '../src/fsTask.mjs'
|
|
7
9
|
|
|
10
|
+
let __dirname = dirname(fileURLToPath(import.meta.url))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
describe(`fsTask 檔案來源之紀錄須為一般物件(R-OBJ-ITER-01 候選9)`, function() {
|
|
14
|
+
|
|
15
|
+
//fpHash.json、fpResult.json 讀自檔案(可能被竄改或損毀), 須視為一般物件之字典: length 為一般鍵, 非一般物件者視為無紀錄
|
|
16
|
+
let root = join(__dirname, '_tmp', 'fsTaskRecord')
|
|
17
|
+
let wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
18
|
+
let item = (p) => [{ type: 'file', path: p }]
|
|
19
|
+
|
|
20
|
+
//測試自建自刪(只刪本案資料夾, 不刪 test/_tmp 根目錄)
|
|
21
|
+
after(function() {
|
|
22
|
+
fs.rmSync(root, { recursive: true, force: true })
|
|
23
|
+
assert.strict.strictEqual(fs.existsSync(root), false)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
//mk, 建立案例資料夾: watch 為監看夾(可預放檔案), _tkfs 為儲存夾(可預寫紀錄檔原文)
|
|
27
|
+
let mk = (name, { hash = null, result = null, files = {} } = {}) => {
|
|
28
|
+
let base = join(root, name)
|
|
29
|
+
fs.rmSync(base, { recursive: true, force: true })
|
|
30
|
+
let fd = join(base, 'watch')
|
|
31
|
+
let st = join(base, '_tkfs')
|
|
32
|
+
fs.mkdirSync(fd, { recursive: true })
|
|
33
|
+
fs.mkdirSync(st, { recursive: true })
|
|
34
|
+
for (let [fn, c] of Object.entries(files)) {
|
|
35
|
+
fs.writeFileSync(join(fd, fn), c, 'utf8')
|
|
36
|
+
}
|
|
37
|
+
if (hash !== null) {
|
|
38
|
+
fs.writeFileSync(join(st, 'fpHash.json'), hash, 'utf8')
|
|
39
|
+
}
|
|
40
|
+
if (result !== null) {
|
|
41
|
+
fs.writeFileSync(join(st, 'fpResult.json'), result, 'utf8')
|
|
42
|
+
}
|
|
43
|
+
return { fd, st }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//watch, 以 40 ms 輪詢 ms 毫秒, 收集 change 事件並立即 resolve 其 pm
|
|
47
|
+
let watch = async (c, ms = 400) => {
|
|
48
|
+
let events = []
|
|
49
|
+
let ev = fsTask(c.fd, { fdStorage: c.st, timeInterval: 40 })
|
|
50
|
+
ev.on('change', (msg) => {
|
|
51
|
+
events.push({ type: msg.type, fp: msg.fp, fn: msg.fn, hash: msg.hash })
|
|
52
|
+
msg.pm.resolve()
|
|
53
|
+
})
|
|
54
|
+
try {
|
|
55
|
+
await wait(ms)
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
ev.clear()
|
|
59
|
+
}
|
|
60
|
+
return events
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let readJson = (c, fn) => JSON.parse(fs.readFileSync(join(c.st, fn), 'utf8'))
|
|
64
|
+
let sortBy = (arr) => [...arr].sort((a, b) => (a.fp < b.fp ? -1 : 1))
|
|
65
|
+
|
|
66
|
+
it(`should treat a length key of fpHash.json as an ordinary path: one del event per recorded key and none repeated`, async function() {
|
|
67
|
+
//修前: 整個字典依 length 當類陣列迭代, 每個輪詢週期重複派發 { type: 'del', fp: '0', fn: '0', hash: '' }
|
|
68
|
+
let c = mk('hash-length', { hash: '{"length":1,"a":"h"}' })
|
|
69
|
+
let events = await watch(c, 500)
|
|
70
|
+
assert.strict.deepStrictEqual(sortBy(events), [
|
|
71
|
+
{ type: 'del', fp: 'a', fn: 'a', hash: 'h' },
|
|
72
|
+
{ type: 'del', fp: 'length', fn: 'length', hash: 1 },
|
|
73
|
+
])
|
|
74
|
+
assert.strict.deepStrictEqual(readJson(c, 'fpHash.json'), {})
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it(`should dispatch one del event for a recorded path and update the record (control without length)`, async function() {
|
|
78
|
+
let c = mk('hash-control', { hash: '{"a":"h"}' })
|
|
79
|
+
let events = await watch(c, 400)
|
|
80
|
+
assert.strict.deepStrictEqual(events, [{ type: 'del', fp: 'a', fn: 'a', hash: 'h' }])
|
|
81
|
+
assert.strict.deepStrictEqual(readJson(c, 'fpHash.json'), {})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it(`should dispatch add once for a watched file named length`, async function() {
|
|
85
|
+
let c = mk('hash-file-length', { files: { length: 'abc' } })
|
|
86
|
+
let events = await watch(c, 400)
|
|
87
|
+
assert.strict.deepStrictEqual(events.map((v) => [v.type, v.fn]), [['add', 'length']])
|
|
88
|
+
assert.strict.deepStrictEqual(Object.keys(readJson(c, 'fpHash.json')), [events[0].fp])
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
let notObjs = ['["a","b"]', '"abc"', '123', 'null', 'true', '{bad', '']
|
|
92
|
+
for (let content of notObjs) {
|
|
93
|
+
it(`should treat fpHash.json as no record when it is not a plain object (${JSON.stringify(content)}): no event for an empty folder`, async function() {
|
|
94
|
+
let c = mk('hash-notobj', { hash: content })
|
|
95
|
+
let events = await watch(c, 300)
|
|
96
|
+
assert.strict.deepStrictEqual(events, [])
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
it(`should dispatch add once for a new file and record it when fpHash.json is not a plain object (${JSON.stringify(content)})`, async function() {
|
|
100
|
+
let c = mk('hash-notobj-file', { hash: content, files: { 'f.txt': 'abc' } })
|
|
101
|
+
let events = await watch(c, 400)
|
|
102
|
+
assert.strict.deepStrictEqual(events.map((v) => [v.type, v.fn]), [['add', 'f.txt']])
|
|
103
|
+
assert.strict.deepStrictEqual(Object.keys(readJson(c, 'fpHash.json')), [events[0].fp])
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
it(`should keep other results and the length key when fpResult.json has a length key and a result is taken`, function() {
|
|
108
|
+
//修前: each 依 length 當類陣列迭代, 其他結果全被清空, 檔案寫成 {}
|
|
109
|
+
let c = mk('result-length', { result: JSON.stringify({ 'length': 0, 'a|h': item('x'), 'b|h': item('y') }) })
|
|
110
|
+
let ev = fsTask(c.fd, { fdStorage: c.st, timeInterval: 100000 })
|
|
111
|
+
try {
|
|
112
|
+
assert.strict.deepStrictEqual(ev.getAndEliminateResult('a', 'h'), item('x'))
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
ev.clear()
|
|
116
|
+
}
|
|
117
|
+
assert.strict.deepStrictEqual(readJson(c, 'fpResult.json'), { 'length': 0, 'b|h': item('y') })
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it(`should keep other results when a result is taken (control without length)`, function() {
|
|
121
|
+
let c = mk('result-control', { result: JSON.stringify({ 'a|h': item('x'), 'b|h': item('y') }) })
|
|
122
|
+
let ev = fsTask(c.fd, { fdStorage: c.st, timeInterval: 100000 })
|
|
123
|
+
try {
|
|
124
|
+
assert.strict.deepStrictEqual(ev.getAndEliminateResult('a', 'h'), item('x'))
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
ev.clear()
|
|
128
|
+
}
|
|
129
|
+
assert.strict.deepStrictEqual(readJson(c, 'fpResult.json'), { 'b|h': item('y') })
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
for (let content of notObjs) {
|
|
133
|
+
it(`should treat fpResult.json as no record when it is not a plain object (${JSON.stringify(content)}): setResult does not throw and results can be taken`, function() {
|
|
134
|
+
//修前: 字串/數字/null/布林使 setResult 拋 TypeError, 字串被展開寫成 {"0":"a",...}
|
|
135
|
+
let c = mk('result-notobj', { result: content })
|
|
136
|
+
let ev = fsTask(c.fd, { fdStorage: c.st, timeInterval: 100000 })
|
|
137
|
+
try {
|
|
138
|
+
assert.strict.deepStrictEqual(ev.getAndEliminateResult('x', 'y'), [])
|
|
139
|
+
assert.strict.deepStrictEqual(readJson(c, 'fpResult.json'), {})
|
|
140
|
+
ev.setResult('f', 'h', item('p'))
|
|
141
|
+
assert.strict.deepStrictEqual(readJson(c, 'fpResult.json'), { 'f|h': item('p') })
|
|
142
|
+
assert.strict.deepStrictEqual(ev.getAndEliminateResult('f', 'h'), item('p'))
|
|
143
|
+
assert.strict.deepStrictEqual(readJson(c, 'fpResult.json'), {})
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
ev.clear()
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
})
|
|
8
152
|
|
|
9
153
|
describe(`fsTask`, function() {
|
|
10
154
|
|
|
@@ -2,6 +2,77 @@ import assert from 'assert'
|
|
|
2
2
|
import getltdtkeys from '../src/getltdtkeys.mjs'
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
describe(`getltdtkeys 列物件只依自有鍵(R-OBJ-ITER-01 候選11)`, function() {
|
|
6
|
+
|
|
7
|
+
it(`should return the own keys of a row that fakes Arguments with a non-writable Symbol.toStringTag`, function() {
|
|
8
|
+
//lodash keys 對不可寫偽稱 Arguments 之物件走 baseTimes(length), 修前得 ['0','1','a']
|
|
9
|
+
let row = Object.defineProperty({ a: 1, length: 2 }, Symbol.toStringTag, { value: 'Arguments' })
|
|
10
|
+
assert.strict.deepStrictEqual(getltdtkeys([row]), ['a', 'length'])
|
|
11
|
+
assert.strict.deepStrictEqual(getltdtkeys([{ x: 1 }, row, { y: 2 }]), ['x', 'a', 'length', 'y'])
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it(`should return the own keys of a row that fakes Array or Arguments with a writable tag`, function() {
|
|
15
|
+
assert.strict.deepStrictEqual(getltdtkeys([{ a: 1, length: 2, [Symbol.toStringTag]: 'Arguments' }]), ['a', 'length'])
|
|
16
|
+
assert.strict.deepStrictEqual(getltdtkeys([{ a: 1, length: 2, [Symbol.toStringTag]: 'Array' }]), ['a', 'length'])
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it(`should treat length as an ordinary key of a row (any non-negative integer, small values)`, function() {
|
|
20
|
+
assert.strict.deepStrictEqual(getltdtkeys([{ length: 2, a: 'x' }]), ['length', 'a'])
|
|
21
|
+
assert.strict.deepStrictEqual(getltdtkeys([{ length: 0, a: 'x' }, { length: 1000, b: 'y' }]), ['length', 'a', 'b'])
|
|
22
|
+
assert.strict.deepStrictEqual(getltdtkeys([{ a: 1, length: -0 }]), ['a', 'length'])
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it(`should keep the behavior for rows that are arrays (including holes), strings, typed arrays, null and primitives`, function() {
|
|
26
|
+
//列為真陣列者沿用 lodash keys: 含空洞索引(Object.keys 不含)
|
|
27
|
+
assert.strict.deepStrictEqual(getltdtkeys([[1, 2]]), ['0', '1'])
|
|
28
|
+
assert.strict.deepStrictEqual(getltdtkeys([[, 1]]), ['0', '1']) // eslint-disable-line no-sparse-arrays
|
|
29
|
+
assert.strict.deepStrictEqual(getltdtkeys([new Uint8Array(2)]), ['0', '1'])
|
|
30
|
+
assert.strict.deepStrictEqual(getltdtkeys([null, undefined, 5, true, 'ab', { a: 1 }]), ['0', '1', 'a'])
|
|
31
|
+
assert.strict.deepStrictEqual(getltdtkeys([new Map([['k', 1]]), new Date(0), /a/, () => 1]), [])
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it(`should return the own enumerable string keys of class instances, null-prototype rows and rows with inherited keys`, function() {
|
|
35
|
+
class Foo {
|
|
36
|
+
constructor() {
|
|
37
|
+
this.a = 1
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
let np = Object.create(null)
|
|
41
|
+
np.n = 1
|
|
42
|
+
let inh = Object.create({ p: 1 })
|
|
43
|
+
inh.q = 2
|
|
44
|
+
assert.strict.deepStrictEqual(getltdtkeys([new Foo(), np, inh]), ['a', 'n', 'q'])
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it(`should return the same keys as the lodash keys on 500 random rows without length keys`, function() {
|
|
48
|
+
let seed = 20261020
|
|
49
|
+
let rnd = () => {
|
|
50
|
+
seed = (seed * 1103515245 + 12345) % 2147483648
|
|
51
|
+
return seed / 2147483648
|
|
52
|
+
}
|
|
53
|
+
let names = ['a', 'b', 'c', '0', '1', '10', 'constructor', 'toString', 'x y', '中文']
|
|
54
|
+
let rows = []
|
|
55
|
+
for (let i = 0; i < 500; i++) {
|
|
56
|
+
let o = {}
|
|
57
|
+
let n = Math.floor(rnd() * 5)
|
|
58
|
+
for (let j = 0; j < n; j++) {
|
|
59
|
+
o[names[Math.floor(rnd() * names.length)]] = j
|
|
60
|
+
}
|
|
61
|
+
rows.push(o)
|
|
62
|
+
}
|
|
63
|
+
let expected = []
|
|
64
|
+
for (let o of rows) {
|
|
65
|
+
for (let k of Object.keys(o)) {
|
|
66
|
+
if (!expected.includes(k)) {
|
|
67
|
+
expected.push(k)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
assert.strict.deepStrictEqual(getltdtkeys(rows), expected)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
})
|
|
75
|
+
|
|
5
76
|
describe(`getltdtkeys`, function() {
|
|
6
77
|
let k
|
|
7
78
|
let o = {}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
//clearXssWalkRunner.mjs: 於限額子行程執行 clearXSS 之走訪案例(R-XSS-WALK-01): 極深巢狀、大型共用結構(DAG)、大型循環
|
|
2
|
+
// 修前之實作對深巢狀同步拋 RangeError(未捕捉, 離開碼非 0)、對 DAG 依路徑數指數重走(2^n, 逾時被終止)
|
|
3
|
+
// 約定同runChildCase: node [--max-old-space-size=N] clearXssWalkRunner.mjs <caseName>, 結果以一行'@@R@@'開頭之JSON輸出至stdout
|
|
4
|
+
// caseName:
|
|
5
|
+
// 'deep:<obj|arr|mixed|map|set>:<層數>': 迭代建構之深巢狀(葉為字串)
|
|
6
|
+
// 'dag:<obj|arr|map|set|mixed>:<層數>': 每層兩個參照指向同一子結構, 葉為字串; 計 filterXSS 呼叫數
|
|
7
|
+
// 'cycle:<長度>': 長度為n之物件環(最後一個指回第一個), 每個節點帶一個字串
|
|
8
|
+
import clearXSS from '../../src/clearXSS.mjs'
|
|
9
|
+
import fxss from '../../src/_filterXSS.mjs'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
let x = '<script>alert(1)</script>'
|
|
13
|
+
let fx = '<script>alert(1)</script>'
|
|
14
|
+
|
|
15
|
+
//計 filterXSS 呼叫數(fxss為可變單例, clearXSS每次呼叫經fxss.getFilterXSS取得)
|
|
16
|
+
let calls = 0
|
|
17
|
+
let origGet = fxss.getFilterXSS
|
|
18
|
+
fxss.getFilterXSS = () => {
|
|
19
|
+
let f = origGet()
|
|
20
|
+
let w = (c, o) => {
|
|
21
|
+
calls++
|
|
22
|
+
return f(c, o)
|
|
23
|
+
}
|
|
24
|
+
w.escapeAttrValue = f.escapeAttrValue
|
|
25
|
+
return w
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let caseName = process.argv[2] || ''
|
|
29
|
+
let [kind, sub, sn] = caseName.split(':')
|
|
30
|
+
let n = Number(kind === 'cycle' ? sub : sn)
|
|
31
|
+
|
|
32
|
+
//wrap, 依種類包一層
|
|
33
|
+
let wrap = (kind2, i, cur) => {
|
|
34
|
+
if (kind2 === 'obj') {
|
|
35
|
+
return { a: cur }
|
|
36
|
+
}
|
|
37
|
+
if (kind2 === 'arr') {
|
|
38
|
+
return [cur]
|
|
39
|
+
}
|
|
40
|
+
if (kind2 === 'map') {
|
|
41
|
+
return new Map([['k', cur]])
|
|
42
|
+
}
|
|
43
|
+
if (kind2 === 'set') {
|
|
44
|
+
return new Set([cur])
|
|
45
|
+
}
|
|
46
|
+
return (i % 2 === 0) ? { a: cur } : [cur] //mixed
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
//child, 取子節點(迭代取葉用)
|
|
50
|
+
let child = (v) => {
|
|
51
|
+
if (Array.isArray(v)) {
|
|
52
|
+
return v[0]
|
|
53
|
+
}
|
|
54
|
+
if (v instanceof Map) {
|
|
55
|
+
return v.get('k')
|
|
56
|
+
}
|
|
57
|
+
if (v instanceof Set) {
|
|
58
|
+
return [...v][0]
|
|
59
|
+
}
|
|
60
|
+
return v.a
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//leaf, 迭代取葉並回傳深度
|
|
64
|
+
let leafOf = (v) => {
|
|
65
|
+
let d = 0
|
|
66
|
+
while (typeof v === 'object' && v !== null) {
|
|
67
|
+
v = child(v)
|
|
68
|
+
d++
|
|
69
|
+
}
|
|
70
|
+
return { v, d }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let out = { kind, sub, n }
|
|
74
|
+
clearXSS({ b: x }) //先載入js-xss
|
|
75
|
+
if (global.gc) {
|
|
76
|
+
global.gc()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (kind === 'deep') {
|
|
80
|
+
let inp = x
|
|
81
|
+
for (let i = 0; i < n; i++) {
|
|
82
|
+
inp = wrap(sub, i, inp)
|
|
83
|
+
}
|
|
84
|
+
let h0 = process.memoryUsage().heapUsed
|
|
85
|
+
calls = 0
|
|
86
|
+
let t0 = process.hrtime.bigint()
|
|
87
|
+
let r = clearXSS(inp)
|
|
88
|
+
out.ms = Number(process.hrtime.bigint() - t0) / 1e6
|
|
89
|
+
out.heapMB = (process.memoryUsage().heapUsed - h0) / 1048576
|
|
90
|
+
let lo = leafOf(r)
|
|
91
|
+
let li = leafOf(inp)
|
|
92
|
+
out.leafCleaned = lo.v === fx
|
|
93
|
+
out.inputIntact = li.v === x
|
|
94
|
+
out.depthOut = lo.d
|
|
95
|
+
out.depthIn = li.d
|
|
96
|
+
out.notSame = r !== inp
|
|
97
|
+
out.calls = calls
|
|
98
|
+
}
|
|
99
|
+
else if (kind === 'dag') {
|
|
100
|
+
let cur = sub === 'map' ? new Map([['v', x]]) : sub === 'set' ? new Set([x]) : sub === 'arr' ? [x] : { v: x } //mixed之葉同obj
|
|
101
|
+
for (let i = 0; i < n; i++) {
|
|
102
|
+
if (sub === 'obj') {
|
|
103
|
+
cur = { l: cur, r: cur }
|
|
104
|
+
}
|
|
105
|
+
else if (sub === 'arr') {
|
|
106
|
+
cur = [cur, cur]
|
|
107
|
+
}
|
|
108
|
+
else if (sub === 'map') {
|
|
109
|
+
cur = new Map([['l', cur], ['r', cur]])
|
|
110
|
+
}
|
|
111
|
+
else if (sub === 'set') {
|
|
112
|
+
cur = new Set([{ p: cur }, { q: cur }]) //Set元素不可重複, 兩個包裝物件各引用同一子Set
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
cur = (i % 2 === 0) ? { l: cur, r: cur } : [cur, cur]
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
calls = 0
|
|
119
|
+
let t0 = process.hrtime.bigint()
|
|
120
|
+
let r = clearXSS(cur)
|
|
121
|
+
out.ms = Number(process.hrtime.bigint() - t0) / 1e6
|
|
122
|
+
out.calls = calls
|
|
123
|
+
//共用: 沿 l 與 r 兩側各走到底, 每層兩側須為同一輸出物件
|
|
124
|
+
let shared = true
|
|
125
|
+
let v = r
|
|
126
|
+
let steps = 0
|
|
127
|
+
while (typeof v === 'object' && v !== null && steps < n + 5) {
|
|
128
|
+
if (sub === 'obj') {
|
|
129
|
+
if (v.l === undefined) {
|
|
130
|
+
break
|
|
131
|
+
}
|
|
132
|
+
shared = shared && v.l === v.r
|
|
133
|
+
v = v.l
|
|
134
|
+
}
|
|
135
|
+
else if (sub === 'arr') {
|
|
136
|
+
if (v.length !== 2) {
|
|
137
|
+
break
|
|
138
|
+
}
|
|
139
|
+
shared = shared && v[0] === v[1]
|
|
140
|
+
v = v[0]
|
|
141
|
+
}
|
|
142
|
+
else if (sub === 'map') {
|
|
143
|
+
if (!v.has('l')) {
|
|
144
|
+
break
|
|
145
|
+
}
|
|
146
|
+
shared = shared && v.get('l') === v.get('r')
|
|
147
|
+
v = v.get('l')
|
|
148
|
+
}
|
|
149
|
+
else if (sub === 'set') {
|
|
150
|
+
let es = [...v]
|
|
151
|
+
if (typeof es[0] !== 'object' || es[0] === null || es[0].p === undefined) {
|
|
152
|
+
break
|
|
153
|
+
}
|
|
154
|
+
shared = shared && es[0].p === es[1].q
|
|
155
|
+
v = es[0].p
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
if (Array.isArray(v)) {
|
|
159
|
+
shared = shared && v[0] === v[1]
|
|
160
|
+
v = v[0]
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
if (v.l === undefined) {
|
|
164
|
+
break
|
|
165
|
+
}
|
|
166
|
+
shared = shared && v.l === v.r
|
|
167
|
+
v = v.l
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
steps++
|
|
171
|
+
}
|
|
172
|
+
out.shared = shared
|
|
173
|
+
out.steps = steps
|
|
174
|
+
}
|
|
175
|
+
else if (kind === 'cycle') {
|
|
176
|
+
let head = { i: 0, s: x }
|
|
177
|
+
let cur = head
|
|
178
|
+
for (let i = 1; i < n; i++) {
|
|
179
|
+
let nx = { i, s: x }
|
|
180
|
+
cur.next = nx
|
|
181
|
+
cur = nx
|
|
182
|
+
}
|
|
183
|
+
cur.next = head
|
|
184
|
+
let t0 = process.hrtime.bigint()
|
|
185
|
+
let r = clearXSS(head)
|
|
186
|
+
out.ms = Number(process.hrtime.bigint() - t0) / 1e6
|
|
187
|
+
//走一圈: 每個節點字串已清除, 第n步回到起點
|
|
188
|
+
let v = r
|
|
189
|
+
let ok = true
|
|
190
|
+
for (let i = 0; i < n; i++) {
|
|
191
|
+
ok = ok && v.i === i && v.s === fx
|
|
192
|
+
v = v.next
|
|
193
|
+
}
|
|
194
|
+
out.cleaned = ok
|
|
195
|
+
out.closed = v === r
|
|
196
|
+
out.inputIntact = head.s === x && cur.next === head
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
throw new Error('unknown case: ' + caseName)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
console.log('@@R@@' + JSON.stringify(out))
|