├── .github ├── FUNDING.yml ├── SPONSORS.yml └── workflows │ └── test.yml ├── .gitignore ├── .prettierrc.js ├── LICENSE ├── README.md ├── dist ├── index.d.ts └── index.js ├── eslint.config.js ├── package-lock.json ├── package.json ├── src └── index.ts ├── test └── index.test.ts └── tsconfig.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: mesqueeb 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/SPONSORS.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: mesqueeb 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | branches: main 5 | paths: 6 | - src/** 7 | - test/** 8 | - '*.js' 9 | - '*.ts' 10 | - '*.json' 11 | - .github/workflows/test.yml 12 | pull_request: 13 | branches: main 14 | paths: 15 | - src/** 16 | - test/** 17 | - '*.js' 18 | - '*.ts' 19 | - '*.json' 20 | - .github/workflows/test.yml 21 | concurrency: 22 | group: test-${{ github.ref }} 23 | cancel-in-progress: true 24 | jobs: 25 | test: 26 | strategy: 27 | matrix: 28 | node-version: ['18', '20'] 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v4 32 | - uses: actions/setup-node@v4 33 | with: 34 | node-version: ${{ matrix.node-version }} 35 | cache: npm 36 | - run: npm ci 37 | - run: npm test 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .vscode 3 | .cache 4 | .env 5 | .env.js 6 | .rpt2_cache 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | import prettier from "@cycraft/eslint/prettier" 2 | 3 | export default prettier 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Luca Ban - Mesqueeb 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 | # Find and replace anything 🎣 2 | 3 | Total Downloads 4 | Latest Stable Version 5 | 6 | ``` 7 | npm i find-and-replace-anything 8 | ``` 9 | 10 | Replace one val with another or all occurrences in an object recursively. A simple & small integration. 11 | 12 | There are two methods you can import and use: 13 | 14 | - **findAndReplace** find `a` replace with `b` (recursively on an object) 15 | - **findAndReplaceIf** execute a function on every prop in an object recursively, and replace the prop with what the function returns 16 | 17 | ## Meet the family (more tiny utils with TS support) 18 | 19 | - [is-what 🙉](https://github.com/mesqueeb/is-what) 20 | - [is-where 🙈](https://github.com/mesqueeb/is-where) 21 | - [merge-anything 🥡](https://github.com/mesqueeb/merge-anything) 22 | - [check-anything 👁](https://github.com/mesqueeb/check-anything) 23 | - [remove-anything ✂️](https://github.com/mesqueeb/remove-anything) 24 | - [getorset-anything 🐊](https://github.com/mesqueeb/getorset-anything) 25 | - [map-anything 🗺](https://github.com/mesqueeb/map-anything) 26 | - [filter-anything ⚔️](https://github.com/mesqueeb/filter-anything) 27 | - [copy-anything 🎭](https://github.com/mesqueeb/copy-anything) 28 | - [case-anything 🐫](https://github.com/mesqueeb/case-anything) 29 | - [flatten-anything 🏏](https://github.com/mesqueeb/flatten-anything) 30 | - [nestify-anything 🧅](https://github.com/mesqueeb/nestify-anything) 31 | 32 | ## find and replace 33 | 34 | This will find a value inside an object and replace it with another: 35 | 36 | - `findAndReplace(object, find, replace)` 37 | 38 | ```js 39 | import { findAndReplace } from 'find-and-replace-anything' 40 | 41 | findAndReplace({deep: {nested: {prop: 'a'}}}, 'a', 'b') 42 | // returns 43 | {deep: {nested: {prop: 'b'}}} 44 | 45 | findAndReplace('works on "exact" strings as well', 'a', 'b') 46 | // returns 47 | 'works on "exact" strings as well' 48 | 49 | findAndReplace('a', 'a', 'b') 50 | // returns 51 | 'b' 52 | 53 | // works with other types as well: 54 | findAndReplace({nr: 1}, 1, 100) 55 | // returns 56 | {nr: 100} 57 | ``` 58 | 59 | ## find and replace IF 60 | 61 | This will execute a provided function to every prop in the object recursively. The "check" function provided will receive the prop's value as param: 62 | 63 | - `findAndReplaceIf(object, checkFn)` checkFn receives each `propVal` of the object recursively 64 | 65 | ```js 66 | import { findAndReplaceIf } from 'find-and-replace-anything' 67 | 68 | // function that replaces 'a' with 'b' 69 | function checkFn (foundVal) { 70 | if (foundVal === 'a') return 'b' 71 | return foundVal 72 | // always return original foundVal when no replacement occurs 73 | } 74 | 75 | findAndReplaceIf({deep: {nested: {prop: 'a'}}}, checkFn) 76 | // returns 77 | {deep: {nested: {prop: 'b'}}} 78 | 79 | // this is what gets executed in order: 80 | checkFn({deep: {nested: {prop: 'a'}}}) 81 | checkFn({nested: {prop: 'a'}}) 82 | checkFn({prop: 'a'}) 83 | checkFn('a') 84 | // the final execution replaces 'a' with 'b' 85 | // and then returns the entire object 86 | 87 | // also works on non-objects 88 | findAndReplace('a', checkFn) 89 | // returns 90 | 'b' 91 | ``` 92 | 93 | ## A note on plain objects vs classes 94 | 95 | > only for `findAndReplace()` 96 | 97 | Please note that it will also recursively look inside special objects like JavaScript classes etc. So make sure you test the behaviour properly in those cases! (especially when your classes have read-only properties etc.) 98 | 99 | ```js 100 | class MyClass { 101 | constructor () { 102 | this.prop = 1 103 | } 104 | } 105 | const target = { 106 | prop: 1, 107 | class: new MyClass() 108 | } 109 | findAndReplace(target, 1, 2) 110 | // this will replace 1 with 2 in the class as well and returns: 111 | {prop: 2, class: {prop: 2}} 112 | ``` 113 | 114 | If you need it to only recursively go through plain JavaScript object and avoid going in custom classes etc. you can pass a 4th parameter like so: 115 | 116 | ```js 117 | findAndReplace(target, 1, 2, {onlyPlainObjects: true}) 118 | // this will replace 1 with 2 only in the plain object and returns: 119 | {prop: 2, class: {prop: 1}} 120 | ``` 121 | 122 | > Also be careful with circular references! It will cause this library to crash. 123 | 124 | ## Source code 125 | 126 | It's literally just this: 127 | 128 | ```js 129 | /** 130 | * @param {*} target Target can be anything 131 | * @param {*} find val to find 132 | * @param {*} replaceWith val to replace 133 | * @returns the target with replaced values 134 | */ 135 | function findAndReplaceRecursively (target, find, replaceWith) { 136 | if (!isObject(target)) { 137 | if (target === find) return replaceWith 138 | return target 139 | } 140 | return Object.keys(target) 141 | .reduce((carry, key) => { 142 | const val = target[key] 143 | carry[key] = findAndReplaceRecursively(val, find, replaceWith) 144 | return carry 145 | }, {}) 146 | } 147 | ``` 148 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | type Config = { 2 | onlyPlainObjects?: boolean; 3 | checkArrayValues?: boolean; 4 | }; 5 | /** 6 | * Goes through an object recursively and replaces all occurences of the `find` value with `replaceWith`. Also works no non-objects. 7 | * 8 | * @export 9 | * @param target Target can be anything 10 | * @param find val to find 11 | * @param replaceWith val to replace 12 | * @param [config={onlyPlainObjects: false, checkArrayValues: false}] 13 | * @returns the target with replaced values 14 | */ 15 | export declare function findAndReplace(target: any, find: any, replaceWith: any, config?: Config): unknown; 16 | export declare function _findAndReplaceIf(target: any, checkFn: (foundVal: any, propKey: string | undefined) => any, propKey: string | undefined, config?: Config): unknown; 17 | /** 18 | * Goes through an object recursively and replaces all props with what's is returned in the `checkFn`. Also works on non-objects. `checkFn` is triggered on every single level of any value/object. 19 | * 20 | * @export 21 | * @param target Target can be anything 22 | * @param checkFn a function that will receive the `foundVal` 23 | * @param [config={onlyPlainObjects: true, checkArrayValues: false}] 24 | * @returns the target with replaced values 25 | */ 26 | export declare function findAndReplaceIf(target: any, checkFn: (foundVal: any, propKey: string | undefined) => any, config?: Config): unknown; 27 | export {}; 28 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | import { isAnyObject, isArray, isNaNValue, isPlainObject } from 'is-what'; 2 | /** 3 | * Goes through an object recursively and replaces all occurences of the `find` value with `replaceWith`. Also works no non-objects. 4 | * 5 | * @export 6 | * @param target Target can be anything 7 | * @param find val to find 8 | * @param replaceWith val to replace 9 | * @param [config={onlyPlainObjects: false, checkArrayValues: false}] 10 | * @returns the target with replaced values 11 | */ 12 | export function findAndReplace(target, find, replaceWith, config = { onlyPlainObjects: false, checkArrayValues: false }) { 13 | const _target = target; 14 | // arrays 15 | if (config.checkArrayValues && isArray(_target) && !isAnyObject(_target)) { 16 | return _target.map((value) => findAndReplace(value, find, replaceWith, config)); 17 | } 18 | // non-objects 19 | if ((!config.onlyPlainObjects && !isAnyObject(_target)) || 20 | (config.onlyPlainObjects === true && !isPlainObject(_target))) { 21 | if (_target === find || (isNaNValue(_target) && isNaNValue(find))) { 22 | return replaceWith; 23 | } 24 | return _target; 25 | } 26 | // objects 27 | return Object.entries(target).reduce((carry, [key, val]) => { 28 | carry[key] = findAndReplace(val, find, replaceWith, config); 29 | return carry; 30 | }, {}); 31 | } 32 | export function _findAndReplaceIf(target, checkFn, propKey, config = { onlyPlainObjects: true, checkArrayValues: false }) { 33 | const _target = checkFn(target, propKey); 34 | if (config.checkArrayValues && isArray(_target) && !isAnyObject(_target)) { 35 | return _target.map((value) => _findAndReplaceIf(value, checkFn, undefined, config)); 36 | } 37 | if (!isPlainObject(_target)) 38 | return _target; 39 | return Object.entries(_target).reduce((carry, [key, val]) => { 40 | carry[key] = _findAndReplaceIf(val, checkFn, key, config); 41 | return carry; 42 | }, {}); 43 | } 44 | /** 45 | * Goes through an object recursively and replaces all props with what's is returned in the `checkFn`. Also works on non-objects. `checkFn` is triggered on every single level of any value/object. 46 | * 47 | * @export 48 | * @param target Target can be anything 49 | * @param checkFn a function that will receive the `foundVal` 50 | * @param [config={onlyPlainObjects: true, checkArrayValues: false}] 51 | * @returns the target with replaced values 52 | */ 53 | export function findAndReplaceIf(target, checkFn, config = { onlyPlainObjects: true, checkArrayValues: false }) { 54 | return _findAndReplaceIf(target, checkFn, undefined, config); 55 | } 56 | -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | import config from '@cycraft/eslint/config' 2 | 3 | export default [ 4 | ...config, 5 | { 6 | rules: { 7 | '@typescript-eslint/no-explicit-any': 'warn', 8 | }, 9 | }, 10 | ] 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "find-and-replace-anything", 3 | "version": "4.0.3", 4 | "description": "Replace one val with another or all occurrences in an object recursively. A simple & small integration.", 5 | "type": "module", 6 | "sideEffects": false, 7 | "exports": { 8 | ".": "./dist/index.js" 9 | }, 10 | "engines": { 11 | "node": ">=18" 12 | }, 13 | "scripts": { 14 | "test": "vitest run", 15 | "lint": "tsc --noEmit && eslint ./src", 16 | "build": "del-cli dist && tsc", 17 | "release": "npm run lint && npm run build && np" 18 | }, 19 | "dependencies": { 20 | "is-what": "^5.2.0" 21 | }, 22 | "devDependencies": { 23 | "@cycraft/eslint": "^0.4.3", 24 | "@cycraft/tsconfig": "^0.1.2", 25 | "del-cli": "^6.0.0", 26 | "np": "^10.2.0", 27 | "vitest": "^3.0.6" 28 | }, 29 | "files": [ 30 | "dist" 31 | ], 32 | "keywords": [ 33 | "find-and-replace", 34 | "find-replace", 35 | "find-and-replace-if", 36 | "javascript", 37 | "recursively", 38 | "has-prop", 39 | "find-prop", 40 | "replace-prop-value", 41 | "replace-value", 42 | "search-prop", 43 | "search-object-prop", 44 | "replace-if" 45 | ], 46 | "author": "Luca Ban - Mesqueeb (https://cycraft.co)", 47 | "funding": "https://github.com/sponsors/mesqueeb", 48 | "license": "MIT", 49 | "repository": { 50 | "type": "git", 51 | "url": "https://github.com/mesqueeb/find-and-replace-anything.git" 52 | }, 53 | "homepage": "https://github.com/mesqueeb/find-and-replace-anything#readme", 54 | "bugs": "https://github.com/mesqueeb/find-and-replace-anything/issues" 55 | } 56 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { isAnyObject, isArray, isNaNValue, isPlainObject } from 'is-what' 2 | 3 | type Config = { 4 | onlyPlainObjects?: boolean 5 | checkArrayValues?: boolean 6 | } 7 | 8 | /** 9 | * Goes through an object recursively and replaces all occurences of the `find` value with `replaceWith`. Also works no non-objects. 10 | * 11 | * @export 12 | * @param target Target can be anything 13 | * @param find val to find 14 | * @param replaceWith val to replace 15 | * @param [config={onlyPlainObjects: false, checkArrayValues: false}] 16 | * @returns the target with replaced values 17 | */ 18 | export function findAndReplace( 19 | target: any, 20 | find: any, 21 | replaceWith: any, 22 | config: Config = { onlyPlainObjects: false, checkArrayValues: false }, 23 | ): unknown { 24 | const _target = target 25 | // arrays 26 | if (config.checkArrayValues && isArray(_target) && !isAnyObject(_target)) { 27 | return (_target as any[]).map((value) => findAndReplace(value, find, replaceWith, config)) 28 | } 29 | // non-objects 30 | if ( 31 | (!config.onlyPlainObjects && !isAnyObject(_target)) || 32 | (config.onlyPlainObjects === true && !isPlainObject(_target)) 33 | ) { 34 | if (_target === find || (isNaNValue(_target) && isNaNValue(find))) { 35 | return replaceWith 36 | } 37 | return _target 38 | } 39 | // objects 40 | return Object.entries(target).reduce((carry, [key, val]) => { 41 | carry[key] = findAndReplace(val, find, replaceWith, config) 42 | return carry 43 | }, {}) 44 | } 45 | 46 | export function _findAndReplaceIf( 47 | target: any, 48 | checkFn: (foundVal: any, propKey: string | undefined) => any, 49 | propKey: string | undefined, 50 | config: Config = { onlyPlainObjects: true, checkArrayValues: false }, 51 | ): unknown { 52 | const _target = checkFn(target, propKey) 53 | if (config.checkArrayValues && isArray(_target) && !isAnyObject(_target)) { 54 | return (_target as any[]).map((value) => _findAndReplaceIf(value, checkFn, undefined, config)) 55 | } 56 | if (!isPlainObject(_target)) return _target 57 | return Object.entries(_target).reduce((carry, [key, val]) => { 58 | carry[key] = _findAndReplaceIf(val, checkFn, key, config) 59 | return carry 60 | }, {}) 61 | } 62 | 63 | /** 64 | * Goes through an object recursively and replaces all props with what's is returned in the `checkFn`. Also works on non-objects. `checkFn` is triggered on every single level of any value/object. 65 | * 66 | * @export 67 | * @param target Target can be anything 68 | * @param checkFn a function that will receive the `foundVal` 69 | * @param [config={onlyPlainObjects: true, checkArrayValues: false}] 70 | * @returns the target with replaced values 71 | */ 72 | export function findAndReplaceIf( 73 | target: any, 74 | checkFn: (foundVal: any, propKey: string | undefined) => any, 75 | config: Config = { onlyPlainObjects: true, checkArrayValues: false }, 76 | ): unknown { 77 | return _findAndReplaceIf(target, checkFn, undefined, config) 78 | } 79 | -------------------------------------------------------------------------------- /test/index.test.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from 'vitest' 2 | import { findAndReplace, findAndReplaceIf } from '../src/index' 3 | 4 | test('findAndReplace in arrays', () => { 5 | const res = findAndReplace({ a: [{ b: 'c' }] }, 'c', 'd', { checkArrayValues: true }) 6 | expect(res).toEqual({ 7 | a: [{ b: 'd' }], 8 | }) 9 | }) 10 | 11 | test('findAndReplaceIf in arrays', () => { 12 | const replacer = (foundVal: any) => (foundVal === 'c' ? 'd' : foundVal) 13 | expect(findAndReplaceIf({ a: ['c'] }, replacer, { checkArrayValues: true })).toEqual({ 14 | a: ['d'], 15 | }) 16 | }) 17 | 18 | test('findAndReplaceIf in arrays double nested', () => { 19 | const replacer = (foundVal: any) => (foundVal === 'c' ? 'd' : foundVal) 20 | expect(findAndReplaceIf({ a: [{ b: 'c' }, 'c'] }, replacer, { checkArrayValues: true })).toEqual({ 21 | a: [{ b: 'd' }, 'd'], 22 | }) 23 | }) 24 | 25 | test('findAndReplace nested strings', () => { 26 | expect(findAndReplace({ a: { b: { c: 'a' } } }, 'a', 'b')).toEqual({ a: { b: { c: 'b' } } }) 27 | }) 28 | 29 | test('findAndReplace strings', () => { 30 | expect(findAndReplace('a', 'a', 'b')).toEqual('b') 31 | expect(findAndReplace('_', 'a', 'b')).toEqual('_') 32 | }) 33 | 34 | test('findAndReplace undefined', () => { 35 | expect(findAndReplace({ undefined: undefined }, undefined, 'undefined')).toEqual({ 36 | undefined: 'undefined', 37 | }) 38 | }) 39 | test('findAndReplace NaN', () => { 40 | expect(findAndReplace({ NaN: NaN }, NaN, 'NaN')).toEqual({ NaN: 'NaN' }) 41 | }) 42 | test('findAndReplace null', () => { 43 | expect(findAndReplace({ null: null }, null, 'null')).toEqual({ null: 'null' }) 44 | }) 45 | 46 | test('findAndReplace does not modify objects', () => { 47 | let res, ori 48 | ori = { a: { b: { c: 'a' }, d: 1 } } 49 | res = findAndReplace(ori, 'a', 'b') 50 | expect(res).toEqual({ a: { b: { c: 'b' }, d: 1 } }) 51 | expect(ori).toEqual({ a: { b: { c: 'a' }, d: 1 } }) 52 | res.a.b = 1 53 | expect(res).toEqual({ a: { b: 1, d: 1 } }) 54 | expect(ori).toEqual({ a: { b: { c: 'a' }, d: 1 } }) 55 | res.a.d = 2 56 | expect(res).toEqual({ a: { b: 1, d: 2 } }) 57 | expect(ori).toEqual({ a: { b: { c: 'a' }, d: 1 } }) 58 | ori.a.d = 3 59 | expect(res).toEqual({ a: { b: 1, d: 2 } }) 60 | expect(ori).toEqual({ a: { b: { c: 'a' }, d: 3 } }) 61 | }) 62 | 63 | test('findAndReplace does not work with objects', () => { 64 | let res, ori 65 | ori = { a: { b: { c: 'a' } } } 66 | res = findAndReplace(ori, { c: 'a' }, { c: 'b' }) 67 | expect(res).toEqual({ a: { b: { c: 'a' } } }) 68 | expect(ori).toEqual({ a: { b: { c: 'a' } } }) 69 | }) 70 | 71 | test('findAndReplaceIf', () => { 72 | let res 73 | function checkFn(foundVal: any) { 74 | if (foundVal === 'a') return 'b' 75 | return foundVal 76 | } 77 | res = findAndReplaceIf({ a: { b: { c: 'a' } } }, checkFn) 78 | expect(res).toEqual({ a: { b: { c: 'b' } } }) 79 | res = findAndReplaceIf('_', checkFn) 80 | expect(res).toEqual('_') 81 | res = findAndReplaceIf('a', checkFn) 82 | expect(res).toEqual('b') 83 | }) 84 | 85 | test('should work on classes', () => { 86 | let res, target 87 | class MyClass { 88 | prop = 0 89 | constructor() { 90 | this.prop = 1 91 | } 92 | } 93 | const myClass = new MyClass() 94 | target = { 95 | prop: 1, 96 | class: myClass, 97 | } 98 | res = findAndReplace(target, 1, 2) 99 | expect(res.prop).toEqual(2) 100 | expect(res.class.prop).toEqual(2) 101 | }) 102 | 103 | test('should prevent classes', () => { 104 | let res, target 105 | class MyClass { 106 | prop = 0 107 | constructor() { 108 | this.prop = 1 109 | } 110 | } 111 | const myClass = new MyClass() 112 | target = { 113 | prop: 1, 114 | class: myClass, 115 | } 116 | res = findAndReplace(target, 1, 2, { onlyPlainObjects: true }) 117 | expect(res.prop).toEqual(2) 118 | expect(res.class.prop).toEqual(1) 119 | }) 120 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@cycraft/tsconfig", 3 | "include": ["src"], 4 | "compilerOptions": { 5 | "outDir": "dist" 6 | } 7 | } 8 | --------------------------------------------------------------------------------