diff --git a/packages/cli/package.json b/packages/cli/package.json index 0823e1c..ba0196b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -29,11 +29,11 @@ "license": "MIT", "dependencies": { "commander": "^11.0.0", - "magic-string": "^0.30.2", "nanospinner": "^1.1.0", "picocolors": "^1.0.0", "picomatch": "^2.3.1", "prompts": "^2.4.2", + "recast": "^0.23.3", "yaml": "^2.3.1" }, "devDependencies": { diff --git a/packages/cli/src/cli.js b/packages/cli/src/cli.js index 6ec8d02..bcd4167 100644 --- a/packages/cli/src/cli.js +++ b/packages/cli/src/cli.js @@ -7,6 +7,7 @@ import path from 'node:path'; import { createSpinner } from 'nanospinner'; import count from './lib/count.js'; import prompts from 'prompts'; +import ConfigsWriter from './configsWriter.js'; export default class Cli { @@ -79,9 +80,11 @@ export default class Cli { configs.filter(c => c.manual), ); - const configsMaps = processor.generateConfigMap(packages); + const writer = new ConfigsWriter(configs, packages.find(c => c.root)?.path); - console.log(configsMaps); + console.log(packages[0].config); + + packages.map(pkg => {pkg.configFile = writer.generateFileObj(pkg); return pkg;}); } diff --git a/packages/cli/src/configs.js b/packages/cli/src/configs.js index 05d4ab2..44d948a 100644 --- a/packages/cli/src/configs.js +++ b/packages/cli/src/configs.js @@ -9,13 +9,13 @@ export default [ { name: 'svelte', packages: { '@eslit/svelte': 'svelte' }, - rules: ['svelte.default'], + configs: ['svelte.recommended'], detect: ['**/*.svelte', 'svelte.config.{js,ts,cjs,cts}'], }, { name: 'vue', - packages: { '@eslint/vue': 'vue' }, - rules: ['vue.default'], + packages: { '@eslit/vue': ['vue', ['hello', 'world']], '@eslit/svelte': ['hello'] }, + configs: ['vue.recommended'], detect: ['nuxt.config.{js,ts,cjs,cts}', '**/*.vue'], }, ], @@ -26,7 +26,7 @@ export default [ manual: true, options: [{ name: 'yes', - packages: { '@eslint/config': 'config' }, + packages: { '@eslit/config': 'config', '@eslit/vue': ['test1'] }, configs: ['config.strict'], }], }, diff --git a/packages/cli/src/configsWriter.js b/packages/cli/src/configsWriter.js new file mode 100644 index 0000000..625cc05 --- /dev/null +++ b/packages/cli/src/configsWriter.js @@ -0,0 +1,126 @@ +import path from 'node:path'; +import {} from 'recast'; +import notNull from './lib/notNull.js'; + +/** + * @param {import('./types').ConfigFile['imports']} map1 - The map to has it values merged from map2 + * @param {import('./types').ConfigFile['imports']} map2 - The map to has it values merged to map1 + * @returns {import('./types').ConfigFile['imports']} The resulting map + */ +function mergeImportsMaps(map1, map2) { + for (const [key, value] of map2) { + if (!map1.has(key)) { + map1.set(key, value); + continue; + } + const imports1 = notNull(map1.get(key)); + const imports2 = notNull(map2.get(key)); + + /** + * Because arrays and objects are always different independently from having equal values + * ([] === [] -> false). It is converted to a string so the comparison can be made. + */ + switch ([typeof imports1 === 'string', typeof imports2 === 'string'].join(',')) { + case 'true,true': + map1.set(key, imports1); + break; + case 'true,false': + map1.set(key, [['default', imports1.toString()], ...imports2]); + break; + case 'false,true': + map1.set(key, [['default', imports2.toString()], ...imports1]); + break; + case 'false,false': + map1.set(key, [...imports1, ...imports2]); + break; + } + map1.set(key, [...new Set(map1.get(key))]); + } + return map1; +} + +/** + * @param {string} path1 The path to traverse from + * @param {string} root The root path + * @returns {string} The path to traverse + */ +function getPathDepth(path1, root) { + const pathDepth = path1.replace(root, '').split('/').slice(1); + if (pathDepth.length <= 1) return pathDepth.map(() => '.').join('/'); + return pathDepth.map(() => '..').join('/'); +} + +export default class ConfigsWriter { + + /** @type {string} */ + root = process.cwd(); + + /** + * @param {import('./types').Config[]} configs The array of configs to construct from + * @param {string} [root] The root directory path + */ + constructor(configs, root) { + this.configs = configs; + this.root = root ?? this.root; + } + + /** + * @param {import('./types').Package} pkg The package to generate the config string from + * @returns {import('./types').ConfigFile} The config file object + */ + generateFileObj(pkg) { + /** @type {import('./types').ConfigFile} */ + const configObj = { + path: path.join(pkg.path, 'eslint.config.js'), + imports: new Map(), + configs: [], + presets: [], + rules: [], + }; + + if (!pkg.root) { + const rootConfig = path.join(getPathDepth(pkg.path, this.root), 'eslint.config.js'); + configObj.imports.set(!rootConfig.startsWith('.') ? `./${rootConfig}` : rootConfig, 'root'); + configObj.presets.push('root'); + } + + for (const [configName, optionsNames] of notNull(pkg.config)) { + + const config = this.configs.find(c => c.name === configName); + if (!config) continue; + + const options = config.options.filter(o => optionsNames.includes(o.name)); + if (!options || options.length === 0) continue; + + const imports = options.reduce((acc, opt) => { + const map1 = new Map(Object.entries(acc.packages ?? {})); + const map2 = new Map(Object.entries(opt.packages ?? {})); + acc.packages = Object.fromEntries(mergeImportsMaps(map1, map2)); + return acc; + }); + + configObj.imports = mergeImportsMaps(configObj.imports, new Map(Object.entries(imports.packages ?? {}))); + + configObj.configs = [...new Set([ + ...configObj.configs, + ...options.map(o => o.configs ?? []).flat(), + ])]; + + configObj.rules = [...new Set([ + ...configObj.rules, + ...options.map(o => o.rules ?? []).flat(), + ])]; + + configObj.presets = [...new Set([ + ...configObj.presets, + ...options.map(o => o.presets ?? []).flat(), + ])]; + + } + + console.log(configObj); + + return configObj; + } + +} diff --git a/packages/cli/src/types.d.ts b/packages/cli/src/types.d.ts index a1e2210..b72a1fd 100644 --- a/packages/cli/src/types.d.ts +++ b/packages/cli/src/types.d.ts @@ -13,9 +13,10 @@ export type Config = { description?: string options: { name: string - packages?: Record + packages?: Record configs?: string[] rules?: string[] + presets?: string[] detect?: string[] | true }[] } | { @@ -25,15 +26,14 @@ export type Config = { description?: string options: [{ name: 'yes' - packages?: Record + packages?: Record configs?: string[] rules?: string[] + presets?: string[] detect?: undefined }] }; -export type PackagesConfigsMap = Map>; - export interface Package { root?: boolean name: string @@ -41,4 +41,13 @@ export interface Package { files: string[] directories: string[] config?: Map + configFile?: ConfigFile +} + +export interface ConfigFile { + path: string + imports: Map + configs: string[] + presets: string[] + rules: string[] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0a81224..8314e7f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -102,9 +102,6 @@ importers: commander: specifier: ^11.0.0 version: 11.0.0 - magic-string: - specifier: ^0.30.2 - version: 0.30.2 nanospinner: specifier: ^1.1.0 version: 1.1.0 @@ -117,6 +114,9 @@ importers: prompts: specifier: ^2.4.2 version: 2.4.2 + recast: + specifier: ^0.23.3 + version: 0.23.3 yaml: specifier: ^2.3.1 version: 2.3.1 @@ -712,6 +712,7 @@ packages: /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: true /@jridgewell/trace-mapping@0.3.18: resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==} @@ -1269,10 +1270,25 @@ packages: engines: {node: '>=0.10.0'} dev: true + /assert@2.0.0: + resolution: {integrity: sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==} + dependencies: + es6-object-assign: 1.1.0 + is-nan: 1.3.2 + object-is: 1.1.5 + util: 0.12.5 + dev: false + + /ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} + dependencies: + tslib: 2.4.1 + dev: false + /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} - dev: true /axobject-query@3.2.1: resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} @@ -1334,7 +1350,6 @@ packages: dependencies: function-bind: 1.1.1 get-intrinsic: 1.2.1 - dev: true /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} @@ -1573,7 +1588,6 @@ packages: dependencies: has-property-descriptors: 1.0.0 object-keys: 1.1.1 - dev: true /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} @@ -1694,6 +1708,10 @@ packages: is-symbol: 1.0.4 dev: true + /es6-object-assign@1.1.0: + resolution: {integrity: sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==} + dev: false + /es6-promise@3.3.1: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} dev: true @@ -1931,7 +1949,6 @@ packages: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - dev: true /esquery@1.5.0: resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} @@ -2049,7 +2066,6 @@ packages: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} dependencies: is-callable: 1.2.7 - dev: true /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} @@ -2082,7 +2098,6 @@ packages: /function-bind@1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - dev: true /function.prototype.name@1.1.5: resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} @@ -2110,7 +2125,6 @@ packages: has: 1.0.3 has-proto: 1.0.1 has-symbols: 1.0.3 - dev: true /get-symbol-description@1.0.0: resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} @@ -2170,7 +2184,6 @@ packages: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: get-intrinsic: 1.2.1 - dev: true /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -2205,31 +2218,26 @@ packages: resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} dependencies: get-intrinsic: 1.2.1 - dev: true /has-proto@1.0.1: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} engines: {node: '>= 0.4'} - dev: true /has-symbols@1.0.3: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} - dev: true /has-tostringtag@1.0.0: resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} engines: {node: '>= 0.4'} dependencies: has-symbols: 1.0.3 - dev: true /has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} dependencies: function-bind: 1.1.1 - dev: true /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} @@ -2294,6 +2302,14 @@ packages: side-channel: 1.0.4 dev: true + /is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + has-tostringtag: 1.0.0 + dev: false + /is-array-buffer@3.0.2: resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} dependencies: @@ -2337,7 +2353,6 @@ packages: /is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - dev: true /is-ci@3.0.1: resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} @@ -2368,12 +2383,27 @@ packages: engines: {node: '>=8'} dev: true + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: false + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 + /is-nan@1.3.2: + resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + dev: false + /is-negative-zero@2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} @@ -2454,7 +2484,6 @@ packages: for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 - dev: true /is-weakref@1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} @@ -2608,13 +2637,6 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: true - /magic-string@0.30.2: - resolution: {integrity: sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - dev: false - /map-obj@1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} @@ -2759,10 +2781,17 @@ packages: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} dev: true + /object-is@1.1.5: + resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + define-properties: 1.2.0 + dev: false + /object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} - dev: true /object.assign@4.1.4: resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} @@ -3025,6 +3054,17 @@ packages: picomatch: 2.3.1 dev: true + /recast@0.23.3: + resolution: {integrity: sha512-HbCVFh2ANP6a09nzD4lx7XthsxMOJWKX5pIcUwtLrmeEIl3I0DwjCoVXDE0Aobk+7k/mS3H50FK4iuYArpcT6Q==} + engines: {node: '>= 4'} + dependencies: + assert: 2.0.0 + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tslib: 2.4.1 + dev: false + /redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} @@ -3235,6 +3275,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: false + /spawndamnit@2.0.0: resolution: {integrity: sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==} dependencies: @@ -3518,7 +3563,6 @@ packages: /tslib@2.4.1: resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} - dev: true /tsutils@3.21.0(typescript@5.0.2): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} @@ -3675,6 +3719,16 @@ packages: dependencies: punycode: 2.3.0 + /util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + dependencies: + inherits: 2.0.4 + is-arguments: 1.1.1 + is-generator-function: 1.0.10 + is-typed-array: 1.1.10 + which-typed-array: 1.1.10 + dev: false + /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: @@ -3777,7 +3831,6 @@ packages: gopd: 1.0.1 has-tostringtag: 1.0.0 is-typed-array: 1.1.10 - dev: true /which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}