├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── src ├── api_test.ts ├── install.ts └── library.ts └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | node_modules 4 | dist 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | tsconfig.json 2 | .vscode 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Axel Rauschmayer 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Set methods polyfill 2 | 3 | A polyfill for [the ECMAScript proposal “Set Methods for JavaScript”](https://github.com/tc39/proposal-set-methods) ([documentation for this proposal](https://2ality.com/2022/12/set-methods.html)). 4 | 5 | ## Warning 6 | 7 | **Don’t trust this code:** 8 | 9 | * It’s mostly untested. 10 | 11 | Caveats: 12 | 13 | * The focus is on simple code, not on spec compliance. 14 | 15 | Functionality: 16 | 17 | * This polyfill implements all methods specified in the proposal. 18 | * This polyfill deliberately does not provide any additional functionality. 19 | 20 | ## Installation 21 | 22 | ```js 23 | npm install @rauschma/set-methods-polyfill 24 | ``` 25 | 26 | ## Examples 27 | 28 | ### Polyfill 29 | 30 | ```js 31 | import '@rauschma/set-methods-polyfill/install'; 32 | import assert from 'node:assert/strict'; 33 | 34 | assert.deepEqual( 35 | new Set(['a', 'b', 'c']).union(new Set(['c', 'd'])), 36 | new Set(['a', 'b', 'c', 'd']) 37 | ); 38 | assert.deepEqual( 39 | new Set(['a', 'b', 'c']).intersection(new Set(['c', 'd'])), 40 | new Set(['c']) 41 | ); 42 | assert.deepEqual( 43 | new Set(['a', 'b', 'c']).difference(new Set(['c', 'd'])), 44 | new Set(['a', 'b']) 45 | ); 46 | 47 | assert.deepEqual( 48 | new Set(['a', 'b', 'c']).isSubsetOf(new Set(['a'])), 49 | false 50 | ); 51 | assert.deepEqual( 52 | new Set(['a', 'b', 'c']).isSupersetOf(new Set(['a'])), 53 | true 54 | ); 55 | ``` 56 | 57 | ### Library (doesn’t change JavaScript’s globals) 58 | 59 | ```js 60 | import {union, intersection, difference, isSubsetOf, isSupersetOf} from '@rauschma/set-methods-polyfill'; 61 | import assert from 'node:assert/strict'; 62 | 63 | assert.deepEqual( 64 | union(new Set(['a', 'b', 'c']), new Set(['c', 'd'])), 65 | new Set(['a', 'b', 'c', 'd']) 66 | ); 67 | assert.deepEqual( 68 | intersection(new Set(['a', 'b', 'c']), new Set(['c', 'd'])), 69 | new Set(['c']) 70 | ); 71 | assert.deepEqual( 72 | difference(new Set(['a', 'b', 'c']), new Set(['c', 'd'])), 73 | new Set(['a', 'b']) 74 | ); 75 | 76 | assert.deepEqual( 77 | isSubsetOf(new Set(['a', 'b', 'c']), new Set(['a'])), 78 | false 79 | ); 80 | assert.deepEqual( 81 | isSupersetOf(new Set(['a', 'b', 'c']), new Set(['a'])), 82 | true 83 | ); 84 | ``` 85 | 86 | ### More examples 87 | 88 | * [`src/api_test.ts`](https://github.com/rauschma/set-methods-polyfill/blob/main/src/api_test.ts) 89 | 90 | ## Material on iterator helpers 91 | 92 | * ECMAScript proposal “Set Methods for JavaScript”: https://github.com/tc39/proposal-set-methods 93 | * Blog post: https://2ality.com/2022/12/set-methods.html 94 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rauschma/set-methods-polyfill", 3 | "version": "0.1.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@rauschma/set-methods-polyfill", 9 | "version": "0.1.0", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "@types/node": "^18.11.12", 13 | "shx": "^0.3.4", 14 | "typescript": "^4.9.4" 15 | } 16 | }, 17 | "node_modules/@types/node": { 18 | "version": "18.11.15", 19 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.15.tgz", 20 | "integrity": "sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw==", 21 | "dev": true 22 | }, 23 | "node_modules/balanced-match": { 24 | "version": "1.0.2", 25 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 26 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 27 | "dev": true 28 | }, 29 | "node_modules/brace-expansion": { 30 | "version": "1.1.11", 31 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 32 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 33 | "dev": true, 34 | "dependencies": { 35 | "balanced-match": "^1.0.0", 36 | "concat-map": "0.0.1" 37 | } 38 | }, 39 | "node_modules/concat-map": { 40 | "version": "0.0.1", 41 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 42 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 43 | "dev": true 44 | }, 45 | "node_modules/fs.realpath": { 46 | "version": "1.0.0", 47 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 48 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 49 | "dev": true 50 | }, 51 | "node_modules/function-bind": { 52 | "version": "1.1.1", 53 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 54 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 55 | "dev": true 56 | }, 57 | "node_modules/glob": { 58 | "version": "7.2.3", 59 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 60 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 61 | "dev": true, 62 | "dependencies": { 63 | "fs.realpath": "^1.0.0", 64 | "inflight": "^1.0.4", 65 | "inherits": "2", 66 | "minimatch": "^3.1.1", 67 | "once": "^1.3.0", 68 | "path-is-absolute": "^1.0.0" 69 | }, 70 | "engines": { 71 | "node": "*" 72 | }, 73 | "funding": { 74 | "url": "https://github.com/sponsors/isaacs" 75 | } 76 | }, 77 | "node_modules/has": { 78 | "version": "1.0.3", 79 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 80 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 81 | "dev": true, 82 | "dependencies": { 83 | "function-bind": "^1.1.1" 84 | }, 85 | "engines": { 86 | "node": ">= 0.4.0" 87 | } 88 | }, 89 | "node_modules/inflight": { 90 | "version": "1.0.6", 91 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 92 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 93 | "dev": true, 94 | "dependencies": { 95 | "once": "^1.3.0", 96 | "wrappy": "1" 97 | } 98 | }, 99 | "node_modules/inherits": { 100 | "version": "2.0.4", 101 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 102 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 103 | "dev": true 104 | }, 105 | "node_modules/interpret": { 106 | "version": "1.4.0", 107 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", 108 | "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", 109 | "dev": true, 110 | "engines": { 111 | "node": ">= 0.10" 112 | } 113 | }, 114 | "node_modules/is-core-module": { 115 | "version": "2.11.0", 116 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", 117 | "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", 118 | "dev": true, 119 | "dependencies": { 120 | "has": "^1.0.3" 121 | }, 122 | "funding": { 123 | "url": "https://github.com/sponsors/ljharb" 124 | } 125 | }, 126 | "node_modules/minimatch": { 127 | "version": "3.1.2", 128 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 129 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 130 | "dev": true, 131 | "dependencies": { 132 | "brace-expansion": "^1.1.7" 133 | }, 134 | "engines": { 135 | "node": "*" 136 | } 137 | }, 138 | "node_modules/minimist": { 139 | "version": "1.2.7", 140 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", 141 | "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", 142 | "dev": true, 143 | "funding": { 144 | "url": "https://github.com/sponsors/ljharb" 145 | } 146 | }, 147 | "node_modules/once": { 148 | "version": "1.4.0", 149 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 150 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 151 | "dev": true, 152 | "dependencies": { 153 | "wrappy": "1" 154 | } 155 | }, 156 | "node_modules/path-is-absolute": { 157 | "version": "1.0.1", 158 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 159 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 160 | "dev": true, 161 | "engines": { 162 | "node": ">=0.10.0" 163 | } 164 | }, 165 | "node_modules/path-parse": { 166 | "version": "1.0.7", 167 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 168 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 169 | "dev": true 170 | }, 171 | "node_modules/rechoir": { 172 | "version": "0.6.2", 173 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", 174 | "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", 175 | "dev": true, 176 | "dependencies": { 177 | "resolve": "^1.1.6" 178 | }, 179 | "engines": { 180 | "node": ">= 0.10" 181 | } 182 | }, 183 | "node_modules/resolve": { 184 | "version": "1.22.1", 185 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", 186 | "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", 187 | "dev": true, 188 | "dependencies": { 189 | "is-core-module": "^2.9.0", 190 | "path-parse": "^1.0.7", 191 | "supports-preserve-symlinks-flag": "^1.0.0" 192 | }, 193 | "bin": { 194 | "resolve": "bin/resolve" 195 | }, 196 | "funding": { 197 | "url": "https://github.com/sponsors/ljharb" 198 | } 199 | }, 200 | "node_modules/shelljs": { 201 | "version": "0.8.5", 202 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", 203 | "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", 204 | "dev": true, 205 | "dependencies": { 206 | "glob": "^7.0.0", 207 | "interpret": "^1.0.0", 208 | "rechoir": "^0.6.2" 209 | }, 210 | "bin": { 211 | "shjs": "bin/shjs" 212 | }, 213 | "engines": { 214 | "node": ">=4" 215 | } 216 | }, 217 | "node_modules/shx": { 218 | "version": "0.3.4", 219 | "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", 220 | "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", 221 | "dev": true, 222 | "dependencies": { 223 | "minimist": "^1.2.3", 224 | "shelljs": "^0.8.5" 225 | }, 226 | "bin": { 227 | "shx": "lib/cli.js" 228 | }, 229 | "engines": { 230 | "node": ">=6" 231 | } 232 | }, 233 | "node_modules/supports-preserve-symlinks-flag": { 234 | "version": "1.0.0", 235 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 236 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 237 | "dev": true, 238 | "engines": { 239 | "node": ">= 0.4" 240 | }, 241 | "funding": { 242 | "url": "https://github.com/sponsors/ljharb" 243 | } 244 | }, 245 | "node_modules/typescript": { 246 | "version": "4.9.4", 247 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", 248 | "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", 249 | "dev": true, 250 | "bin": { 251 | "tsc": "bin/tsc", 252 | "tsserver": "bin/tsserver" 253 | }, 254 | "engines": { 255 | "node": ">=4.2.0" 256 | } 257 | }, 258 | "node_modules/wrappy": { 259 | "version": "1.0.2", 260 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 261 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 262 | "dev": true 263 | } 264 | }, 265 | "dependencies": { 266 | "@types/node": { 267 | "version": "18.11.15", 268 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.15.tgz", 269 | "integrity": "sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw==", 270 | "dev": true 271 | }, 272 | "balanced-match": { 273 | "version": "1.0.2", 274 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 275 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 276 | "dev": true 277 | }, 278 | "brace-expansion": { 279 | "version": "1.1.11", 280 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 281 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 282 | "dev": true, 283 | "requires": { 284 | "balanced-match": "^1.0.0", 285 | "concat-map": "0.0.1" 286 | } 287 | }, 288 | "concat-map": { 289 | "version": "0.0.1", 290 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 291 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 292 | "dev": true 293 | }, 294 | "fs.realpath": { 295 | "version": "1.0.0", 296 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 297 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 298 | "dev": true 299 | }, 300 | "function-bind": { 301 | "version": "1.1.1", 302 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 303 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 304 | "dev": true 305 | }, 306 | "glob": { 307 | "version": "7.2.3", 308 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", 309 | "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", 310 | "dev": true, 311 | "requires": { 312 | "fs.realpath": "^1.0.0", 313 | "inflight": "^1.0.4", 314 | "inherits": "2", 315 | "minimatch": "^3.1.1", 316 | "once": "^1.3.0", 317 | "path-is-absolute": "^1.0.0" 318 | } 319 | }, 320 | "has": { 321 | "version": "1.0.3", 322 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 323 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 324 | "dev": true, 325 | "requires": { 326 | "function-bind": "^1.1.1" 327 | } 328 | }, 329 | "inflight": { 330 | "version": "1.0.6", 331 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 332 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 333 | "dev": true, 334 | "requires": { 335 | "once": "^1.3.0", 336 | "wrappy": "1" 337 | } 338 | }, 339 | "inherits": { 340 | "version": "2.0.4", 341 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 342 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 343 | "dev": true 344 | }, 345 | "interpret": { 346 | "version": "1.4.0", 347 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", 348 | "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", 349 | "dev": true 350 | }, 351 | "is-core-module": { 352 | "version": "2.11.0", 353 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", 354 | "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", 355 | "dev": true, 356 | "requires": { 357 | "has": "^1.0.3" 358 | } 359 | }, 360 | "minimatch": { 361 | "version": "3.1.2", 362 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 363 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 364 | "dev": true, 365 | "requires": { 366 | "brace-expansion": "^1.1.7" 367 | } 368 | }, 369 | "minimist": { 370 | "version": "1.2.7", 371 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", 372 | "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", 373 | "dev": true 374 | }, 375 | "once": { 376 | "version": "1.4.0", 377 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 378 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 379 | "dev": true, 380 | "requires": { 381 | "wrappy": "1" 382 | } 383 | }, 384 | "path-is-absolute": { 385 | "version": "1.0.1", 386 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 387 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 388 | "dev": true 389 | }, 390 | "path-parse": { 391 | "version": "1.0.7", 392 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 393 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 394 | "dev": true 395 | }, 396 | "rechoir": { 397 | "version": "0.6.2", 398 | "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", 399 | "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", 400 | "dev": true, 401 | "requires": { 402 | "resolve": "^1.1.6" 403 | } 404 | }, 405 | "resolve": { 406 | "version": "1.22.1", 407 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", 408 | "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", 409 | "dev": true, 410 | "requires": { 411 | "is-core-module": "^2.9.0", 412 | "path-parse": "^1.0.7", 413 | "supports-preserve-symlinks-flag": "^1.0.0" 414 | } 415 | }, 416 | "shelljs": { 417 | "version": "0.8.5", 418 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", 419 | "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", 420 | "dev": true, 421 | "requires": { 422 | "glob": "^7.0.0", 423 | "interpret": "^1.0.0", 424 | "rechoir": "^0.6.2" 425 | } 426 | }, 427 | "shx": { 428 | "version": "0.3.4", 429 | "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", 430 | "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", 431 | "dev": true, 432 | "requires": { 433 | "minimist": "^1.2.3", 434 | "shelljs": "^0.8.5" 435 | } 436 | }, 437 | "supports-preserve-symlinks-flag": { 438 | "version": "1.0.0", 439 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 440 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 441 | "dev": true 442 | }, 443 | "typescript": { 444 | "version": "4.9.4", 445 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", 446 | "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", 447 | "dev": true 448 | }, 449 | "wrappy": { 450 | "version": "1.0.2", 451 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 452 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 453 | "dev": true 454 | } 455 | } 456 | } 457 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@rauschma/set-methods-polyfill", 3 | "description": "A polyfill for the ECMAScript proposal “Set Methods for JavaScript”", 4 | "version": "0.2.0", 5 | "author": "Axel Rauschmayer", 6 | "keywords": [ 7 | "javascript", 8 | "typescript", 9 | "iteration", 10 | "iterator" 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/rauschma/set-methods-polyfill.git" 15 | }, 16 | "license": "MIT", 17 | "type": "module", 18 | "exports": { 19 | ".": "./dist/library.js", 20 | "./install": "./dist/install.js" 21 | }, 22 | "typesVersions": { 23 | "*": { 24 | "*": ["./dist/library.d.ts", "./dist/install.d.ts"] 25 | } 26 | }, 27 | "scripts": { 28 | "test": "node --test", 29 | "testall": "node --test dist/*_test.js", 30 | "dry": "npm publish --dry-run", 31 | "prepublishOnly": "npm run clean && npm run build", 32 | "build": "tsc", 33 | "watch": "tsc --watch", 34 | "clean": "shx rm -rf ./dist" 35 | }, 36 | "// devDependencies": { 37 | "@types/node": "needed for the unit tests (which use Node’s built-in test runner)", 38 | "shx": "used by the scripts", 39 | "typescript": "needed for `npm publish`" 40 | }, 41 | "devDependencies": { 42 | "@types/node": "^18.11.12", 43 | "shx": "^0.3.4", 44 | "typescript": "^4.9.4" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/api_test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'node:assert/strict'; 2 | import test from 'node:test'; 3 | import './install.js'; 4 | import { intersection, difference, symmetricDifference, isSubsetOf, isSupersetOf, isDisjointFrom, union } from './library.js'; 5 | 6 | // The API often checks which of the two operands have the larger size. 7 | // Therefore – test both: 8 | // - (larger Set, smaller Set) and 9 | // - (smaller Set, larger Set) 10 | 11 | //========== Polyfill ========== 12 | 13 | test('Polyfill: union', (t) => { 14 | assert.deepEqual( 15 | new Set(['a', 'b', 'c']).union(new Set(['c', 'd'])), 16 | new Set(['a', 'b', 'c', 'd']) 17 | ); 18 | assert.deepEqual( 19 | new Set(['c', 'd']).union(new Set(['a', 'b', 'c'])), 20 | new Set(['a', 'b', 'c', 'd']) 21 | ); 22 | 23 | assert.deepEqual( 24 | new Set(['a', 'b', 'c']).union(new Set([])), 25 | new Set(['a', 'b', 'c']) 26 | ); 27 | assert.deepEqual( 28 | new Set([]).union(new Set(['a', 'b', 'c'])), 29 | new Set(['a', 'b', 'c']) 30 | ); 31 | }); 32 | 33 | test('Polyfill: intersection', (t) => { 34 | assert.deepEqual( 35 | new Set(['a', 'b', 'c']).intersection(new Set(['c', 'd'])), 36 | new Set(['c']) 37 | ); 38 | assert.deepEqual( 39 | new Set(['c', 'd']).intersection(new Set(['a', 'b', 'c'])), 40 | new Set(['c']) 41 | ); 42 | 43 | assert.deepEqual( 44 | new Set(['a', 'b']).intersection(new Set(['c', 'd'])), 45 | new Set([]) 46 | ); 47 | assert.deepEqual( 48 | new Set(['c', 'd']).intersection(new Set(['a', 'b'])), 49 | new Set([]) 50 | ); 51 | }); 52 | 53 | test('Polyfill: difference', (t) => { 54 | assert.deepEqual( 55 | new Set(['a', 'b', 'c']).difference(new Set(['c', 'd'])), 56 | new Set(['a', 'b']) 57 | ); 58 | assert.deepEqual( 59 | new Set(['c', 'd']).difference(new Set(['a', 'b', 'c'])), 60 | new Set(['d']) 61 | ); 62 | 63 | assert.deepEqual( 64 | new Set(['a', 'b', 'c']).difference(new Set([])), 65 | new Set(['a', 'b', 'c']) 66 | ); 67 | assert.deepEqual( 68 | new Set([]).difference(new Set(['a', 'b', 'c'])), 69 | new Set([]) 70 | ); 71 | }); 72 | 73 | test('Polyfill: symmetricDifference', (t) => { 74 | assert.deepEqual( 75 | new Set(['a', 'b', 'c']).symmetricDifference(new Set(['c', 'd'])), 76 | new Set(['a', 'b', 'd']) 77 | ); 78 | assert.deepEqual( 79 | new Set(['c', 'd']).symmetricDifference(new Set(['a', 'b', 'c'])), 80 | new Set(['a', 'b', 'd']) 81 | ); 82 | 83 | assert.deepEqual( 84 | new Set(['a', 'b']).symmetricDifference(new Set(['c', 'd'])), 85 | new Set(['a', 'b', 'c', 'd']) 86 | ); 87 | assert.deepEqual( 88 | new Set(['c', 'd']).symmetricDifference(new Set(['a', 'b'])), 89 | new Set(['a', 'b', 'c', 'd']) 90 | ); 91 | }); 92 | 93 | test('Polyfill: isSubsetOf', (t) => { 94 | assert.deepEqual( 95 | new Set(['a', 'b', 'c']).isSubsetOf(new Set(['c', 'd'])), 96 | false 97 | ); 98 | assert.deepEqual( 99 | new Set(['c', 'd']).isSubsetOf(new Set(['a', 'b', 'c'])), 100 | false 101 | ); 102 | assert.deepEqual( 103 | new Set(['a', 'b', 'c']).isSubsetOf(new Set(['a'])), 104 | false 105 | ); 106 | assert.deepEqual( 107 | new Set(['a']).isSubsetOf(new Set(['a', 'b', 'c'])), 108 | true 109 | ); 110 | }); 111 | 112 | test('Polyfill: isSupersetOf', (t) => { 113 | assert.deepEqual( 114 | new Set(['a', 'b', 'c']).isSupersetOf(new Set(['c', 'd'])), 115 | false 116 | ); 117 | assert.deepEqual( 118 | new Set(['c', 'd']).isSupersetOf(new Set(['a', 'b', 'c'])), 119 | false 120 | ); 121 | assert.deepEqual( 122 | new Set(['a', 'b', 'c']).isSupersetOf(new Set(['a'])), 123 | true 124 | ); 125 | assert.deepEqual( 126 | new Set(['a']).isSupersetOf(new Set(['a', 'b', 'c'])), 127 | false 128 | ); 129 | }); 130 | 131 | test('Polyfill: isDisjointFrom', (t) => { 132 | assert.deepEqual( 133 | new Set(['a', 'b', 'c']).isDisjointFrom(new Set(['c', 'd'])), 134 | false 135 | ); 136 | assert.deepEqual( 137 | new Set(['c', 'd']).isDisjointFrom(new Set(['a', 'b', 'c'])), 138 | false 139 | ); 140 | assert.deepEqual( 141 | new Set(['a', 'b', 'c']).isDisjointFrom(new Set(['x'])), 142 | true 143 | ); 144 | assert.deepEqual( 145 | new Set(['x']).isDisjointFrom(new Set(['a', 'b', 'c'])), 146 | true 147 | ); 148 | }); 149 | 150 | test('Polyfill: Infinity', (t) => { 151 | const evenNumbers = { 152 | has(elem: number) { 153 | return (elem % 2) === 0; 154 | }, 155 | size: Infinity, 156 | keys() { 157 | throw new TypeError(); 158 | } 159 | }; 160 | assert.deepEqual( 161 | new Set([0, 1, 2, 3]).difference(evenNumbers), 162 | new Set([1, 3]) 163 | ); 164 | assert.deepEqual( 165 | new Set([0, 1, 2, 3]).intersection(evenNumbers), 166 | new Set([0, 2]) 167 | ); 168 | }); 169 | 170 | //========== Library ========== 171 | 172 | test('Library: union', (t) => { 173 | assert.deepEqual( 174 | union(new Set(['a', 'b', 'c']), new Set(['c', 'd'])), 175 | new Set(['a', 'b', 'c', 'd']) 176 | ); 177 | assert.deepEqual( 178 | union(new Set(['c', 'd']), new Set(['a', 'b', 'c'])), 179 | new Set(['a', 'b', 'c', 'd']) 180 | ); 181 | 182 | assert.deepEqual( 183 | union(new Set(['a', 'b', 'c']), new Set([])), 184 | new Set(['a', 'b', 'c']) 185 | ); 186 | assert.deepEqual( 187 | union(new Set([]), new Set(['a', 'b', 'c'])), 188 | new Set(['a', 'b', 'c']) 189 | ); 190 | }); 191 | 192 | test('Library: intersection', (t) => { 193 | assert.deepEqual( 194 | intersection(new Set(['a', 'b', 'c']), new Set(['c', 'd'])), 195 | new Set(['c']) 196 | ); 197 | assert.deepEqual( 198 | intersection(new Set(['c', 'd']), new Set(['a', 'b', 'c'])), 199 | new Set(['c']) 200 | ); 201 | 202 | assert.deepEqual( 203 | intersection(new Set(['a', 'b']), new Set(['c', 'd'])), 204 | new Set([]) 205 | ); 206 | assert.deepEqual( 207 | intersection(new Set(['c', 'd']), new Set(['a', 'b'])), 208 | new Set([]) 209 | ); 210 | }); 211 | 212 | test('Library: difference', (t) => { 213 | assert.deepEqual( 214 | difference(new Set(['a', 'b', 'c']), new Set(['c', 'd'])), 215 | new Set(['a', 'b']) 216 | ); 217 | assert.deepEqual( 218 | difference(new Set(['c', 'd']), new Set(['a', 'b', 'c'])), 219 | new Set(['d']) 220 | ); 221 | 222 | assert.deepEqual( 223 | difference(new Set(['a', 'b', 'c']), new Set([])), 224 | new Set(['a', 'b', 'c']) 225 | ); 226 | assert.deepEqual( 227 | difference(new Set([]), new Set(['a', 'b', 'c'])), 228 | new Set([]) 229 | ); 230 | }); 231 | 232 | test('Library: symmetricDifference', (t) => { 233 | assert.deepEqual( 234 | symmetricDifference(new Set(['a', 'b', 'c']), new Set(['c', 'd'])), 235 | new Set(['a', 'b', 'd']) 236 | ); 237 | assert.deepEqual( 238 | symmetricDifference(new Set(['c', 'd']), new Set(['a', 'b', 'c'])), 239 | new Set(['a', 'b', 'd']) 240 | ); 241 | 242 | assert.deepEqual( 243 | symmetricDifference(new Set(['a', 'b']), new Set(['c', 'd'])), 244 | new Set(['a', 'c', 'b', 'd']) 245 | ); 246 | assert.deepEqual( 247 | symmetricDifference(new Set(['c', 'd']), new Set(['a', 'b'])), 248 | new Set(['a', 'c', 'b', 'd']) 249 | ); 250 | }); 251 | 252 | test('Library: isSubsetOf', (t) => { 253 | assert.deepEqual( 254 | isSubsetOf(new Set(['a', 'b', 'c']), new Set(['c', 'd'])), 255 | false 256 | ); 257 | assert.deepEqual( 258 | isSubsetOf(new Set(['c', 'd']), new Set(['a', 'b', 'c'])), 259 | false 260 | ); 261 | assert.deepEqual( 262 | isSubsetOf(new Set(['a', 'b', 'c']), new Set(['a'])), 263 | false 264 | ); 265 | assert.deepEqual( 266 | isSubsetOf(new Set(['a']), new Set(['a', 'b', 'c'])), 267 | true 268 | ); 269 | }); 270 | 271 | test('Library: isSupersetOf', (t) => { 272 | assert.deepEqual( 273 | isSupersetOf(new Set(['a', 'b', 'c']), new Set(['c', 'd'])), 274 | false 275 | ); 276 | assert.deepEqual( 277 | isSupersetOf(new Set(['c', 'd']), new Set(['a', 'b', 'c'])), 278 | false 279 | ); 280 | assert.deepEqual( 281 | isSupersetOf(new Set(['a', 'b', 'c']), new Set(['a'])), 282 | true 283 | ); 284 | assert.deepEqual( 285 | isSupersetOf(new Set(['a']), new Set(['a', 'b', 'c'])), 286 | false 287 | ); 288 | }); 289 | 290 | test('Library: isDisjointFrom', (t) => { 291 | assert.deepEqual( 292 | isDisjointFrom(new Set(['a', 'b', 'c']), new Set(['c', 'd'])), 293 | false 294 | ); 295 | assert.deepEqual( 296 | isDisjointFrom(new Set(['c', 'd']), new Set(['a', 'b', 'c'])), 297 | false 298 | ); 299 | assert.deepEqual( 300 | isDisjointFrom(new Set(['a', 'b', 'c']), new Set(['x'])), 301 | true 302 | ); 303 | assert.deepEqual( 304 | isDisjointFrom(new Set(['x']), new Set(['a', 'b', 'c'])), 305 | true 306 | ); 307 | }); 308 | 309 | test('Library: Infinity', (t) => { 310 | const evenNumbers = { 311 | has(elem: number) { 312 | return (elem % 2) === 0; 313 | }, 314 | size: Infinity, 315 | keys() { 316 | throw new TypeError(); 317 | } 318 | }; 319 | assert.deepEqual( 320 | difference(new Set([0, 1, 2, 3]), evenNumbers), 321 | new Set([1, 3]) 322 | ); 323 | assert.deepEqual( 324 | intersection(new Set([0, 1, 2, 3]), evenNumbers), 325 | new Set([0, 2]) 326 | ); 327 | }); 328 | -------------------------------------------------------------------------------- /src/install.ts: -------------------------------------------------------------------------------- 1 | import { _union, _intersection, _difference, _symmetricDifference, _isSubsetOf, _isSupersetOf, _isDisjointFrom } from "./library.js"; 2 | 3 | //========== Types ========== 4 | 5 | declare global { 6 | 7 | interface Set { 8 | union: typeof _union; 9 | intersection: typeof _intersection; 10 | difference: typeof _difference; 11 | symmetricDifference: typeof _symmetricDifference; 12 | isSubsetOf: typeof _isSubsetOf; 13 | isSupersetOf: typeof _isSupersetOf; 14 | isDisjointFrom: typeof _isDisjointFrom; 15 | } 16 | 17 | } // declare global 18 | 19 | //========== Polyfill ========== 20 | 21 | function installPolyfill() { 22 | const funcs = [ 23 | _union, 24 | _intersection, 25 | _difference, 26 | _symmetricDifference, 27 | _isSubsetOf, 28 | _isSupersetOf, 29 | _isDisjointFrom, 30 | ]; 31 | for (const func of funcs) { 32 | Object.defineProperty( 33 | Set.prototype, func.name.slice(1), // remove prefixed underscore 34 | { 35 | value: func, 36 | writable: true, 37 | enumerable: false, 38 | configurable: true 39 | } 40 | ); 41 | } 42 | } 43 | 44 | installPolyfill(); -------------------------------------------------------------------------------- /src/library.ts: -------------------------------------------------------------------------------- 1 | interface SetReadOperations { 2 | size: number; 3 | has(key: T): boolean; 4 | keys(): IterableIterator; 5 | } 6 | 7 | export function _union(this: Set, other: SetReadOperations): Set { 8 | CheckSetRecord(other); 9 | const result = new Set(this); 10 | for (const elem of other.keys()) { 11 | result.add(elem); 12 | } 13 | return result; 14 | } 15 | 16 | export function _intersection(this: Set, other: SetReadOperations): Set { 17 | CheckSetRecord(other); 18 | let smallerElems; 19 | let largerHas; 20 | if (this.size <= other.size) { 21 | smallerElems = this; 22 | largerHas = other; 23 | } else { 24 | smallerElems = other.keys(); 25 | largerHas = this; 26 | } 27 | const result = new Set(); 28 | for (const elem of smallerElems) { 29 | if (largerHas.has(elem)) { 30 | result.add(elem); 31 | } 32 | } 33 | return result; 34 | } 35 | 36 | /* this − other */ 37 | export function _difference(this: Set, other: SetReadOperations): Set { 38 | CheckSetRecord(other); 39 | const result = new Set(this); 40 | if (this.size <= other.size) { 41 | for (const elem of this) { 42 | if (other.has(elem)) { 43 | result.delete(elem); 44 | } 45 | } 46 | } else { 47 | for (const elem of other.keys()) { 48 | if (result.has(elem)) { 49 | result.delete(elem); 50 | } 51 | } 52 | } 53 | return result; 54 | } 55 | 56 | /** 57 | * - this − other ∪ other − this 58 | * - xor 59 | * - the union minus the intersection 60 | * - all elements that don’t exist in both Sets 61 | */ 62 | export function _symmetricDifference(this: Set, other: SetReadOperations): Set { 63 | CheckSetRecord(other); 64 | const result = new Set(this); 65 | for (const elem of other.keys()) { 66 | if (this.has(elem)) { 67 | // Delete elements of `this` that also exist in `other` 68 | result.delete(elem); 69 | } else { 70 | // Add elements of `other` that don’t exist in `this` 71 | result.add(elem); 72 | } 73 | } 74 | return result; 75 | } 76 | 77 | export function _isSubsetOf(this: Set, other: SetReadOperations): boolean { 78 | CheckSetRecord(other); 79 | for (const elem of this) { 80 | if (!other.has(elem)) return false; 81 | } 82 | return true; 83 | } 84 | 85 | export function _isSupersetOf(this: Set, other: SetReadOperations): boolean { 86 | CheckSetRecord(other); 87 | for (const elem of other.keys()) { 88 | if (!this.has(elem)) return false; 89 | } 90 | return true; 91 | } 92 | 93 | export function _isDisjointFrom(this: Set, other: SetReadOperations): boolean { 94 | CheckSetRecord(other); 95 | if (this.size <= other.size) { 96 | for (const elem of this) { 97 | if (other.has(elem)) return false; 98 | } 99 | } else { 100 | for (const elem of other.keys()) { 101 | if (this.has(elem)) return false; 102 | } 103 | } 104 | return true; 105 | } 106 | 107 | /** 108 | * A simpler version of GetSetRecord that only performs checks. 109 | */ 110 | function CheckSetRecord(obj: SetReadOperations): void { 111 | if (!isObject(obj)) { 112 | throw new TypeError(); 113 | } 114 | const rawSize = obj.size; 115 | const numSize = Number(rawSize); 116 | // NaN if rawSize is `undefined` 117 | if (Number.isNaN(numSize)) { 118 | throw new TypeError(); 119 | } 120 | // const intSize = ToIntegerOrInfinity(numSize); 121 | const has = obj.has; 122 | if (typeof has !== 'function') { 123 | throw new TypeError(); 124 | } 125 | const keys = obj.keys; 126 | if (typeof keys !== 'function') { 127 | throw new TypeError(); 128 | } 129 | // return {Set: obj, Size: intSize, Has: has, Keys: keys}; 130 | } 131 | 132 | function isObject(value: unknown) { 133 | if (value === null) return false; 134 | const t = typeof value; 135 | return t === 'object' || t === 'function'; 136 | } 137 | 138 | export const union = uncurryThisForSetResult(_union); 139 | export const intersection = uncurryThisForSetResult(_intersection); 140 | export const difference = uncurryThisForSetResult(_difference); 141 | export const symmetricDifference = uncurryThisForSetResult(_symmetricDifference); 142 | 143 | export const isSubsetOf = uncurryThisForNonSetResult(_isSubsetOf); 144 | export const isSupersetOf = uncurryThisForNonSetResult(_isSupersetOf); 145 | export const isDisjointFrom = uncurryThisForNonSetResult(_isDisjointFrom); 146 | 147 | function uncurryThisForSetResult(func: (this: Set, other: SetReadOperations) => Set): (arg: Set, other: SetReadOperations) => Set { 148 | return Function.prototype.call.bind(func as any) as any; 149 | } 150 | function uncurryThisForNonSetResult(func: Func): Func extends (this: Set, other: SetReadOperations) => infer Result ? (arg: Set, other: SetReadOperations) => Result : never { 151 | return Function.prototype.call.bind(func as any) as any; 152 | } 153 | 154 | // function uncurryThis(func: F): F extends (this: infer This, ...args: infer Args) => infer Result ? (arg: This, ...restArgs: Args) => Result : never { 155 | // return Function.prototype.call.bind(func as any) as any; 156 | // } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["src/**/*"], 3 | "compilerOptions": { 4 | "rootDir": "./src", 5 | "outDir": "dist", 6 | "target": "es2022", 7 | "lib": [ 8 | "es2022" 9 | ], 10 | "module": "ES2022", 11 | "strict": true, 12 | "noImplicitOverride": true, 13 | "importsNotUsedAsValues": "error", 14 | // 15 | "sourceMap": true, 16 | "declaration": true, 17 | "declarationMap": true, // enables importers to jump to source 18 | } 19 | } 20 | --------------------------------------------------------------------------------