@design-edito/tools 0.4.5 → 0.4.11
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/TODO.md +269 -0
- package/agnostic/arrays/dedupe/index.js +9 -7
- package/agnostic/arrays/dedupe/index.test.js +24 -0
- package/agnostic/arrays/find-duplicates/index.js +34 -22
- package/agnostic/arrays/find-duplicates/index.test.js +31 -0
- package/agnostic/arrays/index.d.ts +2 -2
- package/agnostic/arrays/index.js +2 -2
- package/agnostic/arrays/is-array-of/index.js +28 -26
- package/agnostic/arrays/is-array-of/index.test.js +56 -0
- package/agnostic/arrays/make/index.d.ts +1 -1
- package/agnostic/arrays/make/index.js +11 -6
- package/agnostic/arrays/make/index.test.js +10 -0
- package/agnostic/arrays/random-pick/index.js +38 -22
- package/agnostic/arrays/random-pick/index.test.js +23 -0
- package/agnostic/arrays/shuffle/index.js +15 -11
- package/agnostic/arrays/shuffle/index.test.js +14 -0
- package/agnostic/booleans/is-falsy/index.js +24 -15
- package/agnostic/booleans/is-falsy/index.test.js +26 -0
- package/agnostic/colors/channels/index.js +139 -936
- package/agnostic/colors/channels/index.test.js +64 -0
- package/agnostic/colors/contrast/index.js +24 -643
- package/agnostic/colors/contrast/index.test.js +21 -0
- package/agnostic/colors/convert/index.js +811 -837
- package/agnostic/colors/convert/index.test.js +98 -0
- package/agnostic/colors/cssColorsMap.js +153 -0
- package/agnostic/colors/distance/index.js +66 -538
- package/agnostic/colors/distance/index.test.js +21 -0
- package/agnostic/colors/grayscale/index.js +95 -872
- package/agnostic/colors/grayscale/index.test.js +34 -0
- package/agnostic/colors/index.d.ts +4 -4
- package/agnostic/colors/index.js +4 -4
- package/agnostic/colors/invert/index.js +34 -719
- package/agnostic/colors/invert/index.test.js +31 -0
- package/agnostic/colors/lerp/index.js +75 -804
- package/agnostic/colors/lerp/index.test.js +55 -0
- package/agnostic/colors/luminance/index.js +17 -625
- package/agnostic/colors/luminance/index.test.js +30 -0
- package/agnostic/colors/palette/index.js +83 -917
- package/agnostic/colors/palette/index.test.js +35 -0
- package/agnostic/colors/rotate/index.js +35 -835
- package/agnostic/colors/rotate/index.test.js +45 -0
- package/agnostic/colors/tidy/index.js +79 -530
- package/agnostic/colors/tidy/index.test.js +45 -0
- package/agnostic/colors/typechecks/index.js +188 -250
- package/agnostic/colors/typechecks/index.test.js +113 -0
- package/agnostic/colors/types.js +1 -0
- package/agnostic/css/bem/index.js +134 -171
- package/agnostic/css/clss/index.js +64 -29
- package/agnostic/css/clss/index.test.js +60 -0
- package/agnostic/css/generate-nice-color/index.js +26 -71
- package/agnostic/css/generate-nice-color/index.test.js +8 -0
- package/agnostic/css/index.d.ts +2 -2
- package/agnostic/css/index.js +2 -2
- package/agnostic/css/is-valid-css-class-name/index.js +14 -8
- package/agnostic/css/is-valid-css-class-name/index.test.js +36 -0
- package/agnostic/css/scale/index.d.ts +46 -16
- package/agnostic/css/scale/index.js +70 -54
- package/agnostic/css/scale/index.test.js +88 -0
- package/agnostic/css/styles-set/index.js +151 -178
- package/agnostic/errors/index.d.ts +1 -1
- package/agnostic/errors/index.js +1 -1
- package/agnostic/errors/register/index.js +45 -49
- package/agnostic/errors/unknown-to-string/index.js +17 -10
- package/agnostic/errors/unknown-to-string/index.test.js +35 -0
- package/agnostic/html/get-node-ancestors/index.js +29 -29
- package/agnostic/html/get-node-ancestors/index.test.js +58 -0
- package/agnostic/html/get-position-inside-parent/index.js +13 -8
- package/agnostic/html/get-position-inside-parent/index.test.js +56 -0
- package/agnostic/html/hyper-json/cast/index.js +128 -2931
- package/agnostic/html/hyper-json/index.js +23 -2954
- package/agnostic/html/hyper-json/method/index.js +10 -14
- package/agnostic/html/hyper-json/serialize/index.js +88 -222
- package/agnostic/html/hyper-json/smart-tags/coalesced/add/index.js +14 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/addclass/index.js +27 -2937
- package/agnostic/html/hyper-json/smart-tags/coalesced/and/index.js +13 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/append/index.js +34 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/at/index.js +42 -2935
- package/agnostic/html/hyper-json/smart-tags/coalesced/call/index.js +47 -2937
- package/agnostic/html/hyper-json/smart-tags/coalesced/clone/index.js +10 -2939
- package/agnostic/html/hyper-json/smart-tags/coalesced/deleteproperties/index.js +45 -2936
- package/agnostic/html/hyper-json/smart-tags/coalesced/equals/index.js +22 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/getattribute/index.js +26 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/getproperties/index.js +19 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/getproperty/index.js +67 -2935
- package/agnostic/html/hyper-json/smart-tags/coalesced/hjparse/index.js +21 -2937
- package/agnostic/html/hyper-json/smart-tags/coalesced/hjstringify/index.js +89 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/if/index.js +20 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/index.d.ts +11 -11
- package/agnostic/html/hyper-json/smart-tags/coalesced/index.js +11 -11
- package/agnostic/html/hyper-json/smart-tags/coalesced/initialize/index.js +37 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/join/index.js +16 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/length/index.js +21 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/map/index.js +31 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/negate/index.js +10 -2939
- package/agnostic/html/hyper-json/smart-tags/coalesced/notrailing/index.js +33 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/or/index.js +13 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/pickrandom/index.js +17 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/populate/index.js +59 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/print/index.js +23 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/push/index.js +10 -2939
- package/agnostic/html/hyper-json/smart-tags/coalesced/pusheach/index.js +26 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/recordtoarray/index.js +10 -2939
- package/agnostic/html/hyper-json/smart-tags/coalesced/removeattribute/index.js +53 -2935
- package/agnostic/html/hyper-json/smart-tags/coalesced/removeclass/index.js +27 -2937
- package/agnostic/html/hyper-json/smart-tags/coalesced/renameproperty/index.js +31 -2937
- package/agnostic/html/hyper-json/smart-tags/coalesced/replace/index.js +55 -2940
- package/agnostic/html/hyper-json/smart-tags/coalesced/select/index.js +29 -2935
- package/agnostic/html/hyper-json/smart-tags/coalesced/set/index.js +29 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/setattribute/index.js +53 -2935
- package/agnostic/html/hyper-json/smart-tags/coalesced/setproperty/index.js +232 -2936
- package/agnostic/html/hyper-json/smart-tags/coalesced/sorton/index.js +89 -2936
- package/agnostic/html/hyper-json/smart-tags/coalesced/split/index.js +20 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/spread/index.js +23 -2939
- package/agnostic/html/hyper-json/smart-tags/coalesced/toarray/index.js +11 -2939
- package/agnostic/html/hyper-json/smart-tags/coalesced/toboolean/index.js +11 -2939
- package/agnostic/html/hyper-json/smart-tags/coalesced/toelement/index.js +17 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/toggleclass/index.js +27 -2937
- package/agnostic/html/hyper-json/smart-tags/coalesced/tonodelist/index.js +11 -2939
- package/agnostic/html/hyper-json/smart-tags/coalesced/tonull/index.js +10 -2939
- package/agnostic/html/hyper-json/smart-tags/coalesced/tonumber/index.js +11 -2939
- package/agnostic/html/hyper-json/smart-tags/coalesced/torecord/index.js +11 -2939
- package/agnostic/html/hyper-json/smart-tags/coalesced/toref/index.js +11 -2939
- package/agnostic/html/hyper-json/smart-tags/coalesced/tostring/index.js +11 -2939
- package/agnostic/html/hyper-json/smart-tags/coalesced/totext/index.js +11 -2939
- package/agnostic/html/hyper-json/smart-tags/coalesced/transformselected/index.js +84 -2938
- package/agnostic/html/hyper-json/smart-tags/coalesced/trim/index.js +14 -2938
- package/agnostic/html/hyper-json/smart-tags/index.js +28 -181
- package/agnostic/html/hyper-json/smart-tags/isolated/any/index.js +12 -195
- package/agnostic/html/hyper-json/smart-tags/isolated/array/index.js +12 -195
- package/agnostic/html/hyper-json/smart-tags/isolated/boolean/index.js +12 -2939
- package/agnostic/html/hyper-json/smart-tags/isolated/element/index.js +24 -2938
- package/agnostic/html/hyper-json/smart-tags/isolated/get/index.js +18 -2938
- package/agnostic/html/hyper-json/smart-tags/isolated/guess/index.js +56 -2937
- package/agnostic/html/hyper-json/smart-tags/isolated/index.d.ts +2 -2
- package/agnostic/html/hyper-json/smart-tags/isolated/index.js +2 -2
- package/agnostic/html/hyper-json/smart-tags/isolated/nodelist/index.js +18 -2938
- package/agnostic/html/hyper-json/smart-tags/isolated/null/index.js +9 -193
- package/agnostic/html/hyper-json/smart-tags/isolated/number/index.js +16 -2938
- package/agnostic/html/hyper-json/smart-tags/isolated/record/index.js +12 -2938
- package/agnostic/html/hyper-json/smart-tags/isolated/ref/index.js +40 -2935
- package/agnostic/html/hyper-json/smart-tags/isolated/string/index.js +16 -2938
- package/agnostic/html/hyper-json/smart-tags/isolated/text/index.js +18 -2938
- package/agnostic/html/hyper-json/transformer/index.js +112 -148
- package/agnostic/html/hyper-json/tree/index.js +411 -2928
- package/agnostic/html/hyper-json/types/index.js +27 -18
- package/agnostic/html/hyper-json/utils/index.js +497 -2921
- package/agnostic/html/index.d.ts +2 -2
- package/agnostic/html/index.js +2 -2
- package/agnostic/html/insert-node/index.js +27 -16
- package/agnostic/html/insert-node/index.test.js +73 -0
- package/agnostic/html/placeholders/index.js +26 -29
- package/agnostic/html/replace-in-element/index.js +31 -48
- package/agnostic/html/replace-in-element/index.test.js +80 -0
- package/agnostic/html/selector-to-element/index.js +53 -39
- package/agnostic/html/selector-to-element/index.test.js +69 -0
- package/agnostic/html/string-to-nodes/index.js +24 -25
- package/agnostic/html/string-to-nodes/index.test.js +54 -0
- package/agnostic/index.d.ts +4 -4
- package/agnostic/index.js +4 -4
- package/agnostic/misc/assert/index.js +60 -66
- package/agnostic/misc/cast/index.js +123 -57
- package/agnostic/misc/cast/index.test.js +134 -0
- package/agnostic/misc/connection/index.js +55 -36
- package/agnostic/misc/connection/index.test.js +143 -0
- package/agnostic/misc/crawler/index.js +68 -46
- package/agnostic/misc/crawler/index.test.js +56 -0
- package/agnostic/misc/crossenv/detect-runtime/index.js +41 -13
- package/agnostic/misc/crossenv/detect-runtime/index.test.js +24 -0
- package/agnostic/misc/crossenv/types.js +21 -14
- package/agnostic/misc/crossenv/window/index.js +45 -24
- package/agnostic/misc/crossenv/window/index.test.js +24 -0
- package/agnostic/misc/data-size/index.js +182 -294
- package/agnostic/misc/data-size/index.test.js +100 -0
- package/agnostic/misc/data-size/types.js +1 -0
- package/agnostic/misc/index.d.ts +5 -5
- package/agnostic/misc/index.js +5 -5
- package/agnostic/misc/is-constructor-function/index.js +12 -6
- package/agnostic/misc/is-constructor-function/index.test.js +36 -0
- package/agnostic/misc/is-nullish/index.js +24 -11
- package/agnostic/misc/is-nullish/index.test.js +44 -0
- package/agnostic/misc/logs/index.d.ts +1 -1
- package/agnostic/misc/logs/index.js +1 -1
- package/agnostic/misc/logs/logger/index.js +115 -140
- package/agnostic/misc/logs/make-text-block/index.js +13 -13
- package/agnostic/misc/logs/styles/index.js +29 -48
- package/agnostic/misc/lorem-ipsum/index.js +51 -201
- package/agnostic/misc/lorem-ipsum/index.test.js +49 -0
- package/agnostic/misc/normalize-extension/index.js +99 -88
- package/agnostic/misc/normalize-extension/index.test.js +40 -0
- package/agnostic/misc/outcome/index.js +20 -14
- package/agnostic/misc/outcome/index.test.js +40 -0
- package/agnostic/numbers/absolute-modulo/index.js +9 -6
- package/agnostic/numbers/absolute-modulo/index.test.js +23 -0
- package/agnostic/numbers/approximate-rational/index.js +86 -69
- package/agnostic/numbers/approximate-rational/index.test.js +90 -0
- package/agnostic/numbers/clamp/index.js +12 -8
- package/agnostic/numbers/clamp/index.test.js +24 -0
- package/agnostic/numbers/geometric-progressions/index.js +25 -16
- package/agnostic/numbers/geometric-progressions/index.test.js +45 -0
- package/agnostic/numbers/index.d.ts +2 -2
- package/agnostic/numbers/index.js +2 -2
- package/agnostic/numbers/interpolate/index.js +25 -10
- package/agnostic/numbers/interpolate/index.test.js +40 -0
- package/agnostic/numbers/round/index.js +30 -15
- package/agnostic/numbers/round/index.test.js +56 -0
- package/agnostic/objects/deep-get-property/index.js +30 -27
- package/agnostic/objects/deep-get-property/index.test.js +59 -0
- package/agnostic/objects/enums/is-in-enum/index.js +17 -11
- package/agnostic/objects/enums/is-in-enum/index.test.js +100 -0
- package/agnostic/objects/flatten-getters/index.js +15 -14
- package/agnostic/objects/flatten-getters/index.test.js +78 -0
- package/agnostic/objects/index.d.ts +4 -4
- package/agnostic/objects/index.js +4 -4
- package/agnostic/objects/is-object/index.js +16 -9
- package/agnostic/objects/is-object/index.test.js +60 -0
- package/agnostic/objects/is-record/index.js +12 -7
- package/agnostic/objects/is-record/index.test.js +48 -0
- package/agnostic/objects/record-format/index.js +18 -12
- package/agnostic/objects/record-format/index.test.js +92 -0
- package/agnostic/objects/record-map/index.js +16 -11
- package/agnostic/objects/record-map/index.test.js +56 -0
- package/agnostic/objects/sort-keys/index.js +15 -11
- package/agnostic/objects/sort-keys/index.test.js +37 -0
- package/agnostic/objects/validation/index.js +21 -8
- package/agnostic/objects/validation/index.test.js +72 -0
- package/agnostic/optim/memoize/index.js +24 -16
- package/agnostic/optim/memoize/index.test.js +30 -0
- package/agnostic/optim/throttle-debounce/index.js +120 -102
- package/agnostic/optim/throttle-debounce/index.test.js +44 -0
- package/agnostic/optim/throttle-debounce/types.js +1 -0
- package/agnostic/random/hex-char/index.js +8 -10
- package/agnostic/random/hex-char/index.test.js +20 -0
- package/agnostic/random/index.d.ts +1 -1
- package/agnostic/random/index.js +1 -1
- package/agnostic/random/random/index.js +17 -14
- package/agnostic/random/random/index.test.js +73 -0
- package/agnostic/random/uuid/index.js +28 -20
- package/agnostic/random/uuid/index.test.js +45 -0
- package/agnostic/regexps/index.js +126 -84
- package/agnostic/regexps/index.test.js +108 -0
- package/agnostic/sanitization/file-name/index.js +24 -8
- package/agnostic/sanitization/file-name/index.test.js +23 -0
- package/agnostic/sanitization/html/index.js +172 -122
- package/agnostic/sanitization/index.d.ts +1 -1
- package/agnostic/sanitization/index.js +1 -1
- package/agnostic/sanitization/path/index.js +23 -15
- package/agnostic/sanitization/path/index.test.js +18 -0
- package/agnostic/sanitization/types.js +1 -0
- package/agnostic/sanitization/user-input/index.js +36 -24
- package/agnostic/sanitization/user-input/index.test.js +31 -0
- package/agnostic/strings/char-codes/index.js +123 -55
- package/agnostic/strings/index.d.ts +1 -1
- package/agnostic/strings/index.js +1 -1
- package/agnostic/strings/matches/index.js +35 -16
- package/agnostic/strings/normalize-indent/index.js +34 -16
- package/agnostic/strings/parse-table/index.js +153 -86
- package/agnostic/strings/replace-all/index.js +36 -15
- package/agnostic/strings/to-alphanum/index.js +23 -8
- package/agnostic/strings/trim/index.js +22 -9
- package/agnostic/time/dates/format-date/index.js +140 -72
- package/agnostic/time/duration/index.js +106 -140
- package/agnostic/time/timeout/index.js +24 -16
- package/agnostic/time/transitions/index.js +200 -158
- package/agnostic/time/wait/index.js +10 -8
- package/agnostic/typescript/types.js +1 -0
- package/components/BeforeAfter/index.controlled.js +95 -0
- package/components/BeforeAfter/index.js +54 -189
- package/components/BeforeAfter/utils.js +9 -0
- package/components/Disclaimer/index.js +50 -110
- package/components/Drawer/index.js +81 -196
- package/components/EventListener/index.js +29 -80
- package/components/Gallery/index.js +146 -221
- package/components/Gallery/utils.js +12 -0
- package/components/Image/index.js +66 -293
- package/components/IntersectionObserver/index.js +62 -110
- package/components/Overlayer/index.js +59 -103
- package/components/Paginator/index.js +124 -155
- package/components/ResizeObserver/index.js +66 -119
- package/components/ResizeObserver/style.module.css +0 -0
- package/components/Scrllgngn/index.js +171 -468
- package/components/ScrollListener/index.js +97 -276
- package/components/ScrollListener/utils.js +51 -0
- package/components/Sequencer/index.controlled.js +67 -0
- package/components/Sequencer/index.js +105 -262
- package/components/ShadowRoot/index.js +42 -96
- package/components/Subtitles/index.js +107 -244
- package/components/Subtitles/types.js +1 -0
- package/components/Subtitles/utils.js +102 -0
- package/components/Theatre/index.js +88 -136
- package/components/UIModule/index.js +156 -199
- package/components/Video/index.js +292 -857
- package/components/Video/utils.js +137 -0
- package/components/_WIP_AudioQuote/index.js +1 -0
- package/components/_WIP_Icon/index.js +1 -0
- package/components/index.d.ts +4 -4
- package/components/index.js +4 -4
- package/components/public-classnames.js +18 -0
- package/components/utils/index.js +11 -11
- package/components/utils/types.js +1 -0
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/node/@aws-s3/index.test.js +6 -0
- package/node/@aws-s3/storage/directory/copy-dir/index.js +66 -72
- package/node/@aws-s3/storage/directory/index.d.ts +1 -1
- package/node/@aws-s3/storage/directory/index.js +1 -1
- package/node/@aws-s3/storage/directory/list/index.js +32 -42
- package/node/@aws-s3/storage/directory/move-dir/index.js +68 -86
- package/node/@aws-s3/storage/directory/remove-dir/index.js +56 -67
- package/node/@aws-s3/storage/file/copy/index.js +41 -53
- package/node/@aws-s3/storage/file/download/index.js +29 -40
- package/node/@aws-s3/storage/file/exists/index.js +35 -43
- package/node/@aws-s3/storage/file/index.d.ts +1 -1
- package/node/@aws-s3/storage/file/index.js +1 -1
- package/node/@aws-s3/storage/file/move/index.js +57 -63
- package/node/@aws-s3/storage/file/remove/index.js +35 -43
- package/node/@aws-s3/storage/file/stat/index.js +33 -47
- package/node/@aws-s3/storage/file/upload/index.js +52 -63
- package/node/@design-edito/index.js +1 -0
- package/node/@express/@multer/index.js +61 -55
- package/node/@google-cloud/storage/bucket/get-metadata/index.js +25 -29
- package/node/@google-cloud/storage/directory/copy-dir/index.js +35 -41
- package/node/@google-cloud/storage/directory/index.d.ts +1 -1
- package/node/@google-cloud/storage/directory/index.js +1 -1
- package/node/@google-cloud/storage/directory/list/index.js +28 -35
- package/node/@google-cloud/storage/directory/move-dir/index.js +43 -42
- package/node/@google-cloud/storage/directory/remove-dir/index.js +34 -38
- package/node/@google-cloud/storage/file/copy/index.js +35 -40
- package/node/@google-cloud/storage/file/download/index.js +27 -34
- package/node/@google-cloud/storage/file/exists/index.js +25 -31
- package/node/@google-cloud/storage/file/generate-signed-url/index.js +33 -35
- package/node/@google-cloud/storage/file/get-metadata/index.js +28 -31
- package/node/@google-cloud/storage/file/get-permissions/index.js +25 -31
- package/node/@google-cloud/storage/file/index.d.ts +3 -3
- package/node/@google-cloud/storage/file/index.js +3 -3
- package/node/@google-cloud/storage/file/move/index.js +38 -42
- package/node/@google-cloud/storage/file/remove/index.js +34 -35
- package/node/@google-cloud/storage/file/revoke-signed-urls/index.js +32 -95
- package/node/@google-cloud/storage/file/stat/index.js +34 -38
- package/node/@google-cloud/storage/file/update-metadata/index.js +30 -31
- package/node/@google-cloud/storage/file/upload/index.js +44 -46
- package/node/@google-cloud/storage/index.d.ts +1 -1
- package/node/@google-cloud/storage/index.js +1 -1
- package/node/cloud-storage/clients/index.js +35 -15
- package/node/cloud-storage/operations/copy-dir/index.js +30 -203
- package/node/cloud-storage/operations/copy-file/index.js +30 -152
- package/node/cloud-storage/operations/download-file/index.js +30 -103
- package/node/cloud-storage/operations/exists-file/index.js +30 -103
- package/node/cloud-storage/operations/index.d.ts +2 -2
- package/node/cloud-storage/operations/index.js +2 -2
- package/node/cloud-storage/operations/list-dir/index.js +29 -98
- package/node/cloud-storage/operations/move-dir/index.js +30 -169
- package/node/cloud-storage/operations/move-file/index.js +30 -157
- package/node/cloud-storage/operations/remove-dir/index.js +29 -159
- package/node/cloud-storage/operations/remove-file/index.js +29 -121
- package/node/cloud-storage/operations/stat-file/index.js +29 -124
- package/node/cloud-storage/operations/upload-file/index.js +30 -162
- package/node/encryption/@aes-256-gcm/buffer/index.js +31 -72
- package/node/encryption/@aes-256-gcm/uint8-array/index.js +55 -55
- package/node/encryption/key/index.js +19 -12
- package/node/files/index.d.ts +1 -1
- package/node/files/index.js +1 -1
- package/node/files/is-in-directory/index.js +11 -8
- package/node/files/read-write/index.js +11 -15
- package/node/files/subpaths/index.js +156 -121
- package/node/ftps/directory/copy-dir/index.js +55 -62
- package/node/ftps/directory/list/index.js +24 -29
- package/node/ftps/directory/move-dir/index.js +38 -38
- package/node/ftps/directory/remove-dir/index.js +39 -42
- package/node/ftps/file/copy/index.js +42 -47
- package/node/ftps/file/download/index.js +29 -34
- package/node/ftps/file/exists/index.js +38 -36
- package/node/ftps/file/index.d.ts +2 -2
- package/node/ftps/file/index.js +2 -2
- package/node/ftps/file/move/index.js +46 -44
- package/node/ftps/file/remove/index.js +36 -39
- package/node/ftps/file/stat/index.js +30 -38
- package/node/ftps/file/upload/index.js +40 -44
- package/node/images/create/index.js +10 -562
- package/node/images/format/index.js +264 -815
- package/node/images/metadata/index.js +10 -571
- package/node/images/transform/index.js +169 -1022
- package/node/images/transform/operations/blur/index.js +11 -24
- package/node/images/transform/operations/brighten/index.js +11 -24
- package/node/images/transform/operations/extend/index.js +25 -589
- package/node/images/transform/operations/extract/index.js +15 -28
- package/node/images/transform/operations/flatten/index.js +20 -584
- package/node/images/transform/operations/flip/index.js +2 -6
- package/node/images/transform/operations/flop/index.js +2 -6
- package/node/images/transform/operations/hue/index.js +13 -26
- package/node/images/transform/operations/index.d.ts +3 -3
- package/node/images/transform/operations/index.js +3 -3
- package/node/images/transform/operations/level/index.js +14 -30
- package/node/images/transform/operations/lighten/index.js +13 -26
- package/node/images/transform/operations/normalize/index.js +14 -27
- package/node/images/transform/operations/overlay/index.js +89 -673
- package/node/images/transform/operations/resize/index.js +46 -610
- package/node/images/transform/operations/rotate/index.js +20 -584
- package/node/images/transform/operations/saturate/index.js +14 -27
- package/node/images/types.js +34 -31
- package/node/images/utils/index.js +84 -568
- package/node/index.d.ts +2 -2
- package/node/index.js +2 -2
- package/node/process/on-exit/index.js +45 -26
- package/node/process/prompt-continue/index.js +29 -14
- package/node/process/spawner/index.js +104 -134
- package/node/sftp/directory/copy-dir/index.js +52 -60
- package/node/sftp/directory/index.d.ts +1 -1
- package/node/sftp/directory/index.js +1 -1
- package/node/sftp/directory/list/index.js +22 -29
- package/node/sftp/directory/move-dir/index.js +35 -35
- package/node/sftp/directory/remove-dir/index.js +39 -42
- package/node/sftp/file/copy/index.js +37 -45
- package/node/sftp/file/download/index.js +26 -32
- package/node/sftp/file/exists/index.js +29 -29
- package/node/sftp/file/index.d.ts +2 -2
- package/node/sftp/file/index.js +2 -2
- package/node/sftp/file/move/index.js +39 -38
- package/node/sftp/file/remove/index.js +31 -34
- package/node/sftp/file/stat/index.js +26 -37
- package/node/sftp/file/upload/index.js +34 -38
- package/package.json +1 -1
|
@@ -1,127 +1,177 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import * as Window from '../../misc/crossenv/window/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Default sanitization options.
|
|
4
|
+
*
|
|
5
|
+
* Only sets a default recursion depth of 20.
|
|
6
|
+
*/
|
|
7
|
+
export const defaultOptions = { depth: 20 };
|
|
8
|
+
/**
|
|
9
|
+
* Sanitizes an HTML string according to the provided options.
|
|
10
|
+
*
|
|
11
|
+
* @deprecated
|
|
12
|
+
* @security
|
|
13
|
+
* ⚠️ SECURITY WARNING
|
|
14
|
+
* This function is **not a hardened or complete HTML sanitizer**.
|
|
15
|
+
* It does not guarantee protection against XSS or other injection attacks.
|
|
16
|
+
*
|
|
17
|
+
* Correctness and safety depend entirely on strict caller configuration.
|
|
18
|
+
* In particular, unsafe usage may occur if:
|
|
19
|
+
* - Wildcards (`'*'`) are used for allowed tags or attributes
|
|
20
|
+
* - URL-based attributes (`href`, `src`, `xlink:href`, etc.) are insufficiently constrained
|
|
21
|
+
* - Event handler attributes (`on*`) are not explicitly forbidden
|
|
22
|
+
* - SVG or MathML content is allowed
|
|
23
|
+
*
|
|
24
|
+
* This API must not be used as a security boundary for untrusted HTML.
|
|
25
|
+
* For security-critical sanitization, use a dedicated, security-audited library.
|
|
26
|
+
*
|
|
27
|
+
* @param {string} inputStr - The HTML string to sanitize.
|
|
28
|
+
* @param {SanitizeHtmlOptions} [options=defaultOptions] - Sanitization configuration.
|
|
29
|
+
* @returns {string} The sanitized HTML string.
|
|
30
|
+
*
|
|
31
|
+
* @throws Will throw an error if no document object is available for creating elements.
|
|
32
|
+
*/
|
|
33
|
+
export function sanitizeHtml(inputStr, options = defaultOptions) {
|
|
34
|
+
const { document } = Window.get();
|
|
35
|
+
const wrapperDiv = document.createElement('div');
|
|
36
|
+
const { inputFreeTransform } = options;
|
|
37
|
+
wrapperDiv.innerHTML = inputFreeTransform !== undefined ? inputFreeTransform(inputStr) : inputStr;
|
|
38
|
+
const sanitizedWrapper = sanitizeElement(wrapperDiv, options);
|
|
39
|
+
const returned = sanitizedWrapper?.innerHTML;
|
|
40
|
+
return returned ?? '';
|
|
4
41
|
}
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Recursively sanitizes a DOM element and its descendants according to the provided options.
|
|
44
|
+
*
|
|
45
|
+
* @deprecated
|
|
46
|
+
* @security
|
|
47
|
+
* ⚠️ SECURITY WARNING
|
|
48
|
+
* This function is **not a hardened or complete HTML sanitizer**.
|
|
49
|
+
* It does not guarantee protection against XSS or other injection attacks.
|
|
50
|
+
*
|
|
51
|
+
* Correctness and safety depend entirely on strict caller configuration.
|
|
52
|
+
* In particular, unsafe usage may occur if:
|
|
53
|
+
* - Wildcards (`'*'`) are used for allowed tags or attributes
|
|
54
|
+
* - URL-based attributes (`href`, `src`, `xlink:href`, etc.) are insufficiently constrained
|
|
55
|
+
* - Event handler attributes (`on*`) are not explicitly forbidden
|
|
56
|
+
* - SVG or MathML content is allowed
|
|
57
|
+
*
|
|
58
|
+
* This API must not be used as a security boundary for untrusted HTML.
|
|
59
|
+
* For security-critical sanitization, use a dedicated, security-audited library.
|
|
60
|
+
*
|
|
61
|
+
* @param {Element} element - The DOM element to sanitize.
|
|
62
|
+
* @param {SanitizeHtmlOptions} [options=defaultOptions] - Sanitization configuration.
|
|
63
|
+
* @returns {Element | null}
|
|
64
|
+
* - A sanitized clone of the original element with allowed attributes and children.
|
|
65
|
+
* - `null` if the element is forbidden or maximum recursion depth is reached.
|
|
66
|
+
*
|
|
67
|
+
* @throws Will throw an error if no document object is available for creating elements.
|
|
68
|
+
*/
|
|
69
|
+
export function sanitizeElement(element, options = defaultOptions) {
|
|
70
|
+
const { tagName, attributes, childNodes } = element;
|
|
71
|
+
const { allowedTags = [], allowedAttributes = {}, forbiddenTags = [], forbiddenAttributes = {}, depth = 20, verbose = false } = options;
|
|
72
|
+
if (depth <= 0) {
|
|
73
|
+
console.warn('Max depth reached');
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
// Element's tag name checkup
|
|
77
|
+
const normalizedTagName = tagName.toLowerCase().trim();
|
|
78
|
+
const tagIsInForbidden = forbiddenTags.includes('*') || forbiddenTags.includes(normalizedTagName);
|
|
79
|
+
if (tagIsInForbidden) {
|
|
80
|
+
if (verbose)
|
|
81
|
+
console.warn(tagName, 'tag is forbidden');
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
const tagIsInAllowed = allowedTags.includes('*') || allowedTags.includes(normalizedTagName);
|
|
85
|
+
if (!tagIsInAllowed) {
|
|
86
|
+
if (verbose)
|
|
87
|
+
console.warn(tagName, 'tag is not allowed');
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const returnedElement = Window.get().document.createElement(tagName);
|
|
91
|
+
// Element's attributes checkup
|
|
92
|
+
const returnedAttributes = Array.from(attributes).filter(({ name: attributeName, value: attributeValue }) => {
|
|
93
|
+
const allTagsForbiddenAttributes = forbiddenAttributes['*'] ?? [];
|
|
94
|
+
const thisTagForbiddenAttributes = forbiddenAttributes[normalizedTagName] ?? [];
|
|
95
|
+
const mergedForbiddenAttributes = [...allTagsForbiddenAttributes, ...thisTagForbiddenAttributes];
|
|
96
|
+
const isInForbidden = mergedForbiddenAttributes.some(({ attributeName: nameTester, attributeValues: valTesters }) => {
|
|
97
|
+
if (typeof nameTester === 'string' && nameTester !== '*' && attributeName !== nameTester)
|
|
98
|
+
return false; // attribute name doesnt match
|
|
99
|
+
if (typeof nameTester !== 'string' && !nameTester.test(attributeName))
|
|
100
|
+
return false; // attribute name doesnt match
|
|
101
|
+
if (valTesters === undefined) {
|
|
102
|
+
if (verbose)
|
|
103
|
+
console.warn(attributeName, 'attribute on', tagName, 'tag is forbidden');
|
|
104
|
+
return true; // attribute name matches, and all values are forbidden
|
|
105
|
+
}
|
|
106
|
+
if (valTesters.includes('*')) {
|
|
107
|
+
if (verbose)
|
|
108
|
+
console.warn(attributeName, 'attribute on', tagName, 'tag is forbidden');
|
|
109
|
+
return true; // attribute name matches, and all values are EXPLICITLY forbidden
|
|
110
|
+
}
|
|
111
|
+
return valTesters.some(valTester => {
|
|
112
|
+
if (typeof valTester === 'string' && attributeValue === valTester) {
|
|
113
|
+
if (verbose)
|
|
114
|
+
console.warn(attributeValue, 'value for', attributeName, 'attribute on', tagName, 'tag is forbidden. Rule:', valTester);
|
|
115
|
+
return true; // attribute value strictly matches
|
|
116
|
+
}
|
|
117
|
+
if (typeof valTester !== 'string' && valTester.test(attributeValue)) {
|
|
118
|
+
if (verbose)
|
|
119
|
+
console.warn(attributeValue, 'value for', attributeName, 'attribute on', tagName, 'tag is forbidden. Rule:', valTester);
|
|
120
|
+
return true; // attribute value partially matches
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
if (isInForbidden)
|
|
126
|
+
return false;
|
|
127
|
+
const allTagsAllowedAttributes = allowedAttributes['*'] ?? [];
|
|
128
|
+
const thisTagAllowedAttributes = allowedAttributes[normalizedTagName] ?? [];
|
|
129
|
+
const mergedAllowedAttributes = [...allTagsAllowedAttributes, ...thisTagAllowedAttributes];
|
|
130
|
+
let latestNotAllowedReason = [tagName, 'has no allowed attributes'];
|
|
131
|
+
const isInAllowed = mergedAllowedAttributes.some(({ attributeName: nameTester, attributeValues: valTesters }) => {
|
|
132
|
+
if (typeof nameTester === 'string' && nameTester !== '*' && attributeName !== nameTester) {
|
|
133
|
+
latestNotAllowedReason = [attributeName, 'attribute on', tagName, 'tag is not allowed'];
|
|
134
|
+
return false; // attribute name doesnt match
|
|
135
|
+
}
|
|
136
|
+
if (typeof nameTester !== 'string' && !nameTester.test(attributeName)) {
|
|
137
|
+
latestNotAllowedReason = [attributeName, 'attribute on', tagName, 'tag is not allowed'];
|
|
138
|
+
return false; // attribute name doesnt match
|
|
139
|
+
}
|
|
140
|
+
if (valTesters === undefined)
|
|
141
|
+
return true; // attribute name matches, and all values are allowed
|
|
142
|
+
if (valTesters.includes('*'))
|
|
143
|
+
return true; // attribute name matches, and all values are EXPLICITLY allowed
|
|
144
|
+
return valTesters.some(valTester => {
|
|
145
|
+
if (typeof valTester === 'string' && attributeValue === valTester)
|
|
146
|
+
return true; // attribute value strictly matches
|
|
147
|
+
if (typeof valTester !== 'string' && valTester.test(attributeValue))
|
|
148
|
+
return true; // attribute value partially matches
|
|
149
|
+
latestNotAllowedReason = [attributeValue, 'value for', attributeName, 'attribute on', tagName, 'tag is not allowed'];
|
|
150
|
+
return false;
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
if (!isInAllowed) {
|
|
154
|
+
if (verbose)
|
|
155
|
+
console.warn(...latestNotAllowedReason);
|
|
156
|
+
return false;
|
|
75
157
|
}
|
|
76
|
-
return
|
|
77
|
-
});
|
|
158
|
+
return true;
|
|
78
159
|
});
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const thisTagAllowedAttributes = allowedAttributes[normalizedTagName] ?? [];
|
|
82
|
-
const mergedAllowedAttributes = [...allTagsAllowedAttributes, ...thisTagAllowedAttributes];
|
|
83
|
-
let latestNotAllowedReason = [tagName, "has no allowed attributes"];
|
|
84
|
-
const isInAllowed = mergedAllowedAttributes.some(({
|
|
85
|
-
attributeName: nameTester,
|
|
86
|
-
attributeValues: valTesters
|
|
87
|
-
}) => {
|
|
88
|
-
if (typeof nameTester === "string" && nameTester !== "*" && attributeName !== nameTester) {
|
|
89
|
-
latestNotAllowedReason = [attributeName, "attribute on", tagName, "tag is not allowed"];
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
if (typeof nameTester !== "string" && !nameTester.test(attributeName)) {
|
|
93
|
-
latestNotAllowedReason = [attributeName, "attribute on", tagName, "tag is not allowed"];
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
if (valTesters === void 0) return true;
|
|
97
|
-
if (valTesters.includes("*")) return true;
|
|
98
|
-
return valTesters.some((valTester) => {
|
|
99
|
-
if (typeof valTester === "string" && attributeValue === valTester) return true;
|
|
100
|
-
if (typeof valTester !== "string" && valTester.test(attributeValue)) return true;
|
|
101
|
-
latestNotAllowedReason = [attributeValue, "value for", attributeName, "attribute on", tagName, "tag is not allowed"];
|
|
102
|
-
return false;
|
|
103
|
-
});
|
|
160
|
+
returnedAttributes.forEach(({ name, value }) => {
|
|
161
|
+
returnedElement.setAttribute(name, value);
|
|
104
162
|
});
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return
|
|
119
|
-
}).filter((elt) => elt !== null);
|
|
120
|
-
returnedElement.replaceChildren(...sanitizedChildNodes);
|
|
121
|
-
return returnedElement;
|
|
163
|
+
// Element's children sanitization
|
|
164
|
+
const sanitizedChildNodes = Array.from(childNodes)
|
|
165
|
+
.map((node) => {
|
|
166
|
+
if (node.nodeType === Node.ELEMENT_NODE)
|
|
167
|
+
return sanitizeElement(node, { ...options, depth: depth - 1 });
|
|
168
|
+
else if (node.nodeType === Node.TEXT_NODE)
|
|
169
|
+
return node;
|
|
170
|
+
else if (options.keepComments === true && node.nodeType === Node.COMMENT_NODE)
|
|
171
|
+
return node;
|
|
172
|
+
return null;
|
|
173
|
+
})
|
|
174
|
+
.filter((elt) => elt !== null);
|
|
175
|
+
returnedElement.replaceChildren(...sanitizedChildNodes);
|
|
176
|
+
return returnedElement;
|
|
122
177
|
}
|
|
123
|
-
export {
|
|
124
|
-
defaultOptions,
|
|
125
|
-
sanitizeElement,
|
|
126
|
-
sanitizeHtml
|
|
127
|
-
};
|
|
@@ -1,16 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { sanitizeFileName } from '../file-name/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Sanitizes a path string by sanitizing each path segment.
|
|
4
|
+
*
|
|
5
|
+
* - Removes empty segments and `..` segments to prevent path traversal.
|
|
6
|
+
* - Sanitizes each segment using `sanitizeFileName`.
|
|
7
|
+
* - Ensures the returned path starts with a `/`.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} targetPath - The path to sanitize.
|
|
10
|
+
* @returns {string | null} Sanitized absolute path, or null if invalid/empty.
|
|
11
|
+
*/
|
|
12
|
+
export function sanitizePath(targetPath) {
|
|
13
|
+
const sanitized = targetPath
|
|
14
|
+
.split('/')
|
|
15
|
+
.filter(chunk => chunk !== '')
|
|
16
|
+
.map(chunk => sanitizeFileName(chunk) ?? '')
|
|
17
|
+
.filter(chunk => chunk !== '' && chunk !== '..')
|
|
18
|
+
.join('/');
|
|
19
|
+
if (sanitized === '')
|
|
20
|
+
return null;
|
|
21
|
+
return sanitized.startsWith('/')
|
|
22
|
+
? sanitized
|
|
23
|
+
: `/${sanitized}`;
|
|
6
24
|
}
|
|
7
|
-
|
|
8
|
-
// src/agnostic/sanitization/path/index.ts
|
|
9
|
-
function sanitizePath(targetPath) {
|
|
10
|
-
const sanitized = targetPath.split("/").filter((chunk) => chunk !== "").map((chunk) => sanitizeFileName(chunk) ?? "").filter((chunk) => chunk !== "" && chunk !== "..").join("/");
|
|
11
|
-
if (sanitized === "") return null;
|
|
12
|
-
return sanitized.startsWith("/") ? sanitized : `/${sanitized}`;
|
|
13
|
-
}
|
|
14
|
-
export {
|
|
15
|
-
sanitizePath
|
|
16
|
-
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { sanitizePath } from './index.js';
|
|
3
|
+
describe('sanitizePath', () => {
|
|
4
|
+
it('sanitizes each segment and removes empty/.. segments', () => {
|
|
5
|
+
const input = '/some//../unsafe/..//path/ fi?le.txt';
|
|
6
|
+
const result = sanitizePath(input);
|
|
7
|
+
expect(result).toBe('/some/unsafe/path/file.txt');
|
|
8
|
+
});
|
|
9
|
+
it('returns null for an empty or fully-invalid path', () => {
|
|
10
|
+
expect(sanitizePath('')).toBeNull();
|
|
11
|
+
expect(sanitizePath('/../..///')).toBeNull();
|
|
12
|
+
});
|
|
13
|
+
it('ensures the returned path starts with a leading slash', () => {
|
|
14
|
+
const input = 'relative/path.txt';
|
|
15
|
+
const result = sanitizePath(input);
|
|
16
|
+
expect(result?.startsWith('/')).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,26 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
import xss from 'xss';
|
|
2
|
+
/**
|
|
3
|
+
* Recursively sanitizes user input to prevent XSS.
|
|
4
|
+
*
|
|
5
|
+
* - Strings are sanitized using `xss`.
|
|
6
|
+
* - Arrays and objects are sanitized recursively.
|
|
7
|
+
* - Circular references are safely handled via a `WeakMap`.
|
|
8
|
+
*
|
|
9
|
+
* @template T
|
|
10
|
+
* @param input - Input value to sanitize (string, object, or array).
|
|
11
|
+
* @param [seen] - Internal set to track circular references.
|
|
12
|
+
* @returns Sanitized input with the same structure as the original.
|
|
13
|
+
*/
|
|
14
|
+
export const sanitizeUserInput = (input, seen = new WeakMap()) => {
|
|
15
|
+
if (typeof input === 'string')
|
|
16
|
+
return xss(input);
|
|
17
|
+
if (Array.isArray(input)) {
|
|
18
|
+
if (seen.has(input))
|
|
19
|
+
return seen.get(input);
|
|
20
|
+
const sanitized = [];
|
|
21
|
+
seen.set(input, sanitized);
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
23
|
+
sanitized.push(...input.map(item => sanitizeUserInput(item, seen)));
|
|
24
|
+
return sanitized;
|
|
19
25
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
if (input !== null && typeof input === 'object') {
|
|
27
|
+
if (seen.has(input))
|
|
28
|
+
return seen.get(input);
|
|
29
|
+
const sanitized = {};
|
|
30
|
+
seen.set(input, sanitized);
|
|
31
|
+
const entries = Object.entries(input);
|
|
32
|
+
for (const [key, value] of entries) {
|
|
33
|
+
sanitized[xss(key)] = sanitizeUserInput(value, seen);
|
|
34
|
+
}
|
|
35
|
+
return sanitized;
|
|
36
|
+
}
|
|
37
|
+
return input;
|
|
26
38
|
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { sanitizeUserInput } from './index.js';
|
|
3
|
+
vi.mock('xss', () => ({
|
|
4
|
+
default: vi.fn((value) => `sanitized(${value})`)
|
|
5
|
+
}));
|
|
6
|
+
describe('sanitizeUserInput', () => {
|
|
7
|
+
it('sanitizes plain strings using xss', () => {
|
|
8
|
+
const result = sanitizeUserInput('<script>alert(1)</script>');
|
|
9
|
+
expect(result).toBe('sanitized(<script>alert(1)</script>)');
|
|
10
|
+
});
|
|
11
|
+
it('recursively sanitizes arrays and objects', () => {
|
|
12
|
+
const input = {
|
|
13
|
+
'<key>': ['<v1>', '<v2>'],
|
|
14
|
+
nested: { '<inner>': '<v3>' }
|
|
15
|
+
};
|
|
16
|
+
const result = sanitizeUserInput(input);
|
|
17
|
+
expect(result).toEqual({
|
|
18
|
+
'sanitized(<key>)': ['sanitized(<v1>)', 'sanitized(<v2>)'],
|
|
19
|
+
'sanitized(nested)': { 'sanitized(<inner>)': 'sanitized(<v3>)' }
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
it('handles circular references without infinite recursion', () => {
|
|
23
|
+
const obj = { name: '<name>' };
|
|
24
|
+
obj.self = obj;
|
|
25
|
+
const result = sanitizeUserInput(obj);
|
|
26
|
+
// Just verify it doesn't throw and returns something
|
|
27
|
+
expect(result).toBeDefined();
|
|
28
|
+
// The circular reference should still be circular
|
|
29
|
+
expect(result['sanitized(self)']).toBe(result);
|
|
30
|
+
});
|
|
31
|
+
});
|